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 :
54 : // EnergyPlus Headers
55 : #include <AirflowNetwork/Solver.hpp>
56 : #include <EnergyPlus/Autosizing/Base.hh>
57 : #include <EnergyPlus/BranchNodeConnections.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataContaminantBalance.hh>
60 : #include <EnergyPlus/DataConvergParams.hh>
61 : #include <EnergyPlus/DataDefineEquip.hh>
62 : #include <EnergyPlus/DataEnvironment.hh>
63 : #include <EnergyPlus/DataHVACGlobals.hh>
64 : #include <EnergyPlus/DataHeatBalFanSys.hh>
65 : #include <EnergyPlus/DataHeatBalance.hh>
66 : #include <EnergyPlus/DataIPShortCuts.hh>
67 : #include <EnergyPlus/DataLoopNode.hh>
68 : #include <EnergyPlus/DataSizing.hh>
69 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
70 : #include <EnergyPlus/DataZoneEquipment.hh>
71 : #include <EnergyPlus/EMSManager.hh>
72 : #include <EnergyPlus/Fans.hh>
73 : #include <EnergyPlus/FluidProperties.hh>
74 : #include <EnergyPlus/General.hh>
75 : #include <EnergyPlus/GeneralRoutines.hh>
76 : #include <EnergyPlus/GlobalNames.hh>
77 : #include <EnergyPlus/HeatingCoils.hh>
78 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
79 : #include <EnergyPlus/NodeInputManager.hh>
80 : #include <EnergyPlus/OutputProcessor.hh>
81 : #include <EnergyPlus/OutputReportPredefined.hh>
82 : #include <EnergyPlus/Plant/DataPlant.hh>
83 : #include <EnergyPlus/PlantUtilities.hh>
84 : #include <EnergyPlus/Psychrometrics.hh>
85 : #include <EnergyPlus/ReportCoilSelection.hh>
86 : #include <EnergyPlus/ScheduleManager.hh>
87 : #include <EnergyPlus/SingleDuct.hh>
88 : #include <EnergyPlus/SteamCoils.hh>
89 : #include <EnergyPlus/UtilityRoutines.hh>
90 : #include <EnergyPlus/WaterCoils.hh>
91 : #include <EnergyPlus/ZoneAirLoopEquipmentManager.hh>
92 :
93 : namespace EnergyPlus::SingleDuct {
94 :
95 : // Module containing the Single Duct Systems as a single component/ or really a single driver
96 :
97 : // MODULE INFORMATION:
98 : // AUTHOR Richard J. Liesen
99 : // DATE WRITTEN January 2000
100 :
101 : // PURPOSE OF THIS MODULE:
102 : // To encapsulate the data and algorithms required to
103 : // simulate single duct systems as a single driver or inter-connecting controllers.
104 :
105 : // Using/Aliasing
106 : using namespace DataLoopNode;
107 : using BranchNodeConnections::SetUpCompSets;
108 : using BranchNodeConnections::TestCompSet;
109 : using HVAC::SmallAirVolFlow;
110 : using HVAC::SmallLoad;
111 : using HVAC::SmallMassFlow;
112 : using namespace DataSizing;
113 : using Psychrometrics::PsyCpAirFnW;
114 : using Psychrometrics::PsyRhoAirFnPbTdbW;
115 : using namespace SteamCoils;
116 :
117 37322114 : void SimulateSingleDuct(
118 : EnergyPlusData &state, std::string_view CompName, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum, int &CompIndex)
119 : {
120 :
121 : // SUBROUTINE INFORMATION:
122 : // AUTHOR Richard Liesen
123 : // DATE WRITTEN January 2000
124 :
125 : // PURPOSE OF THIS SUBROUTINE:
126 : // This subroutine manages Sys system simulation.
127 : // It is called from the ManageZoneEquip
128 : // at the system time step.
129 :
130 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
131 : int SysNum; // The Sys that you are currently loading input into
132 :
133 : // Obtains and Allocates Sys related parameters from input file
134 37322114 : if (state.dataSingleDuct->GetInputFlag) { // First time subroutine has been entered
135 525 : GetSysInput(state);
136 525 : state.dataSingleDuct->GetInputFlag = false;
137 : }
138 :
139 : // Find the correct SysNumber with the Component Name
140 37322114 : if (CompIndex == 0) {
141 3607 : SysNum = Util::FindItemInList(CompName, state.dataSingleDuct->sd_airterminal, &SingleDuctAirTerminal::SysName);
142 3607 : if (SysNum == 0) {
143 0 : ShowFatalError(state, format("SimulateSingleDuct: System not found={}", CompName));
144 : }
145 3607 : CompIndex = SysNum;
146 : } else {
147 37318507 : SysNum = CompIndex;
148 37318507 : if (SysNum > state.dataSingleDuct->NumSDAirTerminal || SysNum < 1) {
149 0 : ShowFatalError(state,
150 0 : format("SimulateSingleDuct: Invalid CompIndex passed={}, Number of Systems={}, System name={}",
151 : CompIndex,
152 0 : state.dataSingleDuct->NumSDAirTerminal,
153 : CompName));
154 : }
155 37318507 : if (state.dataSingleDuct->CheckEquipName(SysNum)) {
156 3602 : if (CompName != state.dataSingleDuct->sd_airterminal(SysNum).SysName) {
157 0 : ShowFatalError(state,
158 0 : format("SimulateSingleDuct: Invalid CompIndex passed={}, System name={}, stored System Name for that index={}",
159 : CompIndex,
160 : CompName,
161 0 : state.dataSingleDuct->sd_airterminal(SysNum).SysName));
162 : }
163 3602 : state.dataSingleDuct->CheckEquipName(SysNum) = false;
164 : }
165 : }
166 :
167 37322114 : auto &thisATU(state.dataSingleDuct->sd_airterminal(SysNum));
168 :
169 37322114 : state.dataSize->TermUnitSingDuct = true;
170 37322114 : state.dataSize->CurTermUnitSizingNum = state.dataDefineEquipment->AirDistUnit(thisATU.ADUNum).TermUnitSizingNum;
171 :
172 : // With the correct SysNum Initialize the system
173 37322114 : thisATU.InitSys(state, FirstHVACIteration); // Initialize all Sys related parameters
174 :
175 : // Calculate the Correct Sys Model with the current SysNum
176 37322114 : switch (thisATU.SysType_Num) {
177 1656582 : case SysType::SingleDuctConstVolReheat: // AirTerminal:SingleDuct:ConstantVolume:Reheat
178 1656582 : thisATU.SimConstVol(state, FirstHVACIteration, ZoneNum, ZoneNodeNum);
179 1656582 : break;
180 8544703 : case SysType::SingleDuctConstVolNoReheat: // AirTerminal:SingleDuct:ConstantVolume:NoReheat
181 8544703 : thisATU.SimConstVolNoReheat(state);
182 8544703 : break;
183 27022691 : case SysType::SingleDuctVAVReheat: // SINGLE DUCT:VAV:REHEAT
184 : case SysType::SingleDuctVAVNoReheat: // SINGLE DUCT:VAV:NOREHEAT
185 27022691 : thisATU.SimVAV(state, FirstHVACIteration, ZoneNum, ZoneNodeNum);
186 27022691 : break;
187 30864 : case SysType::SingleDuctVAVReheatVSFan: // SINGLE DUCT:VAV:REHEAT:VS FAN
188 30864 : thisATU.SimVAVVS(state, FirstHVACIteration, ZoneNum, ZoneNodeNum);
189 30864 : break;
190 67274 : case SysType::SingleDuctCBVAVReheat: // SINGLE DUCT:VAVHEATANDCOOL:REHEAT
191 : case SysType::SingleDuctCBVAVNoReheat: // SINGLE DUCT:VAVHEATANDCOOL:NOREHEAT
192 67274 : thisATU.SimCBVAV(state, FirstHVACIteration, ZoneNum, ZoneNodeNum);
193 67274 : break;
194 0 : default:
195 : // assert(false);
196 0 : break;
197 : }
198 :
199 : // Report the current Sys
200 37322114 : thisATU.ReportSys(state);
201 :
202 37322114 : state.dataSize->TermUnitSingDuct = false;
203 37322114 : }
204 :
205 : // Get Input Section of the Module
206 : //******************************************************************************
207 :
208 525 : void GetSysInput(EnergyPlusData &state)
209 : {
210 :
211 : // SUBROUTINE INFORMATION:
212 : // AUTHOR Richard Liesen
213 : // DATE WRITTEN April 1998
214 :
215 : // PURPOSE OF THIS SUBROUTINE:
216 : // This subroutine is the main routine to call other input routines and Get routines
217 :
218 : // METHODOLOGY EMPLOYED:
219 : // Uses the status flags to trigger events.
220 :
221 : // Using/Aliasing
222 : using NodeInputManager::GetOnlySingleNode;
223 : using SteamCoils::GetCoilAirOutletNode;
224 : using SteamCoils::GetCoilSteamInletNode;
225 : using SteamCoils::GetSteamCoilIndex;
226 : using WaterCoils::GetCoilOutletNode;
227 : using WaterCoils::GetCoilWaterInletNode;
228 525 : auto &GetHeatingCoilCapacity(HeatingCoils::GetCoilCapacity);
229 525 : auto &GetHeatingCoilOutletNode(HeatingCoils::GetCoilOutletNode);
230 : using namespace DataHeatBalance;
231 :
232 : // SUBROUTINE PARAMETER DEFINITIONS:
233 : static constexpr std::string_view RoutineName("GetSysInput: "); // include trailing blank
234 : static constexpr std::string_view routineName = "GetSysInput";
235 :
236 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
237 :
238 : int NumZoneSiz;
239 : int ZoneSizIndex;
240 : int IOStat;
241 525 : bool ErrorsFound(false); // If errors detected in input
242 : bool IsNotOK; // Flag to verify name
243 : int CtrlZone; // controlled zone do loop index
244 : int SupAirIn; // controlled zone supply air inlet index
245 : int ADUNum; // air distribution unit index
246 525 : std::string CurrentModuleObject; // for ease in getting objects
247 525 : Array1D_string Alphas; // Alpha input items for object
248 525 : Array1D_string cAlphaFields; // Alpha field names
249 525 : Array1D_string cNumericFields; // Numeric field names
250 525 : Array1D<Real64> Numbers; // Numeric input items for object
251 525 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
252 525 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
253 :
254 : // certain object in the input file
255 525 : std::string AirTermSysInletNodeName; // air terminal single duct system inlet node name
256 525 : std::string AirTermSysOutletNodeName; // air terminal single duct system outlet node name
257 :
258 525 : state.dataSingleDuct->NumVAVSysGSI = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:VAV:Reheat");
259 1050 : state.dataSingleDuct->NumNoRHVAVSysGSI =
260 525 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:VAV:NoReheat");
261 1050 : state.dataSingleDuct->NumConstVolSys =
262 525 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:ConstantVolume:Reheat");
263 1050 : state.dataSingleDuct->NumCVNoReheatSysGSI =
264 525 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:ConstantVolume:NoReheat");
265 1050 : state.dataSingleDuct->NumVAVVSGSI =
266 525 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:VAV:Reheat:VariableSpeedFan");
267 1050 : state.dataSingleDuct->NumCBVAVSysGSI =
268 525 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:VAV:HeatAndCool:Reheat");
269 1050 : state.dataSingleDuct->NumNoRHCBVAVSysGSI =
270 525 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:VAV:HeatAndCool:NoReheat");
271 525 : state.dataSingleDuct->NumSDAirTerminal = state.dataSingleDuct->NumVAVSysGSI + state.dataSingleDuct->NumConstVolSys +
272 525 : state.dataSingleDuct->NumCVNoReheatSysGSI + state.dataSingleDuct->NumNoRHVAVSysGSI +
273 525 : state.dataSingleDuct->NumVAVVSGSI + state.dataSingleDuct->NumCBVAVSysGSI +
274 525 : state.dataSingleDuct->NumNoRHCBVAVSysGSI;
275 :
276 525 : state.dataSingleDuct->sd_airterminal.allocate(state.dataSingleDuct->NumSDAirTerminal);
277 525 : state.dataSingleDuct->SysUniqueNames.reserve(static_cast<unsigned>(state.dataSingleDuct->NumSDAirTerminal));
278 525 : state.dataSingleDuct->CheckEquipName.dimension(state.dataSingleDuct->NumSDAirTerminal, true);
279 :
280 1050 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
281 : "AirTerminal:SingleDuct:VAV:Reheat",
282 525 : state.dataSingleDuct->TotalArgsGSI,
283 525 : state.dataSingleDuct->NumAlphasGSI,
284 525 : state.dataSingleDuct->NumNumsGSI);
285 525 : state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
286 525 : state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
287 1050 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
288 : "AirTerminal:SingleDuct:VAV:NoReheat",
289 525 : state.dataSingleDuct->TotalArgsGSI,
290 525 : state.dataSingleDuct->NumAlphasGSI,
291 525 : state.dataSingleDuct->NumNumsGSI);
292 525 : state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
293 525 : state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
294 1050 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
295 : "AirTerminal:SingleDuct:ConstantVolume:Reheat",
296 525 : state.dataSingleDuct->TotalArgsGSI,
297 525 : state.dataSingleDuct->NumAlphasGSI,
298 525 : state.dataSingleDuct->NumNumsGSI);
299 525 : state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
300 525 : state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
301 1050 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
302 : "AirTerminal:SingleDuct:ConstantVolume:NoReheat",
303 525 : state.dataSingleDuct->TotalArgsGSI,
304 525 : state.dataSingleDuct->NumAlphasGSI,
305 525 : state.dataSingleDuct->NumNumsGSI);
306 525 : state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
307 525 : state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
308 1050 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
309 : "AirTerminal:SingleDuct:VAV:Reheat:VariableSpeedFan",
310 525 : state.dataSingleDuct->TotalArgsGSI,
311 525 : state.dataSingleDuct->NumAlphasGSI,
312 525 : state.dataSingleDuct->NumNumsGSI);
313 525 : state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
314 525 : state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
315 1050 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
316 : "AirTerminal:SingleDuct:VAV:HeatAndCool:Reheat",
317 525 : state.dataSingleDuct->TotalArgsGSI,
318 525 : state.dataSingleDuct->NumAlphasGSI,
319 525 : state.dataSingleDuct->NumNumsGSI);
320 525 : state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
321 525 : state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
322 1050 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state,
323 : "AirTerminal:SingleDuct:VAV:HeatAndCool:NoReheat",
324 525 : state.dataSingleDuct->TotalArgsGSI,
325 525 : state.dataSingleDuct->NumAlphasGSI,
326 525 : state.dataSingleDuct->NumNumsGSI);
327 525 : state.dataSingleDuct->MaxNumsGSI = max(state.dataSingleDuct->MaxNumsGSI, state.dataSingleDuct->NumNumsGSI);
328 525 : state.dataSingleDuct->MaxAlphasGSI = max(state.dataSingleDuct->MaxAlphasGSI, state.dataSingleDuct->NumAlphasGSI);
329 :
330 525 : Alphas.allocate(state.dataSingleDuct->MaxAlphasGSI);
331 525 : cAlphaFields.allocate(state.dataSingleDuct->MaxAlphasGSI);
332 525 : cNumericFields.allocate(state.dataSingleDuct->MaxNumsGSI);
333 525 : Numbers.dimension(state.dataSingleDuct->MaxNumsGSI, 0.0);
334 525 : lAlphaBlanks.dimension(state.dataSingleDuct->MaxAlphasGSI, true);
335 525 : lNumericBlanks.dimension(state.dataSingleDuct->MaxNumsGSI, true);
336 :
337 : // Start Loading the System Input
338 2760 : for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumVAVSysGSI;
339 2235 : ++state.dataSingleDuct->SysIndexGSI) {
340 :
341 2235 : CurrentModuleObject = "AirTerminal:SingleDuct:VAV:Reheat";
342 :
343 4470 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
344 : CurrentModuleObject,
345 2235 : state.dataSingleDuct->SysIndexGSI,
346 : Alphas,
347 2235 : state.dataSingleDuct->NumAlphasGSI,
348 : Numbers,
349 2235 : state.dataSingleDuct->NumNumsGSI,
350 : IOStat,
351 : lNumericBlanks,
352 : lAlphaBlanks,
353 : cAlphaFields,
354 : cNumericFields);
355 :
356 2235 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
357 :
358 2235 : state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI;
359 :
360 2235 : auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
361 2235 : airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
362 2235 : GlobalNames::VerifyUniqueInterObjectName(
363 4470 : state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
364 2235 : airTerm.SysName = Alphas(1);
365 2235 : airTerm.sysType = CurrentModuleObject;
366 2235 : airTerm.SysType_Num = SysType::SingleDuctVAVReheat;
367 :
368 2235 : airTerm.ReheatComp = Alphas(7);
369 2235 : if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) {
370 57 : airTerm.ReheatComp_Num = HeatingCoilType::Gas;
371 2178 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) {
372 259 : airTerm.ReheatComp_Num = HeatingCoilType::Electric;
373 1919 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) {
374 1906 : airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating;
375 1906 : airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
376 13 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) {
377 13 : airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating;
378 13 : airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
379 0 : } else if (!airTerm.ReheatComp.empty()) {
380 0 : ShowSevereError(state, format("Illegal {} = {}.", cAlphaFields(8), airTerm.ReheatComp));
381 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
382 0 : ErrorsFound = true;
383 : }
384 :
385 2235 : airTerm.ReheatName = Alphas(8);
386 2235 : if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
387 316 : HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound);
388 316 : if (airTerm.ReheatComp_Index == 0) {
389 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
390 0 : ErrorsFound = true;
391 : }
392 1919 : } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) {
393 1906 : airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
394 1906 : if (airTerm.ReheatComp_Index == 0) {
395 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
396 0 : ErrorsFound = true;
397 : }
398 13 : } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
399 13 : airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
400 13 : if (airTerm.ReheatComp_Index == 0) {
401 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
402 0 : ErrorsFound = true;
403 : }
404 : }
405 :
406 2235 : if (lAlphaBlanks(2)) {
407 23 : airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
408 2212 : } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
409 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
410 0 : ErrorsFound = true;
411 : }
412 : // For node connections, this object is both a parent and a non-parent, because the
413 : // VAV damper is not called out as a separate component, its nodes must be connected
414 : // as ObjectIsNotParent. But for the reheat coil, the nodes are connected as ObjectIsParent
415 6705 : airTerm.OutletNodeNum = GetOnlySingleNode(state,
416 2235 : Alphas(3),
417 : ErrorsFound,
418 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVReheat,
419 2235 : Alphas(1),
420 : DataLoopNode::NodeFluidType::Air,
421 : DataLoopNode::ConnectionType::Outlet,
422 : NodeInputManager::CompFluidStream::Primary,
423 : ObjectIsNotParent,
424 2235 : cAlphaFields(3));
425 6705 : airTerm.InletNodeNum = GetOnlySingleNode(state,
426 2235 : Alphas(4),
427 : ErrorsFound,
428 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVReheat,
429 2235 : Alphas(1),
430 : DataLoopNode::NodeFluidType::Air,
431 : DataLoopNode::ConnectionType::Inlet,
432 : NodeInputManager::CompFluidStream::Primary,
433 : ObjectIsNotParent,
434 2235 : cAlphaFields(4));
435 2235 : airTerm.MaxAirVolFlowRate = Numbers(1);
436 :
437 2235 : if (Util::SameString(Alphas(5), "Constant")) {
438 2197 : airTerm.ZoneMinAirFracMethod = MinFlowFraction::Constant;
439 38 : } else if (Util::SameString(Alphas(5), "FixedFlowRate")) {
440 3 : airTerm.ZoneMinAirFracMethod = MinFlowFraction::Fixed;
441 35 : } else if (Util::SameString(Alphas(5), "Scheduled")) {
442 35 : airTerm.ZoneMinAirFracMethod = MinFlowFraction::Scheduled;
443 : } else {
444 0 : ShowSevereError(state, format("{} = {} not found.", cAlphaFields(5), Alphas(5)));
445 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
446 0 : ErrorsFound = true;
447 : }
448 :
449 2235 : airTerm.ZoneMinAirFracDes = Numbers(2);
450 2235 : if (lNumericBlanks(2)) {
451 54 : airTerm.ConstantMinAirFracSetByUser = false;
452 54 : airTerm.DesignMinAirFrac = 0.0;
453 : } else {
454 2181 : airTerm.ConstantMinAirFracSetByUser = true;
455 2181 : airTerm.DesignMinAirFrac = Numbers(2);
456 2181 : if (airTerm.ZoneMinAirFracMethod == MinFlowFraction::Fixed) {
457 1 : ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(5), Alphas(5), cNumericFields(2)));
458 1 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
459 1 : airTerm.ZoneMinAirFracDes = 0.0;
460 : }
461 : }
462 :
463 2235 : airTerm.ZoneFixedMinAir = Numbers(3);
464 2235 : if (lNumericBlanks(3)) {
465 2177 : airTerm.FixedMinAirSetByUser = false;
466 2177 : airTerm.DesignMinAirFrac = 0.0;
467 : } else {
468 58 : airTerm.FixedMinAirSetByUser = true;
469 58 : airTerm.DesignMinAirFrac = Numbers(3);
470 58 : if (airTerm.ZoneMinAirFracMethod == MinFlowFraction::Constant) {
471 55 : ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(5), Alphas(5), cNumericFields(3)));
472 55 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
473 55 : airTerm.ZoneFixedMinAir = 0.0;
474 : }
475 : }
476 :
477 2235 : if (airTerm.ZoneMinAirFracMethod != MinFlowFraction::Scheduled) {
478 35 : } else if (lAlphaBlanks(6)) {
479 0 : ShowSevereEmptyField(state, eoh, cAlphaFields(6));
480 0 : ErrorsFound = true;
481 35 : } else if ((airTerm.zoneMinAirFracSched = Sched::GetSchedule(state, Alphas(6))) == nullptr) {
482 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
483 0 : ErrorsFound = true;
484 35 : } else if (!airTerm.zoneMinAirFracSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
485 0 : Sched::ShowSevereBadMinMax(state, eoh, cAlphaFields(6), Alphas(6), Clusive::In, 0.0, Clusive::In, 1.0);
486 0 : ErrorsFound = true;
487 : }
488 :
489 : // The reheat coil control node is necessary for hot water and steam reheat, but not necessary for
490 : // electric or gas reheat.
491 2235 : if (airTerm.ReheatComp_Num != HeatingCoilType::Gas && airTerm.ReheatComp_Num != HeatingCoilType::Electric) {
492 1919 : if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
493 13 : IsNotOK = false;
494 13 : airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
495 13 : if (IsNotOK) {
496 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
497 0 : ErrorsFound = true;
498 : }
499 : } else {
500 1906 : IsNotOK = false;
501 1906 : airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
502 1906 : if (IsNotOK) {
503 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
504 0 : ErrorsFound = true;
505 : }
506 : }
507 : }
508 6705 : airTerm.ReheatAirOutletNode = GetOnlySingleNode(state,
509 2235 : Alphas(9),
510 : ErrorsFound,
511 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVReheat,
512 2235 : Alphas(1),
513 : DataLoopNode::NodeFluidType::Air,
514 : DataLoopNode::ConnectionType::Outlet,
515 : NodeInputManager::CompFluidStream::Primary,
516 : ObjectIsParent,
517 2235 : cAlphaFields(9));
518 2235 : if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
519 13 : airTerm.MaxReheatSteamVolFlow = Numbers(4);
520 13 : airTerm.MinReheatSteamVolFlow = Numbers(5);
521 : } else {
522 2222 : airTerm.MaxReheatWaterVolFlow = Numbers(4);
523 2222 : airTerm.MinReheatWaterVolFlow = Numbers(5);
524 : }
525 2235 : airTerm.ControllerOffset = Numbers(6);
526 : // Set default convergence tolerance
527 2235 : if (airTerm.ControllerOffset <= 0.0) {
528 0 : airTerm.ControllerOffset = 0.001;
529 : }
530 2235 : if (Util::SameString(Alphas(10), "Reverse")) {
531 52 : airTerm.DamperHeatingAction = Action::Reverse;
532 2183 : } else if (Util::SameString(Alphas(10), "Normal")) {
533 1069 : airTerm.DamperHeatingAction = Action::Normal;
534 1114 : } else if (Util::SameString(Alphas(10), "ReverseWithLimits")) {
535 1114 : airTerm.DamperHeatingAction = Action::ReverseWithLimits;
536 : } else {
537 0 : ShowSevereError(state, format("{} = {} not found.", cAlphaFields(10), Alphas(10)));
538 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
539 0 : ErrorsFound = true;
540 : }
541 :
542 : // Register component set data
543 4470 : TestCompSet(state,
544 : airTerm.sysType,
545 : airTerm.SysName,
546 2235 : state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
547 2235 : state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode),
548 : "Air Nodes");
549 :
550 45328 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
551 45328 : if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
552 2235 : state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
553 2235 : airTerm.ADUNum = ADUNum;
554 2235 : break;
555 : }
556 : }
557 : // one assumes if there isn't one assigned, it's an error?
558 2235 : if (airTerm.ADUNum == 0) {
559 0 : ShowSevereError(state,
560 0 : format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
561 0 : ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
562 0 : ErrorsFound = true;
563 : } else {
564 :
565 : // Fill the Zone Equipment data with the inlet node number of this unit.
566 96326 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
567 94091 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
568 5460 : continue;
569 : }
570 177897 : for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
571 89266 : if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
572 2235 : if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
573 0 : ShowSevereError(state, "Error in connecting a terminal unit to a zone");
574 0 : ShowContinueError(
575 0 : state, format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
576 0 : ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
577 0 : ShowContinueError(state, "Check terminal unit node names for errors");
578 0 : ErrorsFound = true;
579 : } else {
580 2235 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
581 2235 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode;
582 2235 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
583 2235 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
584 2235 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
585 : }
586 :
587 2235 : airTerm.CtrlZoneNum = CtrlZone;
588 2235 : airTerm.CtrlZoneInNodeIndex = SupAirIn;
589 2235 : airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
590 2235 : state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
591 : }
592 : }
593 : }
594 : }
595 2235 : if (Numbers(7) == Constant::AutoCalculate) {
596 2212 : airTerm.MaxAirVolFlowRateDuringReheat = Numbers(7);
597 : } else {
598 23 : airTerm.MaxAirVolFlowRateDuringReheat = Numbers(7) * airTerm.ZoneFloorArea;
599 : }
600 :
601 2235 : airTerm.MaxAirVolFractionDuringReheat = Numbers(8);
602 :
603 2235 : if (airTerm.DamperHeatingAction != Action::ReverseWithLimits) {
604 1121 : if (airTerm.MaxAirVolFlowRateDuringReheat > 0.0) {
605 0 : ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(10), Alphas(10), cNumericFields(7)));
606 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
607 : }
608 1121 : if (airTerm.MaxAirVolFractionDuringReheat > 0.0) {
609 15 : ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(10), Alphas(10), cNumericFields(8)));
610 15 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
611 : }
612 : }
613 :
614 : // Maximum reheat air temperature, i.e. the maximum supply air temperature leaving the reheat coil
615 2235 : if (!lNumericBlanks(9)) {
616 422 : airTerm.MaxReheatTemp = Numbers(9);
617 422 : airTerm.MaxReheatTempSetByUser = true;
618 : } else {
619 : // user does not specify maximum supply air temperature
620 : // sd_airterminal(SysNum)%MaxReheatTemp = 35.0D0 !C
621 1813 : airTerm.MaxReheatTempSetByUser = false;
622 : }
623 :
624 2235 : if (!lAlphaBlanks(11)) {
625 292 : airTerm.OARequirementsPtr = Util::FindItemInList(Alphas(11), state.dataSize->OARequirements);
626 292 : if (airTerm.OARequirementsPtr == 0) {
627 0 : ShowSevereError(state, format("{} = {} not found.", cAlphaFields(11), Alphas(11)));
628 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
629 0 : ErrorsFound = true;
630 : } else {
631 292 : airTerm.NoOAFlowInputFromUser = false;
632 : }
633 : }
634 :
635 2235 : if (lAlphaBlanks(12)) {
636 2230 : airTerm.ZoneTurndownMinAirFrac = 1.0;
637 5 : } else if ((airTerm.zoneTurndownMinAirFracSched = Sched::GetSchedule(state, Alphas(12))) == nullptr) {
638 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(12), Alphas(12));
639 0 : ErrorsFound = true;
640 : }
641 :
642 2235 : ValidateComponent(state, Alphas(7), Alphas(8), IsNotOK, airTerm.sysType);
643 2235 : if (IsNotOK) {
644 0 : ShowContinueError(state, format("In {} = {}", airTerm.sysType, airTerm.SysName));
645 0 : ErrorsFound = true;
646 : }
647 :
648 : // Add reheat coil to component sets array
649 2235 : SetUpCompSets(state, airTerm.sysType, airTerm.SysName, Alphas(7), Alphas(8), Alphas(3), Alphas(9));
650 :
651 : // Setup the Average damper Position output variable
652 4470 : SetupOutputVariable(state,
653 : "Zone Air Terminal VAV Damper Position",
654 : Constant::Units::None,
655 2235 : airTerm.DamperPosition,
656 : OutputProcessor::TimeStepType::System,
657 : OutputProcessor::StoreType::Average,
658 2235 : airTerm.SysName);
659 4470 : SetupOutputVariable(state,
660 : "Zone Air Terminal Minimum Air Flow Fraction",
661 : Constant::Units::None,
662 2235 : airTerm.ZoneMinAirFracReport,
663 : OutputProcessor::TimeStepType::System,
664 : OutputProcessor::StoreType::Average,
665 2235 : airTerm.SysName);
666 :
667 : } // end Number of Sys Loop
668 :
669 534 : for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumCBVAVSysGSI;
670 9 : ++state.dataSingleDuct->SysIndexGSI) {
671 :
672 9 : CurrentModuleObject = "AirTerminal:SingleDuct:VAV:HeatAndCool:Reheat";
673 :
674 18 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
675 : CurrentModuleObject,
676 9 : state.dataSingleDuct->SysIndexGSI,
677 : Alphas,
678 9 : state.dataSingleDuct->NumAlphasGSI,
679 : Numbers,
680 9 : state.dataSingleDuct->NumNumsGSI,
681 : IOStat,
682 : lNumericBlanks,
683 : lAlphaBlanks,
684 : cAlphaFields,
685 : cNumericFields);
686 :
687 9 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
688 9 : state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI;
689 :
690 9 : auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
691 9 : airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
692 9 : GlobalNames::VerifyUniqueInterObjectName(
693 18 : state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
694 9 : airTerm.SysName = Alphas(1);
695 9 : airTerm.sysType = CurrentModuleObject;
696 9 : airTerm.SysType_Num = SysType::SingleDuctCBVAVReheat;
697 9 : airTerm.ReheatComp = Alphas(5);
698 9 : if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) {
699 0 : airTerm.ReheatComp_Num = HeatingCoilType::Gas;
700 9 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) {
701 9 : airTerm.ReheatComp_Num = HeatingCoilType::Electric;
702 0 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) {
703 0 : airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating;
704 0 : airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
705 0 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) {
706 0 : airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating;
707 0 : airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
708 0 : } else if (!airTerm.ReheatComp.empty()) {
709 0 : ShowSevereError(state, format("Illegal {} = {}.", cAlphaFields(5), airTerm.ReheatComp));
710 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
711 0 : ErrorsFound = true;
712 : }
713 9 : airTerm.ReheatName = Alphas(6);
714 9 : if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
715 9 : HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound);
716 9 : if (airTerm.ReheatComp_Index == 0) {
717 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
718 0 : ErrorsFound = true;
719 : }
720 0 : } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) {
721 0 : airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
722 0 : if (airTerm.ReheatComp_Index == 0) {
723 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
724 0 : ErrorsFound = true;
725 : }
726 0 : } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
727 0 : airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
728 0 : if (airTerm.ReheatComp_Index == 0) {
729 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
730 0 : ErrorsFound = true;
731 : }
732 : }
733 :
734 9 : if (lAlphaBlanks(2)) {
735 1 : airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
736 8 : } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
737 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
738 0 : ErrorsFound = true;
739 : }
740 : // For node connections, this object is both a parent and a non-parent, because the
741 : // VAV damper is not called out as a separate component, its nodes must be connected
742 : // as ObjectIsNotParent. But for the reheat coil, the nodes are connected as ObjectIsParent
743 27 : airTerm.OutletNodeNum = GetOnlySingleNode(state,
744 9 : Alphas(3),
745 : ErrorsFound,
746 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVHeatAndCoolReheat,
747 9 : Alphas(1),
748 : DataLoopNode::NodeFluidType::Air,
749 : DataLoopNode::ConnectionType::Outlet,
750 : NodeInputManager::CompFluidStream::Primary,
751 : ObjectIsNotParent,
752 9 : cAlphaFields(3));
753 27 : airTerm.InletNodeNum = GetOnlySingleNode(state,
754 9 : Alphas(4),
755 : ErrorsFound,
756 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVHeatAndCoolReheat,
757 9 : Alphas(1),
758 : DataLoopNode::NodeFluidType::Air,
759 : DataLoopNode::ConnectionType::Inlet,
760 : NodeInputManager::CompFluidStream::Primary,
761 : ObjectIsNotParent,
762 9 : cAlphaFields(4));
763 9 : airTerm.MaxAirVolFlowRate = Numbers(1);
764 9 : airTerm.ZoneMinAirFracDes = Numbers(2);
765 9 : if (airTerm.ZoneMinAirFracDes < 0.0) {
766 0 : ShowWarningError(state, format("{} \"{}\"", airTerm.sysType, airTerm.SysName));
767 0 : ShowContinueError(state,
768 0 : format("{} must be greater than or equal to 0. Resetting to 0 and the simulation continues.", cNumericFields(2)));
769 0 : airTerm.ZoneMinAirFracDes = 0.0;
770 : }
771 9 : if (airTerm.ZoneMinAirFracDes > 1.0) {
772 0 : ShowWarningError(state, format("{} \"{}\"", airTerm.sysType, airTerm.SysName));
773 0 : ShowContinueError(state, format("{} must be less than or equal to 1. Resetting to 1 and the simulation continues.", cNumericFields(2)));
774 0 : airTerm.ZoneMinAirFracDes = 1.0;
775 : }
776 : // The reheat coil control node is necessary for hot water and steam reheat, but not necessary for
777 : // electric or gas reheat.
778 9 : if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
779 : } else {
780 0 : if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
781 0 : IsNotOK = false;
782 0 : airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
783 0 : if (IsNotOK) {
784 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
785 0 : ErrorsFound = true;
786 : }
787 : } else {
788 0 : IsNotOK = false;
789 0 : airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
790 0 : if (IsNotOK) {
791 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
792 0 : ErrorsFound = true;
793 : }
794 : }
795 : // END IF
796 : }
797 27 : airTerm.ReheatAirOutletNode = GetOnlySingleNode(state,
798 9 : Alphas(7),
799 : ErrorsFound,
800 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVHeatAndCoolReheat,
801 9 : Alphas(1),
802 : DataLoopNode::NodeFluidType::Air,
803 : DataLoopNode::ConnectionType::Outlet,
804 : NodeInputManager::CompFluidStream::Primary,
805 : ObjectIsParent,
806 9 : cAlphaFields(7));
807 9 : if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
808 0 : airTerm.MaxReheatSteamVolFlow = Numbers(3);
809 0 : airTerm.MinReheatSteamVolFlow = Numbers(4);
810 : } else {
811 9 : airTerm.MaxReheatWaterVolFlow = Numbers(3);
812 9 : airTerm.MinReheatWaterVolFlow = Numbers(4);
813 : }
814 9 : airTerm.ControllerOffset = Numbers(5);
815 : // Set default convergence tolerance
816 9 : if (airTerm.ControllerOffset <= 0.0) {
817 0 : airTerm.ControllerOffset = 0.001;
818 : }
819 :
820 9 : airTerm.DamperHeatingAction = Action::Reverse;
821 :
822 : // Register component set data
823 18 : TestCompSet(state,
824 : airTerm.sysType,
825 : airTerm.SysName,
826 9 : state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
827 9 : state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode),
828 : "Air Nodes");
829 :
830 17 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
831 17 : if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
832 9 : state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
833 9 : airTerm.ADUNum = ADUNum;
834 9 : break;
835 : }
836 : }
837 : // one assumes if there isn't one assigned, it's an error?
838 9 : if (airTerm.ADUNum == 0) {
839 0 : ShowSevereError(state,
840 0 : format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
841 0 : ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
842 0 : ErrorsFound = true;
843 : } else {
844 :
845 : // Fill the Zone Equipment data with the inlet node number of this unit
846 39 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
847 30 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
848 1 : continue;
849 : }
850 58 : for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
851 29 : if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
852 9 : if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
853 0 : ShowSevereError(state, "Error in connecting a terminal unit to a zone");
854 0 : ShowContinueError(
855 0 : state, format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
856 0 : ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
857 0 : ShowContinueError(state, "Check terminal unit node names for errors");
858 0 : ErrorsFound = true;
859 : } else {
860 9 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
861 9 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode;
862 9 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
863 9 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
864 9 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
865 : }
866 9 : airTerm.CtrlZoneNum = CtrlZone;
867 9 : airTerm.CtrlZoneInNodeIndex = SupAirIn;
868 9 : airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
869 9 : state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
870 : }
871 : }
872 : }
873 : }
874 9 : if (!lNumericBlanks(6)) {
875 3 : airTerm.MaxReheatTemp = Numbers(6);
876 3 : airTerm.MaxReheatTempSetByUser = true;
877 : } else {
878 : // user does not specify maximum supply air temperature
879 : // sd_airterminal(SysNum)%MaxReheatTemp = 35.0D0 !C
880 6 : airTerm.MaxReheatTempSetByUser = false;
881 : }
882 :
883 9 : ValidateComponent(state, Alphas(5), Alphas(6), IsNotOK, airTerm.sysType);
884 9 : if (IsNotOK) {
885 0 : ShowContinueError(state, format("In {} = {}", airTerm.sysType, airTerm.SysName));
886 0 : ErrorsFound = true;
887 : }
888 :
889 9 : if (lAlphaBlanks(8)) {
890 9 : airTerm.ZoneTurndownMinAirFrac = 1.0;
891 0 : } else if ((airTerm.zoneTurndownMinAirFracSched = Sched::GetSchedule(state, Alphas(8))) == nullptr) {
892 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
893 0 : ErrorsFound = true;
894 : }
895 :
896 : // Add reheat coil to component sets array
897 9 : SetUpCompSets(state, airTerm.sysType, airTerm.SysName, Alphas(5), Alphas(6), Alphas(3), Alphas(7));
898 :
899 : // Setup the Average damper Position output variable
900 18 : SetupOutputVariable(state,
901 : "Zone Air Terminal VAV Damper Position",
902 : Constant::Units::None,
903 9 : airTerm.DamperPosition,
904 : OutputProcessor::TimeStepType::System,
905 : OutputProcessor::StoreType::Average,
906 9 : airTerm.SysName);
907 :
908 : } // end Number of VAVHeatandCool Sys Loop
909 :
910 525 : CurrentModuleObject = "AirTerminal:SingleDuct:ConstantVolume:Reheat";
911 :
912 794 : for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumConstVolSys;
913 269 : ++state.dataSingleDuct->SysIndexGSI) {
914 :
915 538 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
916 : CurrentModuleObject,
917 269 : state.dataSingleDuct->SysIndexGSI,
918 : Alphas,
919 269 : state.dataSingleDuct->NumAlphasGSI,
920 : Numbers,
921 269 : state.dataSingleDuct->NumNumsGSI,
922 : IOStat,
923 : lNumericBlanks,
924 : lAlphaBlanks,
925 : cAlphaFields,
926 : cNumericFields);
927 :
928 269 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
929 :
930 538 : state.dataSingleDuct->SysNumGSI =
931 269 : state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI + state.dataSingleDuct->NumCBVAVSysGSI;
932 269 : auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
933 :
934 269 : airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
935 269 : GlobalNames::VerifyUniqueInterObjectName(
936 538 : state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
937 269 : airTerm.SysName = Alphas(1);
938 269 : airTerm.sysType = CurrentModuleObject;
939 269 : airTerm.SysType_Num = SysType::SingleDuctConstVolReheat;
940 269 : airTerm.ReheatComp = Alphas(5);
941 269 : if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) {
942 38 : airTerm.ReheatComp_Num = HeatingCoilType::Gas;
943 231 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) {
944 4 : airTerm.ReheatComp_Num = HeatingCoilType::Electric;
945 227 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) {
946 227 : airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating;
947 227 : airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
948 0 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) {
949 0 : airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating;
950 0 : airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
951 : } else {
952 0 : ShowSevereError(state, format("Illegal {} = {}.", cAlphaFields(5), airTerm.ReheatComp));
953 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
954 0 : ErrorsFound = true;
955 : }
956 269 : airTerm.ReheatName = Alphas(6);
957 269 : if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
958 42 : HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound);
959 42 : if (airTerm.ReheatComp_Index == 0) {
960 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
961 0 : ErrorsFound = true;
962 : }
963 227 : } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) {
964 227 : airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
965 227 : if (airTerm.ReheatComp_Index == 0) {
966 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
967 0 : ErrorsFound = true;
968 : }
969 0 : } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
970 0 : airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
971 0 : if (airTerm.ReheatComp_Index == 0) {
972 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
973 0 : ErrorsFound = true;
974 : }
975 : }
976 :
977 269 : if (lAlphaBlanks(2)) {
978 4 : airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
979 265 : } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
980 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
981 0 : ErrorsFound = true;
982 : }
983 :
984 807 : airTerm.OutletNodeNum = GetOnlySingleNode(state,
985 269 : Alphas(3),
986 : ErrorsFound,
987 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeReheat,
988 269 : Alphas(1),
989 : DataLoopNode::NodeFluidType::Air,
990 : DataLoopNode::ConnectionType::Outlet,
991 : NodeInputManager::CompFluidStream::Primary,
992 : ObjectIsParent,
993 269 : cAlphaFields(3));
994 807 : airTerm.InletNodeNum = GetOnlySingleNode(state,
995 269 : Alphas(4),
996 : ErrorsFound,
997 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeReheat,
998 269 : Alphas(1),
999 : DataLoopNode::NodeFluidType::Air,
1000 : DataLoopNode::ConnectionType::Inlet,
1001 : NodeInputManager::CompFluidStream::Primary,
1002 : ObjectIsParent,
1003 269 : cAlphaFields(4));
1004 : // The reheat coil control node is necessary for hot water reheat, but not necessary for
1005 : // electric or gas reheat.
1006 269 : if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
1007 : } else {
1008 227 : if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
1009 0 : IsNotOK = false;
1010 0 : airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
1011 0 : if (IsNotOK) {
1012 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1013 0 : ErrorsFound = true;
1014 : }
1015 : } else {
1016 227 : IsNotOK = false;
1017 227 : airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
1018 227 : if (IsNotOK) {
1019 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1020 0 : ErrorsFound = true;
1021 : }
1022 : }
1023 : }
1024 269 : airTerm.ReheatAirOutletNode = airTerm.OutletNodeNum;
1025 269 : airTerm.MaxAirVolFlowRate = Numbers(1);
1026 269 : airTerm.ZoneMinAirFracDes = 0.0;
1027 269 : airTerm.ZoneMinAirFracMethod = MinFlowFraction::MinFracNotUsed;
1028 269 : airTerm.DamperHeatingAction = Action::HeatingNotUsed;
1029 269 : if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
1030 0 : airTerm.MaxReheatSteamVolFlow = Numbers(2);
1031 0 : airTerm.MinReheatSteamVolFlow = Numbers(3);
1032 : } else {
1033 269 : airTerm.MaxReheatWaterVolFlow = Numbers(2);
1034 269 : airTerm.MinReheatWaterVolFlow = Numbers(3);
1035 : }
1036 269 : airTerm.ControllerOffset = Numbers(4);
1037 : // Set default convergence tolerance
1038 269 : if (airTerm.ControllerOffset <= 0.0) {
1039 0 : airTerm.ControllerOffset = 0.001;
1040 : }
1041 :
1042 : // Maximum reheat air temperature, i.e. the maximum supply air temperature leaving the reheat coil
1043 269 : if (!lNumericBlanks(5)) {
1044 4 : airTerm.MaxReheatTemp = Numbers(5);
1045 4 : airTerm.MaxReheatTempSetByUser = true;
1046 : } else {
1047 : // user does not specify maximum supply air temperature
1048 : // sd_airterminal(SysNum)%MaxReheatTemp = 35.0D0 !C
1049 265 : airTerm.MaxReheatTempSetByUser = false;
1050 : }
1051 : // Register component set data
1052 538 : TestCompSet(state,
1053 : airTerm.sysType,
1054 : airTerm.SysName,
1055 269 : state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
1056 269 : state.dataLoopNodes->NodeID(airTerm.OutletNodeNum),
1057 : "Air Nodes");
1058 :
1059 560 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
1060 560 : if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
1061 269 : state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
1062 269 : airTerm.ADUNum = ADUNum;
1063 269 : break;
1064 : }
1065 : }
1066 : // one assumes if there isn't one assigned, it's an error?
1067 269 : if (airTerm.ADUNum == 0) {
1068 0 : ShowSevereError(state,
1069 0 : format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
1070 0 : ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
1071 0 : ErrorsFound = true;
1072 : } else {
1073 :
1074 : // Fill the Zone Equipment data with the inlet node number of this unit.
1075 1204 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
1076 935 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
1077 66 : continue;
1078 : }
1079 1738 : for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
1080 869 : if (airTerm.OutletNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
1081 269 : if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
1082 0 : ShowSevereError(state, "Error in connecting a terminal unit to a zone");
1083 0 : ShowContinueError(state,
1084 0 : format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.OutletNodeNum)));
1085 0 : ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
1086 0 : ShowContinueError(state, "Check terminal unit node names for errors");
1087 0 : ErrorsFound = true;
1088 : } else {
1089 269 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
1090 269 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.OutletNodeNum;
1091 269 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
1092 269 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
1093 269 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
1094 : }
1095 269 : airTerm.CtrlZoneNum = CtrlZone;
1096 269 : airTerm.CtrlZoneInNodeIndex = SupAirIn;
1097 269 : airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
1098 269 : state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
1099 : }
1100 : }
1101 : }
1102 : }
1103 :
1104 269 : ValidateComponent(state, Alphas(5), Alphas(6), IsNotOK, airTerm.sysType);
1105 269 : if (IsNotOK) {
1106 0 : ShowContinueError(state, format("In {} = {}", airTerm.sysType, airTerm.SysName));
1107 0 : ErrorsFound = true;
1108 : }
1109 :
1110 : // Add reheat coil to component sets array
1111 269 : SetUpCompSets(state, airTerm.sysType, airTerm.SysName, Alphas(5), Alphas(6), Alphas(4), Alphas(3));
1112 :
1113 : // Setup the Average damper Position output variable
1114 : // BG removed 9-10-2009 during work on CR 7770, constant volume has no damper
1115 : // CALL SetupOutputVariable(state, 'Damper Position', Sys(SysNum)%DamperPosition, &
1116 : // 'System','Average',Sys(SysNum)%SysName)
1117 :
1118 : } // End Number of Sys Loop
1119 :
1120 525 : CurrentModuleObject = "AirTerminal:SingleDuct:ConstantVolume:NoReheat";
1121 :
1122 1389 : for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumCVNoReheatSysGSI;
1123 864 : ++state.dataSingleDuct->SysIndexGSI) {
1124 :
1125 1728 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1126 : CurrentModuleObject,
1127 864 : state.dataSingleDuct->SysIndexGSI,
1128 : Alphas,
1129 864 : state.dataSingleDuct->NumAlphasGSI,
1130 : Numbers,
1131 864 : state.dataSingleDuct->NumNumsGSI,
1132 : IOStat,
1133 : lNumericBlanks,
1134 : lAlphaBlanks,
1135 : cAlphaFields,
1136 : cNumericFields);
1137 :
1138 864 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1139 :
1140 864 : state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI +
1141 864 : state.dataSingleDuct->NumCBVAVSysGSI + state.dataSingleDuct->NumConstVolSys;
1142 864 : auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
1143 :
1144 864 : airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
1145 864 : GlobalNames::VerifyUniqueInterObjectName(
1146 1728 : state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
1147 864 : airTerm.SysName = Alphas(1);
1148 864 : airTerm.sysType = CurrentModuleObject;
1149 864 : airTerm.SysType_Num = SysType::SingleDuctConstVolNoReheat;
1150 :
1151 864 : if (lAlphaBlanks(2)) {
1152 115 : airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
1153 749 : } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
1154 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1155 0 : ErrorsFound = true;
1156 : }
1157 :
1158 2592 : airTerm.InletNodeNum = GetOnlySingleNode(state,
1159 864 : Alphas(3),
1160 : ErrorsFound,
1161 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeNoReheat,
1162 864 : Alphas(1),
1163 : DataLoopNode::NodeFluidType::Air,
1164 : DataLoopNode::ConnectionType::Inlet,
1165 : NodeInputManager::CompFluidStream::Primary,
1166 : ObjectIsNotParent,
1167 864 : cAlphaFields(3));
1168 2592 : airTerm.OutletNodeNum = GetOnlySingleNode(state,
1169 864 : Alphas(4),
1170 : ErrorsFound,
1171 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeNoReheat,
1172 864 : Alphas(1),
1173 : DataLoopNode::NodeFluidType::Air,
1174 : DataLoopNode::ConnectionType::Outlet,
1175 : NodeInputManager::CompFluidStream::Primary,
1176 : ObjectIsNotParent,
1177 864 : cAlphaFields(4));
1178 :
1179 864 : airTerm.MaxAirVolFlowRate = Numbers(1);
1180 864 : airTerm.ZoneMinAirFracDes = 0.0;
1181 864 : airTerm.ZoneMinAirFracMethod = MinFlowFraction::MinFracNotUsed;
1182 864 : airTerm.DamperHeatingAction = Action::HeatingNotUsed;
1183 :
1184 864 : airTerm.ReheatControlNode = 0;
1185 864 : airTerm.ReheatAirOutletNode = airTerm.OutletNodeNum;
1186 864 : airTerm.MaxReheatWaterVolFlow = 0.0;
1187 864 : airTerm.MaxReheatSteamVolFlow = 0.0;
1188 864 : airTerm.MinReheatWaterVolFlow = 0.0;
1189 864 : airTerm.MinReheatSteamVolFlow = 0.0;
1190 864 : airTerm.ControllerOffset = 0.000001;
1191 :
1192 : // Register component set data
1193 1728 : TestCompSet(state,
1194 : airTerm.sysType,
1195 : airTerm.SysName,
1196 864 : state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
1197 864 : state.dataLoopNodes->NodeID(airTerm.OutletNodeNum),
1198 : "Air Nodes");
1199 :
1200 6810 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
1201 6810 : if (airTerm.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
1202 864 : state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
1203 864 : airTerm.ADUNum = ADUNum;
1204 864 : break;
1205 : }
1206 : }
1207 : // one assumes if there isn't one assigned, it's an error?
1208 864 : if (airTerm.ADUNum == 0) {
1209 0 : ShowSevereError(state,
1210 0 : format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
1211 0 : ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.OutletNodeNum)));
1212 0 : ErrorsFound = true;
1213 : } else {
1214 :
1215 : // Fill the Zone Equipment data with the inlet node number of this unit.
1216 16699 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
1217 15835 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
1218 1680 : continue;
1219 : }
1220 35394 : for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
1221 21239 : if (airTerm.OutletNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
1222 864 : if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
1223 0 : ShowSevereError(state, "Error in connecting a terminal unit to a zone");
1224 0 : ShowContinueError(state,
1225 0 : format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.OutletNodeNum)));
1226 0 : ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
1227 0 : ShowContinueError(state, "Check terminal unit node names for errors");
1228 0 : ErrorsFound = true;
1229 : } else {
1230 864 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
1231 864 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.OutletNodeNum;
1232 864 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
1233 864 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
1234 864 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
1235 : }
1236 864 : airTerm.CtrlZoneNum = CtrlZone;
1237 864 : airTerm.CtrlZoneInNodeIndex = SupAirIn;
1238 864 : airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
1239 864 : state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
1240 : }
1241 : }
1242 : }
1243 : }
1244 :
1245 864 : if (lAlphaBlanks(5)) {
1246 862 : airTerm.NoOAFlowInputFromUser = true;
1247 : } else {
1248 2 : airTerm.OARequirementsPtr = Util::FindItemInList(Alphas(5), state.dataSize->OARequirements);
1249 2 : if (airTerm.OARequirementsPtr == 0) {
1250 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid data.", RoutineName, CurrentModuleObject, Alphas(1)));
1251 0 : ShowContinueError(state, format("..invalid {}=\"{}\".", cAlphaFields(5), Alphas(5)));
1252 0 : ErrorsFound = true;
1253 : } else {
1254 2 : airTerm.NoOAFlowInputFromUser = false;
1255 : }
1256 : }
1257 :
1258 864 : if (lAlphaBlanks(6)) {
1259 863 : airTerm.OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
1260 : } else {
1261 1 : if (Alphas(6) == "CURRENTOCCUPANCY") {
1262 1 : airTerm.OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
1263 0 : } else if (Alphas(6) == "DESIGNOCCUPANCY") {
1264 0 : airTerm.OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::ByDesignLevel;
1265 : } else {
1266 0 : airTerm.OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
1267 0 : ShowWarningError(state, format("{}{}=\"{}\", invalid data.", RoutineName, CurrentModuleObject, Alphas(1)));
1268 0 : ShowContinueError(state,
1269 0 : format("..invalid {}=\"{}\". The default input of CurrentOccupancy is assigned", cAlphaFields(6), Alphas(6)));
1270 : }
1271 : }
1272 :
1273 864 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
1274 : // model results related actuators
1275 266 : SetupEMSActuator(state,
1276 : "AirTerminal:SingleDuct:ConstantVolume:NoReheat",
1277 : airTerm.SysName,
1278 : "Mass Flow Rate",
1279 : "[kg/s]",
1280 266 : airTerm.EMSOverrideAirFlow,
1281 266 : airTerm.EMSMassFlowRateValue);
1282 : // model input related internal variables
1283 266 : SetupEMSInternalVariable(state,
1284 : "AirTerminal:SingleDuct:ConstantVolume:NoReheat Maximum Mass Flow Rate",
1285 : airTerm.SysName,
1286 : "[kg/s]",
1287 266 : airTerm.AirMassFlowRateMax);
1288 : }
1289 :
1290 : } // End Number of Sys Loop
1291 :
1292 743 : for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumNoRHVAVSysGSI;
1293 218 : ++state.dataSingleDuct->SysIndexGSI) {
1294 :
1295 218 : CurrentModuleObject = "AirTerminal:SingleDuct:VAV:NoReheat";
1296 :
1297 436 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1298 : CurrentModuleObject,
1299 218 : state.dataSingleDuct->SysIndexGSI,
1300 : Alphas,
1301 218 : state.dataSingleDuct->NumAlphasGSI,
1302 : Numbers,
1303 218 : state.dataSingleDuct->NumNumsGSI,
1304 : IOStat,
1305 : lNumericBlanks,
1306 : lAlphaBlanks,
1307 : cAlphaFields,
1308 : cNumericFields);
1309 :
1310 218 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1311 218 : state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI +
1312 218 : state.dataSingleDuct->NumCBVAVSysGSI + state.dataSingleDuct->NumConstVolSys +
1313 218 : state.dataSingleDuct->NumCVNoReheatSysGSI;
1314 218 : auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
1315 :
1316 218 : airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
1317 218 : GlobalNames::VerifyUniqueInterObjectName(
1318 436 : state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
1319 218 : airTerm.SysName = Alphas(1);
1320 218 : airTerm.sysType = CurrentModuleObject;
1321 218 : airTerm.SysType_Num = SysType::SingleDuctVAVNoReheat;
1322 218 : airTerm.ReheatComp = "";
1323 218 : airTerm.ReheatName = "";
1324 :
1325 218 : if (lAlphaBlanks(2)) {
1326 30 : airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
1327 188 : } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
1328 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1329 0 : ErrorsFound = true;
1330 : }
1331 :
1332 654 : airTerm.OutletNodeNum = GetOnlySingleNode(state,
1333 218 : Alphas(3),
1334 : ErrorsFound,
1335 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVNoReheat,
1336 218 : Alphas(1),
1337 : DataLoopNode::NodeFluidType::Air,
1338 : DataLoopNode::ConnectionType::Outlet,
1339 : NodeInputManager::CompFluidStream::Primary,
1340 : ObjectIsNotParent,
1341 218 : cAlphaFields(3));
1342 654 : airTerm.InletNodeNum = GetOnlySingleNode(state,
1343 218 : Alphas(4),
1344 : ErrorsFound,
1345 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVNoReheat,
1346 218 : Alphas(1),
1347 : DataLoopNode::NodeFluidType::Air,
1348 : DataLoopNode::ConnectionType::Inlet,
1349 : NodeInputManager::CompFluidStream::Primary,
1350 : ObjectIsNotParent,
1351 218 : cAlphaFields(4));
1352 218 : airTerm.MaxAirVolFlowRate = Numbers(1);
1353 :
1354 218 : if (Util::SameString(Alphas(5), "Constant")) {
1355 90 : airTerm.ZoneMinAirFracMethod = MinFlowFraction::Constant;
1356 128 : } else if (Util::SameString(Alphas(5), "FixedFlowRate")) {
1357 0 : airTerm.ZoneMinAirFracMethod = MinFlowFraction::Fixed;
1358 128 : } else if (Util::SameString(Alphas(5), "Scheduled")) {
1359 128 : airTerm.ZoneMinAirFracMethod = MinFlowFraction::Scheduled;
1360 : } else {
1361 0 : ShowSevereError(state, format("{} = {} not found.", cAlphaFields(5), Alphas(5)));
1362 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1363 0 : ErrorsFound = true;
1364 : }
1365 :
1366 218 : airTerm.ZoneMinAirFracDes = Numbers(2);
1367 218 : if (lNumericBlanks(2)) {
1368 128 : airTerm.ConstantMinAirFracSetByUser = false;
1369 128 : airTerm.ZoneMinAirFracDes = 0.0;
1370 : } else {
1371 90 : airTerm.ConstantMinAirFracSetByUser = true;
1372 90 : airTerm.ZoneMinAirFracDes = Numbers(2);
1373 90 : if (airTerm.ZoneMinAirFracMethod == MinFlowFraction::Fixed) {
1374 0 : ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(5), Alphas(5), cNumericFields(2)));
1375 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1376 0 : airTerm.ZoneMinAirFracDes = 0.0;
1377 : }
1378 : }
1379 :
1380 218 : airTerm.ZoneFixedMinAir = Numbers(3);
1381 218 : if (lNumericBlanks(3)) {
1382 218 : airTerm.FixedMinAirSetByUser = false;
1383 218 : airTerm.DesignFixedMinAir = 0.0;
1384 : } else {
1385 0 : airTerm.FixedMinAirSetByUser = true;
1386 0 : airTerm.DesignFixedMinAir = Numbers(3);
1387 0 : if (airTerm.ZoneMinAirFracMethod == MinFlowFraction::Constant) {
1388 0 : ShowWarningError(state, format("Since {} = {}, input for {} will be ignored.", cAlphaFields(5), Alphas(5), cNumericFields(3)));
1389 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1390 0 : airTerm.ZoneFixedMinAir = 0.0;
1391 : }
1392 : }
1393 :
1394 218 : if (airTerm.ZoneMinAirFracMethod != MinFlowFraction::Scheduled) {
1395 128 : } else if (lAlphaBlanks(6)) {
1396 0 : ShowSevereEmptyField(state, eoh, cAlphaFields(6));
1397 0 : ErrorsFound = true;
1398 128 : } else if ((airTerm.zoneMinAirFracSched = Sched::GetSchedule(state, Alphas(6))) == nullptr) {
1399 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
1400 0 : ErrorsFound = true;
1401 128 : } else if (!airTerm.zoneMinAirFracSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
1402 0 : Sched::ShowSevereBadMinMax(state, eoh, cAlphaFields(6), Alphas(6), Clusive::In, 0.0, Clusive::In, 1.0);
1403 0 : ErrorsFound = true;
1404 : }
1405 :
1406 218 : airTerm.ReheatControlNode = 0;
1407 218 : airTerm.ReheatAirOutletNode = airTerm.OutletNodeNum;
1408 218 : airTerm.MaxReheatWaterVolFlow = 0.0;
1409 218 : airTerm.MaxReheatSteamVolFlow = 0.0;
1410 218 : airTerm.MinReheatWaterVolFlow = 0.0;
1411 218 : airTerm.MinReheatSteamVolFlow = 0.0;
1412 218 : airTerm.ControllerOffset = 0.000001;
1413 218 : airTerm.DamperHeatingAction = Action::HeatingNotUsed;
1414 :
1415 : // Register component set data
1416 436 : TestCompSet(state,
1417 : airTerm.sysType,
1418 : airTerm.SysName,
1419 218 : state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
1420 218 : state.dataLoopNodes->NodeID(airTerm.OutletNodeNum),
1421 : "Air Nodes");
1422 :
1423 8705 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
1424 8705 : if (airTerm.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
1425 218 : state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
1426 218 : airTerm.ADUNum = ADUNum;
1427 218 : break;
1428 : }
1429 : }
1430 : // one assumes if there isn't one assigned, it's an error?
1431 218 : if (airTerm.ADUNum == 0) {
1432 0 : ShowSevereError(state,
1433 0 : format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
1434 0 : ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
1435 0 : ErrorsFound = true;
1436 : } else {
1437 :
1438 : // Fill the Zone Equipment data with the inlet node number of this unit.
1439 17369 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
1440 17151 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
1441 89 : continue;
1442 : }
1443 50833 : for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
1444 33771 : if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
1445 218 : if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
1446 0 : ShowSevereError(state, "Error in connecting a terminal unit to a zone");
1447 0 : ShowContinueError(
1448 0 : state, format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
1449 0 : ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
1450 0 : ShowContinueError(state, "Check terminal unit node names for errors");
1451 0 : ErrorsFound = true;
1452 : } else {
1453 218 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
1454 218 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode;
1455 218 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
1456 218 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
1457 218 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
1458 : }
1459 :
1460 218 : airTerm.CtrlZoneNum = CtrlZone;
1461 218 : airTerm.CtrlZoneInNodeIndex = SupAirIn;
1462 218 : airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
1463 218 : state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
1464 : }
1465 : }
1466 : }
1467 : }
1468 218 : if (!lAlphaBlanks(7)) {
1469 128 : airTerm.OARequirementsPtr = Util::FindItemInList(Alphas(7), state.dataSize->OARequirements);
1470 128 : if (airTerm.OARequirementsPtr == 0) {
1471 0 : ShowSevereError(state, format("{} = {} not found.", cAlphaFields(7), Alphas(7)));
1472 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1473 0 : ErrorsFound = true;
1474 : } else {
1475 128 : airTerm.NoOAFlowInputFromUser = false;
1476 : }
1477 : }
1478 :
1479 218 : if (lAlphaBlanks(8)) {
1480 218 : airTerm.ZoneTurndownMinAirFrac = 1.0;
1481 0 : } else if ((airTerm.zoneTurndownMinAirFracSched = Sched::GetSchedule(state, Alphas(8))) == nullptr) {
1482 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
1483 0 : ErrorsFound = true;
1484 : }
1485 :
1486 : // Setup the Average damper Position output variable
1487 436 : SetupOutputVariable(state,
1488 : "Zone Air Terminal VAV Damper Position",
1489 : Constant::Units::None,
1490 218 : airTerm.DamperPosition,
1491 : OutputProcessor::TimeStepType::System,
1492 : OutputProcessor::StoreType::Average,
1493 218 : airTerm.SysName);
1494 436 : SetupOutputVariable(state,
1495 : "Zone Air Terminal Minimum Air Flow Fraction",
1496 : Constant::Units::None,
1497 218 : airTerm.ZoneMinAirFracReport,
1498 : OutputProcessor::TimeStepType::System,
1499 : OutputProcessor::StoreType::Average,
1500 218 : airTerm.SysName);
1501 :
1502 : } // end Number of Sys Loop
1503 :
1504 529 : for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumNoRHCBVAVSysGSI;
1505 4 : ++state.dataSingleDuct->SysIndexGSI) {
1506 :
1507 4 : CurrentModuleObject = "AirTerminal:SingleDuct:VAV:HeatAndCool:NoReheat";
1508 :
1509 8 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1510 : CurrentModuleObject,
1511 4 : state.dataSingleDuct->SysIndexGSI,
1512 : Alphas,
1513 4 : state.dataSingleDuct->NumAlphasGSI,
1514 : Numbers,
1515 4 : state.dataSingleDuct->NumNumsGSI,
1516 : IOStat,
1517 : lNumericBlanks,
1518 : lAlphaBlanks,
1519 : cAlphaFields,
1520 : cNumericFields);
1521 :
1522 4 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1523 4 : state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI +
1524 4 : state.dataSingleDuct->NumCBVAVSysGSI + state.dataSingleDuct->NumConstVolSys +
1525 4 : state.dataSingleDuct->NumCVNoReheatSysGSI + state.dataSingleDuct->NumNoRHVAVSysGSI;
1526 4 : auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
1527 :
1528 4 : airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
1529 4 : GlobalNames::VerifyUniqueInterObjectName(
1530 8 : state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
1531 4 : airTerm.SysName = Alphas(1);
1532 4 : airTerm.sysType = CurrentModuleObject;
1533 4 : airTerm.SysType_Num = SysType::SingleDuctCBVAVNoReheat;
1534 4 : airTerm.ReheatComp = "";
1535 4 : airTerm.ReheatName = "";
1536 :
1537 4 : if (lAlphaBlanks(2)) {
1538 0 : airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
1539 4 : } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
1540 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1541 0 : ErrorsFound = true;
1542 : }
1543 :
1544 12 : airTerm.OutletNodeNum = GetOnlySingleNode(state,
1545 4 : Alphas(3),
1546 : ErrorsFound,
1547 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVHeatAndCoolNoReheat,
1548 4 : Alphas(1),
1549 : DataLoopNode::NodeFluidType::Air,
1550 : DataLoopNode::ConnectionType::Outlet,
1551 : NodeInputManager::CompFluidStream::Primary,
1552 : ObjectIsNotParent,
1553 4 : cAlphaFields(3));
1554 12 : airTerm.InletNodeNum = GetOnlySingleNode(state,
1555 4 : Alphas(4),
1556 : ErrorsFound,
1557 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctVAVHeatAndCoolNoReheat,
1558 4 : Alphas(1),
1559 : DataLoopNode::NodeFluidType::Air,
1560 : DataLoopNode::ConnectionType::Inlet,
1561 : NodeInputManager::CompFluidStream::Primary,
1562 : ObjectIsNotParent,
1563 4 : cAlphaFields(4));
1564 4 : airTerm.MaxAirVolFlowRate = Numbers(1);
1565 4 : airTerm.ZoneMinAirFracDes = Numbers(2);
1566 4 : if (airTerm.ZoneMinAirFracDes < 0.0) {
1567 0 : ShowWarningError(state, format("{} = \"{}", airTerm.sysType, airTerm.SysName));
1568 0 : ShowContinueError(state,
1569 0 : format("{} must be greater than or equal to 0. Resetting to 0 and the simulation continues.", cNumericFields(2)));
1570 0 : airTerm.ZoneMinAirFracDes = 0.0;
1571 : }
1572 4 : if (airTerm.ZoneMinAirFracDes > 1.0) {
1573 0 : ShowWarningError(state, format("{} = \"{}", airTerm.sysType, airTerm.SysName));
1574 0 : ShowContinueError(state, format("{} must be less than or equal to 1. Resetting to 1 and the simulation continues.", cNumericFields(2)));
1575 0 : airTerm.ZoneMinAirFracDes = 1.0;
1576 : }
1577 :
1578 4 : airTerm.ReheatControlNode = 0;
1579 4 : airTerm.ReheatAirOutletNode = airTerm.OutletNodeNum;
1580 4 : airTerm.MaxReheatWaterVolFlow = 0.0;
1581 4 : airTerm.MaxReheatSteamVolFlow = 0.0;
1582 4 : airTerm.MinReheatWaterVolFlow = 0.0;
1583 4 : airTerm.MinReheatSteamVolFlow = 0.0;
1584 4 : airTerm.ControllerOffset = 0.000001;
1585 4 : airTerm.DamperHeatingAction = Action::HeatingNotUsed;
1586 :
1587 : // Register component set data
1588 8 : TestCompSet(state,
1589 : airTerm.sysType,
1590 : airTerm.SysName,
1591 4 : state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
1592 4 : state.dataLoopNodes->NodeID(airTerm.OutletNodeNum),
1593 : "Air Nodes");
1594 :
1595 12 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
1596 12 : if (airTerm.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
1597 4 : state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
1598 4 : airTerm.ADUNum = ADUNum;
1599 4 : break;
1600 : }
1601 : }
1602 : // one assumes if there isn't one assigned, it's an error?
1603 4 : if (airTerm.ADUNum == 0) {
1604 0 : ShowSevereError(state,
1605 0 : format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
1606 0 : ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
1607 0 : ErrorsFound = true;
1608 : } else {
1609 :
1610 : // Fill the Zone Equipment data with the inlet node number of this unit.
1611 16 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
1612 12 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
1613 0 : continue;
1614 : }
1615 24 : for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
1616 12 : if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
1617 4 : if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
1618 0 : ShowSevereError(state, "Error in connecting a terminal unit to a zone");
1619 0 : ShowContinueError(
1620 0 : state, format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
1621 0 : ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
1622 0 : ShowContinueError(state, "Check terminal unit node names for errors");
1623 0 : ErrorsFound = true;
1624 : } else {
1625 4 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
1626 4 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode;
1627 4 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
1628 4 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
1629 4 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
1630 : }
1631 4 : airTerm.CtrlZoneNum = CtrlZone;
1632 4 : airTerm.CtrlZoneInNodeIndex = SupAirIn;
1633 4 : airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
1634 4 : state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
1635 : }
1636 : }
1637 : }
1638 : }
1639 :
1640 4 : if (lAlphaBlanks(5)) {
1641 4 : airTerm.ZoneTurndownMinAirFrac = 1.0;
1642 0 : } else if ((airTerm.zoneTurndownMinAirFracSched = Sched::GetSchedule(state, Alphas(5))) == nullptr) {
1643 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(5), Alphas(5));
1644 0 : ErrorsFound = true;
1645 : }
1646 :
1647 : // Setup the Average damper Position output variable
1648 8 : SetupOutputVariable(state,
1649 : "Zone Air Terminal VAV Damper Position",
1650 : Constant::Units::None,
1651 4 : airTerm.DamperPosition,
1652 : OutputProcessor::TimeStepType::System,
1653 : OutputProcessor::StoreType::Average,
1654 4 : airTerm.SysName);
1655 :
1656 : } // end Number of VAVHeatandCool:NoReheat Sys Loop
1657 :
1658 : // read in the SINGLE DUCT:VAV:REHEAT:VS FAN data
1659 533 : for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumVAVVSGSI;
1660 8 : ++state.dataSingleDuct->SysIndexGSI) {
1661 :
1662 8 : CurrentModuleObject = "AirTerminal:SingleDuct:VAV:Reheat:VariableSpeedFan";
1663 :
1664 16 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1665 : CurrentModuleObject,
1666 8 : state.dataSingleDuct->SysIndexGSI,
1667 : Alphas,
1668 8 : state.dataSingleDuct->NumAlphasGSI,
1669 : Numbers,
1670 8 : state.dataSingleDuct->NumNumsGSI,
1671 : IOStat,
1672 : lNumericBlanks,
1673 : lAlphaBlanks,
1674 : cAlphaFields,
1675 : cNumericFields);
1676 :
1677 8 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
1678 :
1679 8 : state.dataSingleDuct->SysNumGSI = state.dataSingleDuct->SysIndexGSI + state.dataSingleDuct->NumVAVSysGSI +
1680 8 : state.dataSingleDuct->NumCBVAVSysGSI + state.dataSingleDuct->NumConstVolSys +
1681 8 : state.dataSingleDuct->NumCVNoReheatSysGSI + state.dataSingleDuct->NumNoRHVAVSysGSI +
1682 8 : state.dataSingleDuct->NumNoRHCBVAVSysGSI;
1683 8 : auto &airTerm = state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysNumGSI);
1684 8 : airTerm.SysNum = state.dataSingleDuct->SysNumGSI;
1685 8 : GlobalNames::VerifyUniqueInterObjectName(
1686 16 : state, state.dataSingleDuct->SysUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
1687 8 : airTerm.SysName = Alphas(1);
1688 8 : airTerm.sysType = CurrentModuleObject;
1689 8 : airTerm.SysType_Num = SysType::SingleDuctVAVReheatVSFan;
1690 8 : airTerm.ReheatComp = Alphas(7);
1691 8 : airTerm.ReheatName = Alphas(8);
1692 8 : IsNotOK = false;
1693 8 : if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Fuel")) {
1694 0 : airTerm.ReheatComp_Num = HeatingCoilType::Gas;
1695 0 : airTerm.ReheatAirOutletNode = GetHeatingCoilOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
1696 0 : airTerm.ReheatCoilMaxCapacity = GetHeatingCoilCapacity(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
1697 0 : if (IsNotOK) {
1698 0 : ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
1699 : }
1700 8 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Electric")) {
1701 0 : airTerm.ReheatComp_Num = HeatingCoilType::Electric;
1702 0 : airTerm.ReheatAirOutletNode = GetHeatingCoilOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
1703 0 : airTerm.ReheatCoilMaxCapacity = GetHeatingCoilCapacity(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
1704 0 : if (IsNotOK) {
1705 0 : ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
1706 : }
1707 8 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Water")) {
1708 8 : airTerm.ReheatComp_Num = HeatingCoilType::SimpleHeating;
1709 8 : airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
1710 0 : } else if (Util::SameString(airTerm.ReheatComp, "Coil:Heating:Steam")) {
1711 0 : airTerm.ReheatComp_Num = HeatingCoilType::SteamAirHeating;
1712 0 : airTerm.ReheatComp_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
1713 0 : } else if (!airTerm.ReheatComp.empty()) {
1714 0 : ShowSevereError(state, format("Illegal {} = {}.", cAlphaFields(7), airTerm.ReheatComp));
1715 0 : ShowContinueError(state, format("Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1716 0 : ErrorsFound = true;
1717 : }
1718 :
1719 8 : if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
1720 0 : HeatingCoils::GetCoilIndex(state, airTerm.ReheatName, airTerm.ReheatComp_Index, ErrorsFound);
1721 0 : if (airTerm.ReheatComp_Index == 0) {
1722 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
1723 0 : ErrorsFound = true;
1724 : }
1725 8 : } else if (airTerm.ReheatComp_Num == HeatingCoilType::SimpleHeating) {
1726 8 : airTerm.ReheatComp_Index = WaterCoils::GetWaterCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
1727 8 : if (airTerm.ReheatComp_Index == 0) {
1728 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
1729 0 : ErrorsFound = true;
1730 : }
1731 0 : } else if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
1732 0 : airTerm.ReheatComp_Index = SteamCoils::GetSteamCoilIndex(state, airTerm.ReheatComp, airTerm.ReheatName, ErrorsFound);
1733 0 : if (airTerm.ReheatComp_Index == 0) {
1734 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), Alphas(8));
1735 0 : ErrorsFound = true;
1736 : }
1737 : }
1738 :
1739 8 : airTerm.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(5)));
1740 :
1741 8 : if (airTerm.fanType != HVAC::FanType::VAV && airTerm.fanType != HVAC::FanType::SystemModel) {
1742 0 : ShowSevereInvalidKey(state, eoh, cAlphaFields(5), Alphas(5), "Support fan types are Fan:VAV and Fan:SystemModel");
1743 :
1744 0 : ErrorsFound = true;
1745 : }
1746 :
1747 8 : airTerm.FanName = Alphas(6);
1748 :
1749 8 : airTerm.Fan_Index = Fans::GetFanIndex(state, airTerm.FanName);
1750 8 : if (airTerm.Fan_Index == 0) {
1751 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), airTerm.FanName);
1752 0 : ErrorsFound = true;
1753 : }
1754 8 : airTerm.OutletNodeNum = state.dataFans->fans(airTerm.Fan_Index)->outletNodeNum;
1755 8 : airTerm.InletNodeNum = state.dataFans->fans(airTerm.Fan_Index)->inletNodeNum;
1756 :
1757 8 : if (airTerm.fanType == HVAC::FanType::SystemModel) {
1758 4 : dynamic_cast<Fans::FanSystem *>(state.dataFans->fans(airTerm.Fan_Index))->isSecondaryDriver = true;
1759 : }
1760 :
1761 8 : if (lAlphaBlanks(2)) {
1762 0 : airTerm.availSched = Sched::GetScheduleAlwaysOn(state);
1763 8 : } else if ((airTerm.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
1764 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1765 0 : ErrorsFound = true;
1766 : }
1767 :
1768 8 : AirTermSysInletNodeName = state.dataLoopNodes->NodeID(airTerm.InletNodeNum);
1769 8 : if (!Util::SameString(Alphas(3), AirTermSysInletNodeName)) {
1770 0 : ShowWarningError(state,
1771 0 : format("{}Invalid air terminal object air inlet node name in {} = {}", RoutineName, airTerm.sysType, airTerm.SysName));
1772 0 : ShowContinueError(state, format(" Specified air inlet node name is = {}.", Alphas(3)));
1773 0 : ShowContinueError(state, format(" Expected air inlet node name is = {}.", AirTermSysInletNodeName));
1774 : // ErrorsFound = true;
1775 : }
1776 :
1777 8 : airTerm.MaxAirVolFlowRate = Numbers(1);
1778 8 : airTerm.MaxHeatAirVolFlowRate = Numbers(2);
1779 8 : airTerm.ZoneMinAirFracDes = Numbers(3);
1780 : // The reheat coil control node is necessary for hot water reheat, but not necessary for
1781 : // electric or gas reheat.
1782 8 : if (airTerm.ReheatComp_Num == HeatingCoilType::Gas || airTerm.ReheatComp_Num == HeatingCoilType::Electric) {
1783 : // IF(.NOT. lAlphaBlanks(6)) THEN
1784 : // CALL ShowWarningError(state, 'In '//TRIM(sd_airterminal(SysNum)%SysType)//' = ' // TRIM(sd_airterminal(SysNum)%SysName) &
1785 : // // ' the '//TRIM(cAlphaFields(6))//' is not needed and will be ignored.')
1786 : // CALL ShowContinueError(state, ' It is used for hot water reheat coils only.')
1787 : // END IF
1788 : } else {
1789 : // IF(lAlphaBlanks(6)) THEN
1790 : // CALL ShowSevereError(state, 'In '//TRIM(sd_airterminal(SysNum)%SysType)//' = ' // TRIM(sd_airterminal(SysNum)%SysName) &
1791 : // // ' the '//TRIM(cAlphaFields(6))//' is undefined')
1792 : // ErrorsFound=.TRUE.
1793 : // END IF
1794 8 : if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
1795 0 : IsNotOK = false;
1796 0 : airTerm.ReheatControlNode = GetCoilSteamInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
1797 0 : if (IsNotOK) {
1798 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1799 0 : ErrorsFound = true;
1800 : } else {
1801 : // A4, \field Unit supply air outlet node
1802 : // \note same as heating coil air outlet node
1803 : // \note same as zone inlet node
1804 : // \type alpha
1805 0 : IsNotOK = false;
1806 0 : airTerm.ReheatAirOutletNode = GetCoilAirOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
1807 0 : if (IsNotOK) {
1808 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1809 0 : ErrorsFound = true;
1810 : }
1811 : }
1812 : // GetOnlySingleNode(state, Alphas(6),ErrorsFound,sd_airterminal(SysNum)%SysType,Alphas(1), &
1813 : // DataLoopNode::NodeFluidType::Steam,DataLoopNode::NodeConnectionType::Actuator,1,ObjectIsParent)
1814 : } else {
1815 8 : IsNotOK = false;
1816 8 : airTerm.ReheatControlNode = GetCoilWaterInletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
1817 8 : if (IsNotOK) {
1818 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1819 0 : ErrorsFound = true;
1820 : } else {
1821 : // A4, \field Unit supply air outlet node
1822 : // \note same as heating coil air outlet node
1823 : // \note same as zone inlet node
1824 : // \type alpha
1825 8 : IsNotOK = false;
1826 8 : airTerm.ReheatAirOutletNode = GetCoilOutletNode(state, airTerm.ReheatComp, airTerm.ReheatName, IsNotOK);
1827 8 : if (IsNotOK) {
1828 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1829 0 : ErrorsFound = true;
1830 : }
1831 : }
1832 : // GetOnlySingleNode(state, Alphas(6),ErrorsFound,sd_airterminal(SysNum)%SysType,Alphas(1), &
1833 : // DataLoopNode::NodeFluidType::Water,DataLoopNode::NodeConnectionType::Actuator,1,ObjectIsParent)
1834 : }
1835 : }
1836 : // A4, \field Unit supply air outlet node
1837 : // \note same as heating coil air outlet node
1838 : // \note same as zone inlet node
1839 : // \type alpha
1840 : // sd_airterminal(SysNum)%ReheatAirOutletNode = &
1841 : // GetOnlySingleNode(state, Alphas(4),ErrorsFound,sd_airterminal(SysNum)%SysType,Alphas(1), &
1842 : // DataLoopNode::NodeFluidType::Air,DataLoopNode::NodeConnectionType::Outlet,1,ObjectIsParent)
1843 8 : AirTermSysOutletNodeName = state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode);
1844 8 : if (!Util::SameString(Alphas(4), AirTermSysOutletNodeName)) {
1845 0 : ShowWarningError(state,
1846 0 : format("{}Invalid air terminal object air outlet node name in {} = {}", RoutineName, airTerm.sysType, airTerm.SysName));
1847 0 : ShowContinueError(state, format(" Specified air outlet node name is = {}.", Alphas(4)));
1848 0 : ShowContinueError(state, format(" Expected air outlet node name is = {}.", AirTermSysOutletNodeName));
1849 : // ErrorsFound = true;
1850 : }
1851 :
1852 8 : if (airTerm.ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
1853 0 : airTerm.MaxReheatSteamVolFlow = Numbers(4);
1854 0 : airTerm.MinReheatSteamVolFlow = Numbers(5);
1855 : } else {
1856 8 : airTerm.MaxReheatWaterVolFlow = Numbers(4);
1857 8 : airTerm.MinReheatWaterVolFlow = Numbers(5);
1858 : }
1859 8 : airTerm.ControllerOffset = Numbers(6);
1860 : // Set default convergence tolerance
1861 8 : if (airTerm.ControllerOffset <= 0.0) {
1862 0 : airTerm.ControllerOffset = 0.001;
1863 : }
1864 8 : airTerm.DamperHeatingAction = Action::HeatingNotUsed;
1865 :
1866 : // Register component set data
1867 16 : TestCompSet(state,
1868 : airTerm.sysType,
1869 : airTerm.SysName,
1870 8 : state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
1871 8 : state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode),
1872 : "Air Nodes");
1873 :
1874 20 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
1875 20 : if (airTerm.ReheatAirOutletNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
1876 8 : state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = airTerm.InletNodeNum;
1877 8 : airTerm.ADUNum = ADUNum;
1878 8 : break;
1879 : }
1880 : }
1881 : // one assumes if there isn't one assigned, it's an error?
1882 8 : if (airTerm.ADUNum == 0) {
1883 0 : ShowSevereError(state,
1884 0 : format("{}No matching Air Distribution Unit, for System = [{},{}].", RoutineName, airTerm.sysType, airTerm.SysName));
1885 0 : ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
1886 0 : ErrorsFound = true;
1887 : } else {
1888 :
1889 : // Fill the Zone Equipment data with the inlet node number of this unit.
1890 : // what if not found? error?
1891 8 : IsNotOK = true;
1892 64 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
1893 56 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
1894 16 : continue;
1895 : }
1896 80 : for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
1897 40 : if (airTerm.ReheatAirOutletNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
1898 8 : IsNotOK = false;
1899 8 : if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
1900 0 : ShowSevereError(state, "Error in connecting a terminal unit to a zone");
1901 0 : ShowContinueError(
1902 0 : state, format("{} already connects to another zone", state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode)));
1903 0 : ShowContinueError(state, format("Occurs for terminal unit {} = {}", airTerm.sysType, airTerm.SysName));
1904 0 : ShowContinueError(state, "Check terminal unit node names for errors");
1905 0 : ErrorsFound = true;
1906 : } else {
1907 8 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = airTerm.InletNodeNum;
1908 8 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = airTerm.ReheatAirOutletNode;
1909 8 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).TermUnitSizingNum =
1910 8 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
1911 8 : state.dataDefineEquipment->AirDistUnit(airTerm.ADUNum).ZoneEqNum = CtrlZone;
1912 : }
1913 8 : airTerm.CtrlZoneNum = CtrlZone;
1914 8 : airTerm.CtrlZoneInNodeIndex = SupAirIn;
1915 8 : airTerm.ZoneFloorArea = state.dataHeatBal->Zone(CtrlZone).FloorArea * state.dataHeatBal->Zone(CtrlZone).Multiplier *
1916 8 : state.dataHeatBal->Zone(CtrlZone).ListMultiplier;
1917 : }
1918 : }
1919 : }
1920 : }
1921 8 : if (IsNotOK) {
1922 0 : ShowWarningError(state, "Did not Match Supply Air Outlet Node to any Zone Node");
1923 0 : ShowContinueError(state, format("..Occurs in {} = {}", airTerm.sysType, airTerm.SysName));
1924 : }
1925 :
1926 8 : if (lAlphaBlanks(9)) {
1927 8 : airTerm.ZoneTurndownMinAirFrac = 1.0;
1928 0 : } else if ((airTerm.zoneTurndownMinAirFracSched = Sched::GetSchedule(state, Alphas(9))) == nullptr) {
1929 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(9), Alphas(9));
1930 0 : ErrorsFound = true;
1931 : }
1932 :
1933 : // Add reheat coil to component sets array
1934 16 : SetUpCompSets(state,
1935 : airTerm.sysType,
1936 : airTerm.SysName,
1937 8 : Alphas(7),
1938 8 : Alphas(8),
1939 8 : state.dataLoopNodes->NodeID(airTerm.OutletNodeNum),
1940 8 : state.dataLoopNodes->NodeID(airTerm.ReheatAirOutletNode));
1941 : // Add fan to component sets array
1942 16 : SetUpCompSets(state,
1943 : airTerm.sysType,
1944 : airTerm.SysName,
1945 8 : Alphas(5),
1946 8 : Alphas(6),
1947 8 : state.dataLoopNodes->NodeID(airTerm.InletNodeNum),
1948 8 : state.dataLoopNodes->NodeID(airTerm.OutletNodeNum));
1949 :
1950 : // Setup the Average damper Position output variable
1951 16 : SetupOutputVariable(state,
1952 : "Zone Air Terminal VAV Damper Position",
1953 : Constant::Units::None,
1954 8 : airTerm.DamperPosition,
1955 : OutputProcessor::TimeStepType::System,
1956 : OutputProcessor::StoreType::Average,
1957 8 : airTerm.SysName);
1958 : }
1959 :
1960 : // common report variable for all single duct air terminals
1961 4132 : for (int sdIndex = 1; sdIndex <= state.dataSingleDuct->NumSDAirTerminal; ++sdIndex) {
1962 7214 : SetupOutputVariable(state,
1963 : "Zone Air Terminal Outdoor Air Volume Flow Rate",
1964 : Constant::Units::m3_s,
1965 3607 : state.dataSingleDuct->sd_airterminal(sdIndex).OutdoorAirFlowRate,
1966 : OutputProcessor::TimeStepType::System,
1967 : OutputProcessor::StoreType::Average,
1968 3607 : state.dataSingleDuct->sd_airterminal(sdIndex).SysName);
1969 : }
1970 :
1971 : // Error check to see if a single duct air terminal is assigned to zone that has zone secondary recirculation
1972 : // specified in the Sizing:Zone object
1973 :
1974 525 : NumZoneSiz = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Sizing:Zone");
1975 525 : if (NumZoneSiz > 0) {
1976 3506 : for (state.dataSingleDuct->SysIndexGSI = 1; state.dataSingleDuct->SysIndexGSI <= state.dataSingleDuct->NumSDAirTerminal;
1977 3151 : ++state.dataSingleDuct->SysIndexGSI) {
1978 122207 : for (ZoneSizIndex = 1; ZoneSizIndex <= NumZoneSiz; ++ZoneSizIndex) {
1979 119060 : if (state.dataGlobal->DoZoneSizing) {
1980 118783 : if (state.dataSize->FinalZoneSizing(ZoneSizIndex).ZoneNum ==
1981 118783 : state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysIndexGSI).CtrlZoneNum) {
1982 2791 : if (state.dataSize->FinalZoneSizing(ZoneSizIndex).ZoneSecondaryRecirculation > 0.0) {
1983 8 : ShowWarningError(state,
1984 8 : format("{}A zone secondary recirculation fraction is specified for zone served by ", RoutineName));
1985 8 : ShowContinueError(state,
1986 8 : format("...terminal unit \"{}\" , that indicates a single path system",
1987 4 : state.dataSingleDuct->sd_airterminal(state.dataSingleDuct->SysIndexGSI).SysName));
1988 8 : ShowContinueError(state, "...The zone secondary recirculation for that zone was set to 0.0");
1989 4 : state.dataSize->FinalZoneSizing(ZoneSizIndex).ZoneSecondaryRecirculation = 0.0;
1990 4 : goto SizLoop_exit;
1991 : }
1992 : }
1993 : }
1994 : }
1995 3151 : SizLoop_exit:;
1996 : }
1997 : }
1998 :
1999 525 : Alphas.deallocate();
2000 525 : cAlphaFields.deallocate();
2001 525 : cNumericFields.deallocate();
2002 525 : Numbers.deallocate();
2003 525 : lAlphaBlanks.deallocate();
2004 525 : lNumericBlanks.deallocate();
2005 :
2006 525 : if (ErrorsFound) {
2007 0 : ShowFatalError(state, format("{}Errors found in input. Preceding condition(s) cause termination.", RoutineName));
2008 : }
2009 525 : }
2010 :
2011 : // End of Get Input subroutines for the Module
2012 : //******************************************************************************
2013 :
2014 : // Beginning Initialization Section of the Module
2015 : //******************************************************************************
2016 :
2017 37322114 : void SingleDuctAirTerminal::InitSys(EnergyPlusData &state, bool const FirstHVACIteration)
2018 : {
2019 :
2020 : // SUBROUTINE INFORMATION:
2021 : // AUTHOR Richard J. Liesen
2022 : // DATE WRITTEN January 2000
2023 :
2024 : // PURPOSE OF THIS SUBROUTINE:
2025 : // This subroutine is for initializations of the Sys Components.
2026 :
2027 : // METHODOLOGY EMPLOYED:
2028 : // Uses the status flags to trigger events.
2029 :
2030 : // Using/Aliasing
2031 :
2032 : using DataZoneEquipment::CheckZoneEquipmentList;
2033 : using PlantUtilities::InitComponentNodes;
2034 : using PlantUtilities::ScanPlantLoopsForObject;
2035 37322114 : auto &GetHeatingCoilCapacity(HeatingCoils::GetCoilCapacity);
2036 :
2037 : // SUBROUTINE PARAMETER DEFINITIONS:
2038 : static constexpr std::string_view RoutineName("InitSys");
2039 : static constexpr std::string_view RoutineNameFull("InitHVACSingleDuct");
2040 :
2041 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2042 : int InletNode;
2043 : int OutletNode;
2044 : Real64 SteamTemp;
2045 : Real64 SteamDensity;
2046 : Real64 rho;
2047 : bool errFlag;
2048 :
2049 : // static Array1D_bool PlantLoopScanFlag;
2050 :
2051 : // Do the Begin Simulation initializations
2052 37322114 : if (this->PlantLoopScanFlag && allocated(state.dataPlnt->PlantLoop)) {
2053 3607 : if ((this->ReheatComp_PlantType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) ||
2054 1466 : (this->ReheatComp_PlantType == DataPlant::PlantEquipmentType::CoilSteamAirHeating)) {
2055 : // setup plant topology indices for plant fed heating coils
2056 2154 : errFlag = false;
2057 2154 : ScanPlantLoopsForObject(state, this->ReheatName, this->ReheatComp_PlantType, this->HWplantLoc, errFlag, _, _, _, _, _);
2058 :
2059 2154 : if (errFlag) {
2060 0 : ShowContinueError(state, format("Reference Unit=\"{}\", type={}", this->SysName, this->sysType));
2061 0 : ShowFatalError(state, "InitSys: Program terminated for previous conditions.");
2062 : }
2063 :
2064 2154 : this->ReheatCoilOutletNode = DataPlant::CompData::getPlantComponent(state, this->HWplantLoc).NodeNumOut;
2065 :
2066 2154 : this->PlantLoopScanFlag = false;
2067 : } else {
2068 1453 : this->PlantLoopScanFlag = false;
2069 : }
2070 37318507 : } else if (this->PlantLoopScanFlag && !state.dataGlobal->AnyPlantInModel) {
2071 0 : this->PlantLoopScanFlag = false;
2072 : }
2073 :
2074 37322114 : if (!state.dataSingleDuct->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
2075 525 : state.dataSingleDuct->ZoneEquipmentListChecked = true;
2076 : // Check to see if there is a Air Distribution Unit on the Zone Equipment List
2077 4132 : for (int SysIndex = 1; SysIndex <= state.dataSingleDuct->NumSDAirTerminal; ++SysIndex) {
2078 3607 : if (state.dataSingleDuct->sd_airterminal(SysIndex).ADUNum == 0) {
2079 0 : continue;
2080 : }
2081 7214 : if (CheckZoneEquipmentList(state,
2082 : "ZoneHVAC:AirDistributionUnit",
2083 3607 : state.dataDefineEquipment->AirDistUnit(state.dataSingleDuct->sd_airterminal(SysIndex).ADUNum).Name)) {
2084 3607 : continue;
2085 : }
2086 0 : ShowSevereError(state,
2087 0 : format("InitSingleDuctSystems: ADU=[Air Distribution Unit,{}] is not on any ZoneHVAC:EquipmentList.",
2088 0 : state.dataDefineEquipment->AirDistUnit(state.dataSingleDuct->sd_airterminal(SysIndex).ADUNum).Name));
2089 0 : ShowContinueError(state,
2090 0 : format("...System=[{},{}] will not be simulated.",
2091 0 : state.dataSingleDuct->sd_airterminal(SysIndex).sysType,
2092 0 : state.dataSingleDuct->sd_airterminal(SysIndex).SysName));
2093 : }
2094 : }
2095 :
2096 : // get current time step air terminal box turndown minimum flow fraction
2097 37322114 : if (this->zoneTurndownMinAirFracSched != nullptr) {
2098 18510 : this->ZoneTurndownMinAirFrac = this->zoneTurndownMinAirFracSched->getCurrentVal();
2099 : } else {
2100 37303604 : this->ZoneTurndownMinAirFrac = 1.0;
2101 : }
2102 :
2103 37322114 : if (!state.dataGlobal->SysSizingCalc && this->MySizeFlag) {
2104 :
2105 3602 : this->SizeSys(state);
2106 :
2107 3602 : this->MySizeFlag = false;
2108 : }
2109 :
2110 37322114 : if (this->GetGasElecHeatCoilCap) {
2111 3607 : if (this->ReheatComp_Num == HeatingCoilType::Electric || this->ReheatComp_Num == HeatingCoilType::Gas) {
2112 367 : if (this->ReheatCoilMaxCapacity == AutoSize) {
2113 0 : errFlag = false;
2114 0 : this->ReheatCoilMaxCapacity = GetHeatingCoilCapacity(state, this->ReheatComp, this->ReheatName, errFlag);
2115 0 : if (errFlag) {
2116 0 : ShowContinueError(state, format("Occurs for terminal unit {} = {}", this->sysType, this->SysName));
2117 : }
2118 : }
2119 367 : if (this->ReheatCoilMaxCapacity != AutoSize) {
2120 367 : this->GetGasElecHeatCoilCap = false;
2121 : }
2122 : } else {
2123 3240 : this->GetGasElecHeatCoilCap = false;
2124 : }
2125 : }
2126 :
2127 : // Do the Begin Environment initializations
2128 37322114 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
2129 :
2130 : // Set the outlet node max mass flow rate to the Max Air Flow specified for the Sys
2131 23015 : OutletNode = this->OutletNodeNum;
2132 23015 : InletNode = this->InletNodeNum;
2133 23015 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMax = this->MaxAirVolFlowRate * state.dataEnvrn->StdRhoAir;
2134 23015 : this->AirMassFlowRateMax = this->MaxAirVolFlowRate * state.dataEnvrn->StdRhoAir;
2135 23015 : this->HeatAirMassFlowRateMax = this->MaxHeatAirVolFlowRate * state.dataEnvrn->StdRhoAir;
2136 23015 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax = this->MaxAirVolFlowRate * state.dataEnvrn->StdRhoAir;
2137 23015 : this->MassFlowDiff = 1.0e-10 * this->AirMassFlowRateMax;
2138 :
2139 23015 : if (this->HWplantLoc.loopNum > 0 && this->ReheatComp_Num != HeatingCoilType::SteamAirHeating) { // protect early calls before plant is setup
2140 14269 : rho = state.dataPlnt->PlantLoop(this->HWplantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
2141 : } else {
2142 8746 : rho = 1000.0;
2143 : }
2144 :
2145 23015 : this->MaxReheatWaterFlow = rho * this->MaxReheatWaterVolFlow;
2146 23015 : this->MinReheatWaterFlow = rho * this->MinReheatWaterVolFlow;
2147 :
2148 23015 : this->AirMassFlowDuringReheatMax = this->MaxAirVolFlowRateDuringReheat * state.dataEnvrn->StdRhoAir;
2149 :
2150 : // set the upstream leakage flowrate - remove from here - done in ZoneAirLoopEquipmentManager::SimZoneAirLoopEquipment
2151 :
2152 23015 : if (this->ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
2153 78 : SteamTemp = 100.0;
2154 78 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, SteamTemp, 1.0, RoutineNameFull);
2155 78 : this->MaxReheatSteamFlow = SteamDensity * this->MaxReheatSteamVolFlow;
2156 78 : this->MinReheatSteamFlow = SteamDensity * this->MinReheatSteamVolFlow;
2157 : }
2158 :
2159 : // get current environment air terminal box turndown minimum flow fraction
2160 23015 : Real64 CurrentEnvZoneTurndownMinAirFrac = 1.0;
2161 23015 : if (this->zoneTurndownMinAirFracSched != nullptr) {
2162 80 : CurrentEnvZoneTurndownMinAirFrac = this->zoneTurndownMinAirFracSched->getCurrentVal();
2163 : }
2164 23015 : if ((this->SysType_Num == SysType::SingleDuctVAVReheat || this->SysType_Num == SysType::SingleDuctCBVAVReheat) ||
2165 8232 : (this->SysType_Num == SysType::SingleDuctCBVAVNoReheat)) {
2166 : // need the lowest schedule value
2167 14803 : if (this->ZoneMinAirFracMethod == MinFlowFraction::Scheduled) {
2168 232 : this->ZoneMinAirFracDes = this->zoneMinAirFracSched->getCurrentVal();
2169 : }
2170 14803 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMin =
2171 14803 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMax * this->ZoneMinAirFracDes * CurrentEnvZoneTurndownMinAirFrac;
2172 14803 : state.dataLoopNodes->Node(InletNode).MassFlowRateMin =
2173 14803 : state.dataLoopNodes->Node(InletNode).MassFlowRateMax * this->ZoneMinAirFracDes * CurrentEnvZoneTurndownMinAirFrac;
2174 : } else {
2175 8212 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMin = 0.0;
2176 8212 : state.dataLoopNodes->Node(InletNode).MassFlowRateMin = 0.0;
2177 : }
2178 23015 : if ((this->ReheatControlNode > 0) && !this->PlantLoopScanFlag) {
2179 14347 : if (this->ReheatComp_Num == HeatingCoilType::SteamAirHeating) {
2180 78 : InitComponentNodes(state, this->MinReheatSteamFlow, this->MaxReheatSteamFlow, this->ReheatControlNode, this->ReheatCoilOutletNode);
2181 : } else {
2182 14269 : InitComponentNodes(state, this->MinReheatWaterFlow, this->MaxReheatWaterFlow, this->ReheatControlNode, this->ReheatCoilOutletNode);
2183 : }
2184 : }
2185 : // Find air loop associated with terminal unit
2186 23015 : if ((this->CtrlZoneNum > 0) && (this->CtrlZoneInNodeIndex > 0)) {
2187 23015 : this->AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(this->CtrlZoneNum).InletNodeAirLoopNum(this->CtrlZoneInNodeIndex);
2188 23015 : state.dataDefineEquipment->AirDistUnit(this->ADUNum).AirLoopNum = this->AirLoopNum;
2189 : }
2190 :
2191 23015 : this->MyEnvrnFlag = false;
2192 : }
2193 :
2194 37322114 : if (!state.dataGlobal->BeginEnvrnFlag) {
2195 37157682 : this->MyEnvrnFlag = true;
2196 : }
2197 :
2198 : // Initialize the Inlet Nodes of the air side of air terminal
2199 37322114 : InletNode = this->InletNodeNum;
2200 37322114 : OutletNode = this->OutletNodeNum;
2201 :
2202 37322114 : Real64 mDotFromOARequirement(0.0);
2203 :
2204 37322114 : if (this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
2205 8544703 : if (!this->NoOAFlowInputFromUser) {
2206 6414 : mDotFromOARequirement = this->AirMassFlowRateMax;
2207 6414 : int airLoopNum(0);
2208 6414 : Real64 airLoopOAFrac(0.0);
2209 6414 : airLoopNum = this->AirLoopNum;
2210 6414 : if (airLoopNum > 0) {
2211 6405 : airLoopOAFrac = state.dataAirLoop->AirLoopFlow(airLoopNum).OAFrac;
2212 6405 : bool UseOccSchFlag = false;
2213 6405 : if (this->OAPerPersonMode == DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel) {
2214 6405 : UseOccSchFlag = true;
2215 : }
2216 6405 : if (airLoopOAFrac > 0.0) {
2217 : Real64 vDotOAReq =
2218 6389 : DataSizing::calcDesignSpecificationOutdoorAir(state, this->OARequirementsPtr, this->CtrlZoneNum, UseOccSchFlag, true);
2219 6389 : mDotFromOARequirement = vDotOAReq * state.dataEnvrn->StdRhoAir / airLoopOAFrac;
2220 6389 : mDotFromOARequirement = min(mDotFromOARequirement, this->AirMassFlowRateMax);
2221 : } else {
2222 16 : mDotFromOARequirement = this->AirMassFlowRateMax;
2223 : }
2224 : }
2225 : }
2226 : }
2227 :
2228 37322114 : if (this->ZoneMinAirFracMethod == MinFlowFraction::Scheduled) {
2229 2288391 : this->ZoneMinAirFracDes = this->zoneMinAirFracSched->getCurrentVal();
2230 : // now reset inlet node min avail
2231 2288391 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = this->AirMassFlowRateMax * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
2232 : }
2233 :
2234 37322114 : if (FirstHVACIteration) {
2235 : // The first time through set the mass flow rate to the Max
2236 14340948 : if ((state.dataLoopNodes->Node(InletNode).MassFlowRate > 0.0) && (this->availSched->getCurrentVal() > 0.0)) {
2237 11590966 : if (!(state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated)) {
2238 11590950 : state.dataLoopNodes->Node(InletNode).MassFlowRate = this->AirMassFlowRateMax;
2239 : }
2240 : } else {
2241 2749982 : state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
2242 : }
2243 14340948 : if ((state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail > 0.0) && (this->availSched->getCurrentVal() > 0.0)) {
2244 11591228 : if (!(state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated)) {
2245 11591212 : if (this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
2246 2350930 : if (this->NoOAFlowInputFromUser) {
2247 2347731 : state.dataLoopNodes->Node(InletNode).MassFlowRate = this->AirMassFlowRateMax;
2248 2347731 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = this->AirMassFlowRateMax;
2249 : } else {
2250 3199 : state.dataLoopNodes->Node(InletNode).MassFlowRate = mDotFromOARequirement;
2251 3199 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = mDotFromOARequirement;
2252 : }
2253 2350930 : if (this->EMSOverrideAirFlow) {
2254 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate = this->EMSMassFlowRateValue;
2255 0 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = this->EMSMassFlowRateValue;
2256 : }
2257 : } else {
2258 9240282 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = this->AirMassFlowRateMax;
2259 : }
2260 : }
2261 : } else {
2262 2749720 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = 0.0;
2263 : }
2264 :
2265 14340948 : if ((state.dataLoopNodes->Node(InletNode).MassFlowRate > 0.0) && (this->availSched->getCurrentVal() > 0.0)) {
2266 11590967 : if (!(state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated)) {
2267 11590951 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail =
2268 11590951 : this->AirMassFlowRateMax * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
2269 : }
2270 : } else {
2271 2749981 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = 0.0;
2272 : }
2273 : // reset the mass flow rate histories
2274 14340948 : this->MassFlow1 = 0.0;
2275 14340948 : this->MassFlow2 = 0.0;
2276 14340948 : this->MassFlow3 = 0.0;
2277 14340948 : this->MassFlow3 = 0.0;
2278 :
2279 : } else {
2280 22981166 : if (this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
2281 5468931 : if (!this->EMSOverrideAirFlow) {
2282 5468931 : if ((state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail > 0.0) && (this->availSched->getCurrentVal() > 0.0)) {
2283 4676379 : if (this->NoOAFlowInputFromUser) {
2284 4673185 : if (state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail < state.dataLoopNodes->Node(InletNode).MassFlowRateMax) {
2285 1871145 : state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail;
2286 2802040 : } else if (state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail > state.dataLoopNodes->Node(InletNode).MassFlowRateMin) {
2287 92214 : state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail;
2288 : } else {
2289 2709826 : state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail;
2290 : }
2291 : } else {
2292 3194 : state.dataLoopNodes->Node(InletNode).MassFlowRate = mDotFromOARequirement;
2293 : // but also apply constraints
2294 3194 : state.dataLoopNodes->Node(InletNode).MassFlowRate =
2295 3194 : min(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail);
2296 3194 : state.dataLoopNodes->Node(InletNode).MassFlowRate =
2297 3194 : min(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMax);
2298 3194 : state.dataLoopNodes->Node(InletNode).MassFlowRate =
2299 3194 : max(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail);
2300 3194 : state.dataLoopNodes->Node(InletNode).MassFlowRate =
2301 3194 : max(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMin);
2302 : }
2303 : } else {
2304 792552 : state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
2305 792552 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = 0.0;
2306 792552 : state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail = 0.0;
2307 : }
2308 : } else { // EMS override on
2309 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate = this->EMSMassFlowRateValue;
2310 : // but also apply constraints
2311 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate =
2312 0 : min(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail);
2313 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate =
2314 0 : min(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMax);
2315 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate =
2316 0 : max(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail);
2317 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate =
2318 0 : max(state.dataLoopNodes->Node(InletNode).MassFlowRate, state.dataLoopNodes->Node(InletNode).MassFlowRateMin);
2319 : }
2320 : }
2321 : }
2322 :
2323 : // Do a check and make sure that the max and min available(control) flow is
2324 : // between the physical max and min while operating.
2325 37322114 : this->sd_airterminalInlet.AirMassFlowRateMaxAvail = min(this->AirMassFlowRateMax, state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail);
2326 37322114 : this->sd_airterminalInlet.AirMassFlowRateMinAvail =
2327 37322114 : min(max(state.dataLoopNodes->Node(OutletNode).MassFlowRateMin, state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail),
2328 : this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
2329 :
2330 : // Do the following initializations (every time step): This should be the info from
2331 : // the previous components outlets or the node data in this section.
2332 : // Load the node data in this section for the component simulation
2333 37322114 : this->sd_airterminalInlet.AirMassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
2334 37322114 : this->sd_airterminalInlet.AirTemp = state.dataLoopNodes->Node(InletNode).Temp;
2335 37322114 : this->sd_airterminalInlet.AirHumRat = state.dataLoopNodes->Node(InletNode).HumRat;
2336 37322114 : this->sd_airterminalInlet.AirEnthalpy = state.dataLoopNodes->Node(InletNode).Enthalpy;
2337 :
2338 : // update to the current minimum air flow fraction
2339 37322114 : this->ZoneMinAirFrac = this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
2340 37322114 : }
2341 :
2342 3602 : void SingleDuctAirTerminal::SizeSys(EnergyPlusData &state)
2343 : {
2344 :
2345 : // SUBROUTINE INFORMATION:
2346 : // AUTHOR Fred Buhl
2347 : // DATE WRITTEN September 2001
2348 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
2349 :
2350 : // PURPOSE OF THIS SUBROUTINE:
2351 : // This subroutine is for sizing Sys Components for which flow rates have not been
2352 : // specified in the input.
2353 :
2354 : // METHODOLOGY EMPLOYED:
2355 : // Obtains flow rates from the zone or system sizing arrays.
2356 :
2357 : // Using/Aliasing
2358 : using General::SafeDivide;
2359 : using PlantUtilities::MyPlantSizingIndex;
2360 : using SteamCoils::GetCoilSteamInletNode;
2361 : using SteamCoils::GetCoilSteamOutletNode;
2362 : using WaterCoils::GetCoilWaterInletNode;
2363 : using WaterCoils::GetCoilWaterOutletNode;
2364 : using WaterCoils::SetCoilDesFlow;
2365 :
2366 : // SUBROUTINE PARAMETER DEFINITIONS:
2367 : static constexpr std::string_view RoutineName("SizeSys");
2368 : static constexpr std::string_view RoutineNameFull("SizeHVACSingleDuct");
2369 :
2370 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2371 : int PltSizHeatNum; // index of plant sizing object for 1st heating loop
2372 : Real64 TempSteamIn;
2373 : Real64 EnthSteamOutWet;
2374 : Real64 EnthSteamInDry;
2375 : Real64 LatentHeatSteam;
2376 : Real64 SteamDensity;
2377 :
2378 : bool PlantSizingErrorsFound;
2379 : Real64 rho; // local fluid density
2380 : Real64 Cp; // local fluid specific heat
2381 :
2382 3602 : Real64 DesMassFlow = 0.0;
2383 3602 : bool ErrorsFound = false;
2384 3602 : bool IsAutoSize = false;
2385 3602 : bool IsMaxFlowAutoSize = false;
2386 3602 : Real64 MaxAirVolFlowRateDes = 0.0; // Autosized maximum air flow rate for reporting
2387 3602 : Real64 MaxAirVolFlowRateUser = 0.0; // Hardsized maximum air flow rate for reporting
2388 3602 : Real64 MaxHeatAirVolFlowRateDes = 0.0; // Autosized maximum heating air flow rate for reporting
2389 3602 : Real64 MaxHeatAirVolFlowRateUser = 0.0; // Hardsized maximum heating air flow rate for reporting
2390 3602 : Real64 MinAirFlowFracDes = 0.0; // Autosized minimum cooling air flow fraction for reporting
2391 3602 : Real64 MinAirFlowFracUser = 0.0; // User input minimum cooling air flow fraction for reporting
2392 3602 : Real64 FixedMinAirDes = 0.0; // Autosized minimum cooling air flow rate for reporting [m3/s]
2393 3602 : Real64 FixedMinAirUser = 0.0; // User input minimum cooling air flow rate for reporting [m3/s]
2394 3602 : Real64 MaxAirVolFlowRateDuringReheatDes = 0.0; // Autosized maximum air flow durign reheat for reporting
2395 3602 : Real64 MaxAirVolFlowRateDuringReheatUser = 0.0; // Hardsized maximum air flow durign reheat for reporting
2396 3602 : Real64 MaxAirVolFractionDuringReheatDes = 0.0; // Autosized maximum air fraction durign reheat for reporting
2397 3602 : Real64 MaxAirVolFractionDuringReheatUser = 0.0; // Hardsized maximum air flow durign reheat for reporting
2398 3602 : Real64 MaxReheatWaterVolFlowDes = 0.0; // Autosized reheat water flow or reporting
2399 3602 : Real64 MaxReheatWaterVolFlowUser = 0.0; // Hardsized reheat water flow for reporting
2400 3602 : Real64 MaxReheatSteamVolFlowDes = 0.0; // Autosized reheat steam flow for reporting
2401 3602 : Real64 MaxReheatSteamVolFlowUser = 0.0; // Hardsized reheat steam flow for reporting
2402 3602 : Real64 MinMinFlowRatio = 0.0; // the minimum minimum flow ratio
2403 3602 : int SysSizNum = 0; // System sizing number
2404 :
2405 3602 : int ZoneNum = this->CtrlZoneNum;
2406 :
2407 3602 : auto &TermUnitSizing(state.dataSize->TermUnitSizing);
2408 :
2409 3602 : if (this->MaxAirVolFlowRate == AutoSize) {
2410 3025 : IsAutoSize = true;
2411 : }
2412 :
2413 3602 : if (state.dataSize->CurTermUnitSizingNum > 0) {
2414 3602 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation continue
2415 515 : if (this->MaxAirVolFlowRate > 0.0) {
2416 515 : BaseSizer::reportSizerOutput(
2417 : state, this->sysType, this->SysName, "User-Specified Maximum Air Flow Rate [m3/s]", this->MaxAirVolFlowRate);
2418 : }
2419 : } else { // Autosize or hard-size with sizing run
2420 :
2421 3087 : CheckZoneSizing(state, this->sysType, this->SysName);
2422 :
2423 : Real64 heatingMaxFlow;
2424 4179 : if (this->DamperHeatingAction == Action::ReverseWithLimits &&
2425 1092 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow >
2426 1092 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax) {
2427 199 : heatingMaxFlow = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax;
2428 : } else {
2429 2888 : heatingMaxFlow = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
2430 : }
2431 3087 : MaxAirVolFlowRateDes = max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlow, heatingMaxFlow);
2432 :
2433 3087 : if (MaxAirVolFlowRateDes < SmallAirVolFlow) {
2434 0 : MaxAirVolFlowRateDes = 0.0;
2435 : }
2436 3087 : if (IsAutoSize) {
2437 3025 : this->MaxAirVolFlowRate = MaxAirVolFlowRateDes;
2438 3025 : IsMaxFlowAutoSize = true;
2439 3025 : BaseSizer::reportSizerOutput(state, this->sysType, this->SysName, "Design Size Maximum Air Flow Rate [m3/s]", MaxAirVolFlowRateDes);
2440 : } else { // Hard-size with sizing data
2441 62 : if (this->MaxAirVolFlowRate > 0.0 && MaxAirVolFlowRateDes > 0.0) {
2442 62 : MaxAirVolFlowRateUser = this->MaxAirVolFlowRate;
2443 62 : BaseSizer::reportSizerOutput(state,
2444 : this->sysType,
2445 : this->SysName,
2446 : "Design Size Maximum Air Flow Rate [m3/s]",
2447 : MaxAirVolFlowRateDes,
2448 : "User-Specified Maximum Air Flow Rate [m3/s]",
2449 : MaxAirVolFlowRateUser);
2450 62 : if (state.dataGlobal->DisplayExtraWarnings) {
2451 0 : if ((std::abs(MaxAirVolFlowRateDes - MaxAirVolFlowRateUser) / MaxAirVolFlowRateUser) >
2452 0 : state.dataSize->AutoVsHardSizingThreshold) {
2453 0 : ShowMessage(
2454 : state,
2455 0 : format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
2456 0 : ShowContinueError(state, format("User-Specified Maximum Air Flow Rate of {:.5R} [m3/s]", MaxAirVolFlowRateUser));
2457 0 : ShowContinueError(state, format("differs from Design Size Maximum Air Flow Rate of {:.5R} [m3/s]", MaxAirVolFlowRateDes));
2458 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2459 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2460 : }
2461 : }
2462 : }
2463 : }
2464 : }
2465 : }
2466 :
2467 3602 : IsAutoSize = false;
2468 3602 : if (this->MaxHeatAirVolFlowRate == AutoSize) {
2469 8 : IsAutoSize = true;
2470 : }
2471 3602 : if (state.dataSize->CurTermUnitSizingNum > 0) {
2472 3602 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // simulation should continue
2473 515 : state.dataSingleDuct->UserInputMaxHeatAirVolFlowRateSS = this->MaxHeatAirVolFlowRate;
2474 515 : if (this->MaxHeatAirVolFlowRate > 0.0) {
2475 0 : BaseSizer::reportSizerOutput(
2476 : state, this->sysType, this->SysName, "User-Specified Maximum Heating Air Flow Rate [m3/s]", this->MaxHeatAirVolFlowRate);
2477 : }
2478 : } else {
2479 3087 : CheckZoneSizing(state, this->sysType, this->SysName);
2480 4179 : if (this->DamperHeatingAction == Action::ReverseWithLimits &&
2481 1092 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow >
2482 1092 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax) {
2483 199 : MaxHeatAirVolFlowRateDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax;
2484 : } else {
2485 2888 : MaxHeatAirVolFlowRateDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
2486 : }
2487 3087 : if (MaxHeatAirVolFlowRateDes < SmallAirVolFlow) {
2488 14 : MaxHeatAirVolFlowRateDes = 0.0;
2489 : }
2490 3087 : if (IsAutoSize) {
2491 8 : this->MaxHeatAirVolFlowRate = MaxHeatAirVolFlowRateDes;
2492 8 : state.dataSingleDuct->UserInputMaxHeatAirVolFlowRateSS = 0.0;
2493 8 : BaseSizer::reportSizerOutput(
2494 : state, this->sysType, this->SysName, "Design Size Maximum Heating Air Flow Rate [m3/s]", MaxHeatAirVolFlowRateDes);
2495 : } else { // Hard-size with sizing data
2496 3079 : if (this->MaxHeatAirVolFlowRate > 0.0 && MaxHeatAirVolFlowRateDes > 0.0) {
2497 0 : MaxHeatAirVolFlowRateUser = this->MaxHeatAirVolFlowRate;
2498 0 : state.dataSingleDuct->UserInputMaxHeatAirVolFlowRateSS = this->MaxHeatAirVolFlowRate;
2499 0 : BaseSizer::reportSizerOutput(state,
2500 : this->sysType,
2501 : this->SysName,
2502 : "Design Size Maximum Heating Air Flow Rate [m3/s]",
2503 : MaxHeatAirVolFlowRateDes,
2504 : "User-Specified Maximum Heating Air Flow Rate [m3/s]",
2505 : MaxHeatAirVolFlowRateUser);
2506 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2507 0 : if ((std::abs(MaxHeatAirVolFlowRateDes - MaxHeatAirVolFlowRateUser) / MaxHeatAirVolFlowRateUser) >
2508 0 : state.dataSize->AutoVsHardSizingThreshold) {
2509 0 : ShowMessage(
2510 : state,
2511 0 : format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
2512 0 : ShowContinueError(state,
2513 0 : format("User-Specified Maximum Heating Air Flow Rate of {:.5R} [m3/s]", MaxHeatAirVolFlowRateUser));
2514 0 : ShowContinueError(
2515 0 : state, format("differs from Design Size Maximum Heating Air Flow Rate of {:.5R} [m3/s]", MaxHeatAirVolFlowRateDes));
2516 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2517 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2518 : }
2519 : }
2520 : }
2521 : }
2522 : }
2523 : }
2524 :
2525 : // get design day terminal unit turndown minimum flow fraction
2526 3602 : if (this->zoneTurndownMinAirFracSched != nullptr) {
2527 5 : this->ZoneTurndownMinAirFrac = this->zoneTurndownMinAirFracSched->getCurrentVal();
2528 : } else {
2529 3597 : this->ZoneTurndownMinAirFrac = 1.0;
2530 : }
2531 :
2532 : // if a sizing run has been done, check if system sizing has been done for this system
2533 3602 : bool SizingDesRunThisAirSys = false;
2534 3602 : if (state.dataSize->SysSizingRunDone) {
2535 3059 : int AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(this->CtrlZoneNum).InletNodeAirLoopNum(this->CtrlZoneInNodeIndex);
2536 3059 : if (AirLoopNum > 0) {
2537 3059 : CheckThisAirSystemForSizing(state, AirLoopNum, SizingDesRunThisAirSys);
2538 : }
2539 :
2540 : // get system sizing id if a sizing run has been done for this system
2541 3059 : if (SizingDesRunThisAirSys) {
2542 3055 : SysSizNum = Util::FindItemInList(
2543 3055 : state.dataSize->FinalSysSizing(AirLoopNum).AirPriLoopName, state.dataSize->SysSizInput, &SystemSizingInputData::AirPriLoopName);
2544 3055 : if (SysSizNum == 0) {
2545 0 : SysSizNum = 1; // use first when none applicable
2546 : }
2547 : }
2548 : }
2549 :
2550 3602 : IsAutoSize = false;
2551 3602 : if (this->ZoneMinAirFracDes == AutoSize) {
2552 45 : IsAutoSize = true;
2553 : }
2554 3602 : if (this->ZoneMinAirFracMethod == MinFlowFraction::Constant) {
2555 2308 : if (state.dataSize->ZoneSizingRunDone) {
2556 2264 : if (state.dataSize->CurTermUnitSizingNum > 0) {
2557 : // use the combined defaults or other user inputs stored in DesCoolVolFlowMin
2558 2264 : if (this->MaxAirVolFlowRate > 0.0) {
2559 2264 : MinAirFlowFracDes = min(1.0,
2560 2264 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlowMin /
2561 2264 : this->MaxAirVolFlowRate);
2562 : } else {
2563 0 : MinAirFlowFracDes = 0.0;
2564 : }
2565 : }
2566 : } else {
2567 : // if no zone sizing values available; use max of min frac = 0.2 and 0.000762 [m3/s-m2]
2568 44 : if (this->MaxAirVolFlowRate > 0.0) {
2569 44 : MinMinFlowRatio = (0.000762 * state.dataHeatBal->Zone(ZoneNum).FloorArea * state.dataHeatBal->Zone(ZoneNum).Multiplier *
2570 44 : state.dataHeatBal->Zone(ZoneNum).ListMultiplier) /
2571 44 : this->MaxAirVolFlowRate;
2572 44 : MinAirFlowFracDes = max(0.2, MinMinFlowRatio);
2573 : } else {
2574 0 : MinAirFlowFracDes = 0.0;
2575 : }
2576 : }
2577 2308 : if (SizingDesRunThisAirSys) {
2578 2261 : if (state.dataSize->SysSizInput(SysSizNum).SystemOAMethod == SysOAMethod::SP) { // 62.1 simplified procedure
2579 4 : if (this->MaxAirVolFlowRate > 0.0) {
2580 4 : MinAirFlowFracDes = 1.5 *
2581 4 : max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VozClgByZone,
2582 4 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VozHtgByZone) /
2583 4 : this->MaxAirVolFlowRate;
2584 :
2585 : // adjust maximum flow rate
2586 4 : if (MinAirFlowFracDes > 1.0 && IsMaxFlowAutoSize) {
2587 0 : this->MaxAirVolFlowRate *= MinAirFlowFracDes;
2588 0 : MinAirFlowFracDes = 1.0;
2589 0 : ShowWarningError(state,
2590 0 : format("SingleDuctSystem:SizeSys: Autosized maximum air flow rate for {} was increased to meet the zone "
2591 : "primary air flow determined according to the ASHRAE Standard 62.1 Simplified Procedure.",
2592 0 : this->SysName));
2593 4 : } else if (MinAirFlowFracDes > 1.0) {
2594 0 : ShowWarningError(state,
2595 0 : format("SingleDuctSystem:SizeSys: Maximum air flow rate for {} is potentially too low.", this->SysName));
2596 0 : ShowContinueError(
2597 : state,
2598 : "The flow is lower than the minimum flow rate calculated following the ASHRAE Standard 62.1 Simplified Procedure:");
2599 0 : ShowContinueError(state, format(" User-specified maximum air flow rate: {:.3R} m3/s.", this->MaxAirVolFlowRate));
2600 0 : ShowContinueError(state,
2601 0 : format(" Calculated minimum air flow rate: {:.3R} m3/s.", this->MaxAirVolFlowRate * MinAirFlowFracDes));
2602 0 : MinAirFlowFracDes = 1.0;
2603 : }
2604 : }
2605 : }
2606 : }
2607 2308 : if (IsAutoSize) {
2608 : // report out autosized result and save value in Sys array
2609 86 : BaseSizer::reportSizerOutput(state,
2610 : this->sysType,
2611 : this->SysName,
2612 : "Design Size Constant Minimum Air Flow Fraction",
2613 43 : MinAirFlowFracDes * this->ZoneTurndownMinAirFrac);
2614 43 : if (SizingDesRunThisAirSys) {
2615 43 : if (state.dataSize->SysSizInput(SysSizNum).SystemOAMethod == SysOAMethod::SP) {
2616 4 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VpzMinByZoneSPSized = true;
2617 : }
2618 : }
2619 43 : this->ZoneMinAirFracDes = MinAirFlowFracDes;
2620 : } else {
2621 : // report out hard (user set) value and issue warning if appropriate
2622 2265 : MinAirFlowFracUser = this->ZoneMinAirFracDes;
2623 4530 : BaseSizer::reportSizerOutput(state,
2624 : this->sysType,
2625 : this->SysName,
2626 : "Design Size Constant Minimum Air Flow Fraction",
2627 2265 : MinAirFlowFracDes * this->ZoneTurndownMinAirFrac,
2628 : "User-Specified Constant Minimum Air Flow Fraction",
2629 2265 : MinAirFlowFracUser * this->ZoneTurndownMinAirFrac);
2630 2265 : if (state.dataGlobal->DisplayExtraWarnings) {
2631 220 : if ((MinAirFlowFracUser > 0.0) &&
2632 110 : ((std::abs(MinAirFlowFracDes - MinAirFlowFracUser) / MinAirFlowFracUser) > state.dataSize->AutoVsHardSizingThreshold)) {
2633 194 : ShowMessage(state,
2634 194 : format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
2635 97 : ShowContinueError(state, format("User-Specified Minimum Cooling Air Flow Fraction of {:.5R}", MinAirFlowFracUser));
2636 97 : ShowContinueError(state, format("differs from Design Size Minimum Cooling Air Flow Fraction of {:.5R}", MinAirFlowFracDes));
2637 194 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2638 291 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2639 : }
2640 : }
2641 : }
2642 : // report out the min air flow rate set by min air flow frac
2643 4616 : BaseSizer::reportSizerOutput(state,
2644 : this->sysType,
2645 : this->SysName,
2646 : "Design Size Minimum Air Flow Rate [m3/s]",
2647 2308 : this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac);
2648 : } else {
2649 1294 : if (IsAutoSize) {
2650 2 : this->ZoneMinAirFracDes = 0.0;
2651 : }
2652 : }
2653 :
2654 3602 : IsAutoSize = false;
2655 3602 : if (this->ZoneFixedMinAir == AutoSize) {
2656 2397 : IsAutoSize = true;
2657 : }
2658 3602 : if (this->ZoneMinAirFracMethod == MinFlowFraction::Fixed) {
2659 3 : if (state.dataSize->ZoneSizingRunDone) {
2660 2 : if (state.dataSize->CurTermUnitSizingNum > 0) {
2661 : // use the combined defaults or other user inputs stored in DesCoolVolFlowMin
2662 2 : if (this->MaxAirVolFlowRate > 0.0) {
2663 2 : FixedMinAirDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlowMin;
2664 : } else {
2665 0 : MinAirFlowFracDes = 0.0;
2666 : }
2667 : }
2668 : } else {
2669 : // if no zone sizing values available; use max of min frac = 0.2 and 0.000762 [m3/s-m2]
2670 1 : if (this->MaxAirVolFlowRate > 0.0) {
2671 1 : FixedMinAirDes = max(0.2 * this->MaxAirVolFlowRate,
2672 1 : 0.000762 * state.dataHeatBal->Zone(ZoneNum).FloorArea * state.dataHeatBal->Zone(ZoneNum).Multiplier *
2673 1 : state.dataHeatBal->Zone(ZoneNum).ListMultiplier);
2674 : } else {
2675 0 : MinAirFlowFracDes = 0.0;
2676 : }
2677 : }
2678 3 : if (SizingDesRunThisAirSys) {
2679 2 : if (state.dataSize->SysSizInput(SysSizNum).SystemOAMethod == SysOAMethod::SP) { // 62.1 simplified procedure
2680 2 : if (this->MaxAirVolFlowRate > 0.0) {
2681 2 : FixedMinAirDes = 1.5 * max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VozClgByZone,
2682 2 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VozHtgByZone);
2683 :
2684 : // adjust maximum flow rate
2685 2 : if (FixedMinAirDes > this->MaxAirVolFlowRate && IsMaxFlowAutoSize) {
2686 0 : this->MaxAirVolFlowRate = FixedMinAirDes;
2687 0 : ShowWarningError(state,
2688 0 : format("SingleDuctSystem:SizeSys: Autosized maximum air flow rate for {} was increased to meet the zone "
2689 : "primary air flow determined according to the ASHRAE Standard 62.1 Simplified Procedure.",
2690 0 : this->SysName));
2691 2 : } else if (FixedMinAirDes > this->MaxAirVolFlowRate) {
2692 0 : ShowWarningError(state,
2693 0 : format("SingleDuctSystem:SizeSys: Maximum air flow rate for {} is potentially too low.", this->SysName));
2694 0 : ShowContinueError(
2695 : state,
2696 : "The flow is lower than the minimum flow rate calculated following the ASHRAE Standard 62.1 Simplified Procedure:");
2697 0 : ShowContinueError(state, format(" User-specified maximum air flow rate: {:.3R} m3/s.", this->MaxAirVolFlowRate));
2698 0 : ShowContinueError(state, format(" Calculated minimum air flow rate: {:.3R} m3/s.", FixedMinAirDes));
2699 0 : FixedMinAirDes = this->MaxAirVolFlowRate;
2700 : }
2701 : }
2702 : }
2703 : }
2704 3 : if (IsAutoSize) {
2705 : // report out autosized result and save value in Sys array
2706 4 : BaseSizer::reportSizerOutput(
2707 2 : state, this->sysType, this->SysName, "Design Size Fixed Minimum Air Flow Rate [m3/s]", FixedMinAirDes * this->ZoneTurndownMinAirFrac);
2708 2 : if (SizingDesRunThisAirSys) {
2709 2 : if (state.dataSize->SysSizInput(SysSizNum).SystemOAMethod == SysOAMethod::SP) {
2710 2 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VpzMinByZoneSPSized = true;
2711 : }
2712 : }
2713 2 : this->ZoneFixedMinAir = FixedMinAirDes;
2714 : } else {
2715 : // report out hard (user set) value and issue warning if appropriate
2716 1 : FixedMinAirUser = this->ZoneFixedMinAir;
2717 2 : BaseSizer::reportSizerOutput(state,
2718 : this->sysType,
2719 : this->SysName,
2720 : "Design Size Fixed Minimum Air Flow Rate [m3/s]",
2721 1 : FixedMinAirDes * this->ZoneTurndownMinAirFrac,
2722 : "User-Specified Fixed Minimum Air Flow Rate [m3/s]",
2723 1 : FixedMinAirUser * this->ZoneTurndownMinAirFrac);
2724 1 : if (state.dataGlobal->DisplayExtraWarnings) {
2725 0 : if ((std::abs(FixedMinAirDes - FixedMinAirUser) / FixedMinAirUser) > state.dataSize->AutoVsHardSizingThreshold) {
2726 0 : ShowMessage(state,
2727 0 : format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
2728 0 : ShowContinueError(state, format("User-Specified Minimum Cooling Air Flow Rate of {:.5R} [m3/s]", FixedMinAirUser));
2729 0 : ShowContinueError(state, format("differs from Design Size Minimum Cooling Air Flow Rate of {:.5R} [m3/s]", FixedMinAirDes));
2730 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2731 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2732 : }
2733 : }
2734 : }
2735 : // report out the min air flow frac set by the min air flow rate
2736 3 : if (this->MaxAirVolFlowRate > 0.0) {
2737 6 : BaseSizer::reportSizerOutput(state,
2738 : this->sysType,
2739 : this->SysName,
2740 : "Design Size Minimum Air Flow Fraction [m3/s]",
2741 3 : this->ZoneFixedMinAir * this->ZoneTurndownMinAirFrac / this->MaxAirVolFlowRate);
2742 : }
2743 : } else {
2744 3599 : if (IsAutoSize) {
2745 2395 : this->ZoneFixedMinAir = 0.0;
2746 : }
2747 : }
2748 :
2749 3602 : if (this->ZoneMinAirFracMethod == MinFlowFraction::Scheduled) {
2750 : // need a value for sizing.
2751 163 : if (this->ConstantMinAirFracSetByUser) {
2752 3 : this->ZoneMinAirFracDes = this->DesignMinAirFrac;
2753 : // if both inputs are defined, use the max
2754 3 : if (this->FixedMinAirSetByUser) {
2755 0 : this->ZoneMinAirFracDes = min(1.0, max(this->ZoneMinAirFracDes, SafeDivide(this->DesignFixedMinAir, this->MaxAirVolFlowRate)));
2756 : }
2757 : // if only fixed is defined, use the value
2758 160 : } else if (this->FixedMinAirSetByUser) {
2759 0 : this->ZoneMinAirFracDes = min(1.0, SafeDivide(this->DesignFixedMinAir, this->MaxAirVolFlowRate));
2760 : } else {
2761 : // use an average of min and max in schedule
2762 160 : this->ZoneMinAirFracDes = (this->zoneMinAirFracSched->getMinVal(state) + this->zoneMinAirFracSched->getMaxVal(state)) / 2.0;
2763 : }
2764 : }
2765 :
2766 3602 : if (this->ZoneMinAirFracMethod == MinFlowFraction::Fixed) {
2767 : // need a value for sizing.
2768 3 : this->ZoneMinAirFracDes = min(1.0, SafeDivide(this->ZoneFixedMinAir, this->MaxAirVolFlowRate));
2769 : }
2770 :
2771 3602 : if (this->DamperHeatingAction == Action::ReverseWithLimits) {
2772 1114 : if (state.dataSize->ZoneSizingRunDone) {
2773 1092 : if (state.dataSize->CurTermUnitSizingNum > 0) {
2774 : // if zone sizing run done, set the design max reheat air flow to the value from the design calcs
2775 1092 : if (state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow >
2776 1092 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax) {
2777 199 : MaxAirVolFlowRateDuringReheatDes =
2778 199 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax;
2779 : } else {
2780 893 : MaxAirVolFlowRateDuringReheatDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
2781 : }
2782 : }
2783 : } else {
2784 : // if no design calc use 0.002032 [m3/s-m2] times floor area. That's .40 cfm/ft2
2785 22 : MaxAirVolFlowRateDuringReheatDes = min(0.002032 * this->ZoneFloorArea, this->MaxAirVolFlowRate);
2786 : }
2787 : // check that result is not greater than the max flow or less than the min flow.
2788 1114 : MaxAirVolFlowRateDuringReheatDes = min(MaxAirVolFlowRateDuringReheatDes, this->MaxAirVolFlowRate);
2789 1114 : MaxAirVolFlowRateDuringReheatDes = max(MaxAirVolFlowRateDuringReheatDes, (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes));
2790 1114 : if (this->MaxAirVolFlowRate > 0.0) {
2791 1114 : MaxAirVolFractionDuringReheatDes = MaxAirVolFlowRateDuringReheatDes / this->MaxAirVolFlowRate;
2792 : } else {
2793 0 : MaxAirVolFractionDuringReheatDes = 0.0;
2794 : }
2795 1114 : if (this->MaxAirVolFlowRateDuringReheat == Constant::AutoCalculate && this->MaxAirVolFractionDuringReheat == Constant::AutoCalculate) {
2796 : // if both inputs are autosize (the default) report both out and save in the Sys array.
2797 740 : BaseSizer::reportSizerOutput(
2798 : state, this->sysType, this->SysName, "Design Size Maximum Flow Fraction during Reheat []", MaxAirVolFractionDuringReheatDes);
2799 740 : if (this->ZoneFloorArea > 0.0) {
2800 1480 : BaseSizer::reportSizerOutput(state,
2801 : this->sysType,
2802 : this->SysName,
2803 : "Design Size Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
2804 740 : MaxAirVolFlowRateDuringReheatDes / this->ZoneFloorArea);
2805 : }
2806 740 : this->MaxAirVolFlowRateDuringReheat = MaxAirVolFlowRateDuringReheatDes;
2807 740 : this->MaxAirVolFractionDuringReheat = MaxAirVolFractionDuringReheatDes;
2808 374 : } else if (this->MaxAirVolFlowRateDuringReheat == Constant::AutoCalculate && this->MaxAirVolFractionDuringReheat != Constant::AutoCalculate) {
2809 : // if max reheat flow fraction was input, set the max reheat flow design value correspondingly, report both out.
2810 : // Check for optional caution message that user input value is not within 10% of the design value.
2811 351 : MaxAirVolFlowRateDuringReheatDes = this->MaxAirVolFractionDuringReheat * this->MaxAirVolFlowRate;
2812 351 : MaxAirVolFractionDuringReheatUser = this->MaxAirVolFractionDuringReheat;
2813 351 : BaseSizer::reportSizerOutput(state,
2814 : this->sysType,
2815 : this->SysName,
2816 : "Design Size Maximum Flow Fraction during Reheat []",
2817 : MaxAirVolFractionDuringReheatDes,
2818 : "User-Specified Maximum Flow Fraction during Reheat []",
2819 : MaxAirVolFractionDuringReheatUser);
2820 351 : if (this->ZoneFloorArea > 0.0) {
2821 702 : BaseSizer::reportSizerOutput(state,
2822 : this->sysType,
2823 : this->SysName,
2824 : "Design Size Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
2825 351 : MaxAirVolFlowRateDuringReheatDes / this->ZoneFloorArea);
2826 : }
2827 351 : this->MaxAirVolFlowRateDuringReheat = MaxAirVolFlowRateDuringReheatDes;
2828 351 : if (state.dataGlobal->DisplayExtraWarnings) {
2829 0 : if ((std::abs(MaxAirVolFractionDuringReheatDes - MaxAirVolFractionDuringReheatUser) / MaxAirVolFractionDuringReheatUser) >
2830 0 : state.dataSize->AutoVsHardSizingThreshold) {
2831 0 : ShowMessage(state,
2832 0 : format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
2833 0 : ShowContinueError(state,
2834 0 : format("User-Specified Maximum Flow Fraction during Reheat of {:.5R} []", MaxAirVolFractionDuringReheatUser));
2835 0 : ShowContinueError(
2836 0 : state, format("differs from Design Size Maximum Flow Fraction during Reheat of {:.5R} []", MaxAirVolFractionDuringReheatDes));
2837 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2838 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2839 : }
2840 : }
2841 23 : } else if (this->MaxAirVolFlowRateDuringReheat != Constant::AutoCalculate && this->MaxAirVolFractionDuringReheat == Constant::AutoCalculate) {
2842 : // if max reheat flow was input set the design max reheat flow frac to the corresponding value, report both out, save the design value
2843 : // of the flow frac in Sys. Check for optional caution message that user input value is not within 10% of the design value.
2844 23 : if (this->MaxAirVolFlowRate > 0.0) {
2845 23 : MaxAirVolFractionDuringReheatDes = MaxAirVolFlowRateDuringReheatDes / this->MaxAirVolFlowRate;
2846 : } else {
2847 0 : MaxAirVolFractionDuringReheatDes = 0.0;
2848 : }
2849 23 : MaxAirVolFlowRateDuringReheatUser = this->MaxAirVolFlowRateDuringReheat;
2850 23 : BaseSizer::reportSizerOutput(
2851 : state, this->sysType, this->SysName, "Design Size Maximum Flow Fraction during Reheat []", MaxAirVolFractionDuringReheatDes);
2852 23 : if (this->ZoneFloorArea > 0.0) {
2853 46 : BaseSizer::reportSizerOutput(state,
2854 : this->sysType,
2855 : this->SysName,
2856 : "Design Size Maximum Flow per Zone Floor Area during Reheat [ m3/s-m2 ]",
2857 23 : MaxAirVolFlowRateDuringReheatDes / this->ZoneFloorArea,
2858 : "User-Specified Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
2859 46 : MaxAirVolFlowRateDuringReheatUser / this->ZoneFloorArea);
2860 : }
2861 23 : this->MaxAirVolFractionDuringReheat = MaxAirVolFractionDuringReheatDes;
2862 23 : if (state.dataGlobal->DisplayExtraWarnings) {
2863 0 : if ((std::abs(MaxAirVolFlowRateDuringReheatDes - MaxAirVolFlowRateDuringReheatUser) / MaxAirVolFlowRateDuringReheatUser) >
2864 0 : state.dataSize->AutoVsHardSizingThreshold) {
2865 0 : ShowMessage(state,
2866 0 : format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
2867 0 : ShowContinueError(state,
2868 0 : format("User-Specified Maximum Flow per Zone Floor Area during Reheat of {:.5R} [m3/s-m2]",
2869 : MaxAirVolFlowRateDuringReheatUser));
2870 0 : ShowContinueError(state,
2871 0 : format("differs from Design Size Maximum Flow per Zone Floor Area during Reheat of {:.5R} [m3/s-m2]",
2872 : MaxAirVolFlowRateDuringReheatDes));
2873 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2874 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2875 : }
2876 : }
2877 : } else {
2878 : // both fields have user input. Report both out, use the larger of the 2 values. Note that only sd_airterminal( SysNum
2879 : // ).MaxAirVolFlowRateDuringReheat is used subsequently. Check both inputs for optional caution message that user input value is not
2880 : // within 10% of the design value.
2881 0 : MaxAirVolFlowRateDuringReheatUser = this->MaxAirVolFlowRateDuringReheat;
2882 0 : MaxAirVolFractionDuringReheatUser = this->MaxAirVolFractionDuringReheat;
2883 0 : BaseSizer::reportSizerOutput(state,
2884 : this->sysType,
2885 : this->SysName,
2886 : "Design Size Maximum Flow Fraction during Reheat []",
2887 : MaxAirVolFractionDuringReheatDes,
2888 : "User-Specified Maximum Flow Fraction during Reheat []",
2889 : MaxAirVolFractionDuringReheatUser);
2890 0 : if (this->ZoneFloorArea > 0.0) {
2891 0 : BaseSizer::reportSizerOutput(state,
2892 : this->sysType,
2893 : this->SysName,
2894 : "Design Size Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
2895 0 : MaxAirVolFlowRateDuringReheatDes / this->ZoneFloorArea,
2896 : "User-Specified Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
2897 0 : MaxAirVolFlowRateDuringReheatUser / this->ZoneFloorArea);
2898 : }
2899 0 : this->MaxAirVolFlowRateDuringReheat =
2900 0 : max(this->MaxAirVolFlowRateDuringReheat, this->MaxAirVolFractionDuringReheat * this->MaxAirVolFlowRate);
2901 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2902 0 : if ((std::abs(MaxAirVolFractionDuringReheatDes - MaxAirVolFractionDuringReheatUser) / MaxAirVolFractionDuringReheatUser) >
2903 0 : state.dataSize->AutoVsHardSizingThreshold) {
2904 0 : ShowMessage(state,
2905 0 : format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
2906 0 : ShowContinueError(state,
2907 0 : format("User-Specified Maximum Flow Fraction during Reheat of {:.5R} []", MaxAirVolFractionDuringReheatUser));
2908 0 : ShowContinueError(
2909 0 : state, format("differs from Design Size Maximum Flow Fraction during Reheat of {:.5R} []", MaxAirVolFractionDuringReheatDes));
2910 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2911 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2912 : }
2913 : }
2914 0 : if (state.dataGlobal->DisplayExtraWarnings) {
2915 0 : if ((std::abs(MaxAirVolFlowRateDuringReheatDes - MaxAirVolFlowRateDuringReheatUser) / MaxAirVolFlowRateDuringReheatUser) >
2916 0 : state.dataSize->AutoVsHardSizingThreshold) {
2917 0 : ShowMessage(state,
2918 0 : format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".", this->sysType, this->SysName));
2919 0 : ShowContinueError(state,
2920 0 : format("User-Specified Maximum Flow per Zone Floor Area during Reheat of {:.5R} [m3/s-m2]",
2921 : MaxAirVolFlowRateDuringReheatUser));
2922 0 : ShowContinueError(state,
2923 0 : format("differs from Design Size Maximum Flow per Zone Floor Area during Reheat of {:.5R} [m3/s-m2]",
2924 : MaxAirVolFlowRateDuringReheatDes));
2925 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
2926 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
2927 : }
2928 : }
2929 : }
2930 : // check that MaxAirVolFlowRateDuringReheat is greater than the min and less than the max
2931 1114 : this->MaxAirVolFlowRateDuringReheat = min(MaxAirVolFlowRateDuringReheatDes, this->MaxAirVolFlowRate);
2932 1114 : this->MaxAirVolFlowRateDuringReheat = max(MaxAirVolFlowRateDuringReheatDes, (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes));
2933 2488 : } else if (this->DamperHeatingAction == Action::Normal) {
2934 : // for Normal action, max reheat flow is equal to the minimum. Report it.
2935 1069 : if (this->ZoneFloorArea > 0.0) {
2936 2138 : BaseSizer::reportSizerOutput(state,
2937 : this->sysType,
2938 : this->SysName,
2939 : "Design Size Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
2940 1069 : (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes) / this->ZoneFloorArea);
2941 : }
2942 1069 : BaseSizer::reportSizerOutput(
2943 : state, this->sysType, this->SysName, "Design Size Maximum Flow Fraction during Reheat []", this->ZoneMinAirFracDes);
2944 : // zero the ReverseActioWithLimits inputs
2945 1069 : this->MaxAirVolFlowRateDuringReheat = max(this->MaxAirVolFlowRateDuringReheat, 0.0);
2946 1069 : this->MaxAirVolFractionDuringReheat = max(this->MaxAirVolFractionDuringReheat, 0.0);
2947 1419 : } else if (this->DamperHeatingAction == Action::Reverse) {
2948 : // for ReverseAction, max reheat flow is equal to the maximum. Report it.
2949 61 : if (this->ZoneFloorArea > 0.0) {
2950 122 : BaseSizer::reportSizerOutput(state,
2951 : this->sysType,
2952 : this->SysName,
2953 : "Design Size Maximum Flow per Zone Floor Area during Reheat [m3/s-m2]",
2954 61 : this->MaxAirVolFlowRate / this->ZoneFloorArea);
2955 : }
2956 61 : BaseSizer::reportSizerOutput(state, this->sysType, this->SysName, "Design Size Maximum Flow Fraction during Reheat []", 1.0);
2957 : // zero the ReverseActioWithLimits inputs
2958 61 : this->MaxAirVolFlowRateDuringReheat = max(this->MaxAirVolFlowRateDuringReheat, 0.0);
2959 61 : this->MaxAirVolFractionDuringReheat = max(this->MaxAirVolFractionDuringReheat, 0.0);
2960 : }
2961 :
2962 3602 : if (state.dataSize->CurTermUnitSizingNum > 0) {
2963 3602 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult = 1.0;
2964 3602 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult = 1.0;
2965 3602 : if (state.dataSize->ZoneSizingRunDone) {
2966 : // set air flow rate used to size heating coils, ZoneTurndownMinAirFrac defaults to 1 for those TU types that do not use it
2967 3087 : if (this->SysType_Num == SysType::SingleDuctVAVReheatVSFan) {
2968 8 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
2969 8 : max(state.dataSingleDuct->UserInputMaxHeatAirVolFlowRateSS,
2970 8 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatVolFlow,
2971 8 : this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac);
2972 3079 : } else if (this->SysType_Num == SysType::SingleDuctConstVolReheat || this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
2973 658 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
2974 658 : max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatVolFlow,
2975 658 : this->MaxAirVolFlowRate * this->ZoneTurndownMinAirFrac);
2976 : } else {
2977 2421 : if (this->SysType_Num == SysType::SingleDuctVAVReheat && this->DamperHeatingAction == Action::ReverseWithLimits) {
2978 1092 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow = this->MaxAirVolFlowRateDuringReheat;
2979 : } else {
2980 1329 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
2981 1329 : max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatVolFlow,
2982 1329 : this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac);
2983 : }
2984 : }
2985 : } else {
2986 515 : if (this->SysType_Num == SysType::SingleDuctVAVReheatVSFan) {
2987 0 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
2988 0 : max(this->MaxHeatAirVolFlowRate, this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac);
2989 515 : } else if (this->SysType_Num == SysType::SingleDuctConstVolReheat || this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
2990 470 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow = this->MaxAirVolFlowRate;
2991 : } else {
2992 45 : if (this->DamperHeatingAction == Action::Reverse) {
2993 0 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow = this->MaxAirVolFlowRate;
2994 45 : } else if (this->DamperHeatingAction == Action::ReverseWithLimits) {
2995 22 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
2996 22 : max(this->MaxAirVolFlowRateDuringReheat, (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac));
2997 : } else {
2998 23 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
2999 23 : this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
3000 : }
3001 : }
3002 : }
3003 :
3004 3602 : if (TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow > SmallAirVolFlow) {
3005 3602 : if (this->DamperHeatingAction == Action::ReverseWithLimits) {
3006 1114 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
3007 1114 : min(this->MaxAirVolFlowRateDuringReheat, this->MaxAirVolFlowRate) /
3008 1114 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
3009 1114 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult =
3010 1114 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult;
3011 2488 : } else if (this->DamperHeatingAction == Action::Reverse) {
3012 61 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
3013 61 : this->MaxAirVolFlowRate / TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
3014 61 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult =
3015 61 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult;
3016 2427 : } else if (this->DamperHeatingAction == Action::Normal && this->MaxAirVolFlowRateDuringReheat > 0.0) {
3017 0 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
3018 0 : min(this->MaxAirVolFlowRateDuringReheat, (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac)) /
3019 0 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
3020 0 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult = 1.0;
3021 2427 : } else if (this->DamperHeatingAction == Action::Normal && this->MaxAirVolFlowRateDuringReheat == 0.0) {
3022 1069 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
3023 2138 : (this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac) /
3024 1069 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
3025 1069 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult = 1.0;
3026 : } else {
3027 1358 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
3028 1358 : this->MaxAirVolFlowRate / TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
3029 1358 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult =
3030 1358 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult;
3031 : }
3032 3602 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult =
3033 3602 : max(1.0, TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult);
3034 3602 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult =
3035 3602 : max(1.0, TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult);
3036 : } else {
3037 0 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatAirFlowMult = 1.0;
3038 0 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult = 1.0;
3039 : }
3040 3602 : if (this->ReheatComp_Index > 0) {
3041 2521 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilReheatMultiplier(
3042 2521 : state, this->ReheatName, this->ReheatComp, TermUnitSizing(state.dataSize->CurTermUnitSizingNum).ReheatLoadMult);
3043 : }
3044 : }
3045 :
3046 3602 : IsAutoSize = false;
3047 3602 : if (this->MaxReheatWaterVolFlow == AutoSize) {
3048 2125 : IsAutoSize = true;
3049 : }
3050 3602 : if (state.dataSize->CurTermUnitSizingNum > 0) {
3051 3602 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
3052 515 : if (this->MaxReheatWaterVolFlow > 0.0) {
3053 214 : BaseSizer::reportSizerOutput(
3054 : state, this->sysType, this->SysName, "User-Specified Maximum Reheat Water Flow Rate [m3/s]", this->MaxReheatWaterVolFlow);
3055 : }
3056 : } else {
3057 3087 : CheckZoneSizing(state, this->sysType, this->SysName);
3058 3087 : if (Util::SameString(this->ReheatComp, "Coil:Heating:Water")) {
3059 1927 : state.dataSingleDuct->CoilWaterInletNodeSS = GetCoilWaterInletNode(state, "Coil:Heating:Water", this->ReheatName, ErrorsFound);
3060 1927 : state.dataSingleDuct->CoilWaterOutletNodeSS = GetCoilWaterOutletNode(state, "Coil:Heating:Water", this->ReheatName, ErrorsFound);
3061 1927 : if (IsAutoSize) {
3062 1871 : PlantSizingErrorsFound = false;
3063 1871 : PltSizHeatNum = MyPlantSizingIndex(state,
3064 : "Coil:Heating:Water",
3065 : this->ReheatName,
3066 1871 : state.dataSingleDuct->CoilWaterInletNodeSS,
3067 1871 : state.dataSingleDuct->CoilWaterOutletNodeSS,
3068 : PlantSizingErrorsFound);
3069 1871 : if (PlantSizingErrorsFound) {
3070 0 : ShowContinueError(state, format("...Occurs in {}:{}", this->sysType, this->SysName));
3071 0 : ErrorsFound = true;
3072 : }
3073 1871 : if (PltSizHeatNum > 0) {
3074 3742 : state.dataSingleDuct->CoilInTempSS =
3075 1871 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInTempTU;
3076 1871 : DesMassFlow = state.dataEnvrn->StdRhoAir * TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
3077 3742 : state.dataSingleDuct->DesZoneHeatLoadSS =
3078 1871 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatLoad;
3079 3742 : state.dataSingleDuct->ZoneDesTempSS =
3080 1871 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtHeatPeak;
3081 3742 : state.dataSingleDuct->ZoneDesHumRatSS =
3082 1871 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneHumRatAtHeatPeak;
3083 : // the coil load is the zone design heating load plus (or minus!) the reheat load
3084 3742 : state.dataSingleDuct->DesCoilLoadSS =
3085 1871 : state.dataSingleDuct->DesZoneHeatLoadSS + PsyCpAirFnW(state.dataSingleDuct->ZoneDesHumRatSS) * DesMassFlow *
3086 1871 : (state.dataSingleDuct->ZoneDesTempSS - state.dataSingleDuct->CoilInTempSS);
3087 1871 : if (state.dataSingleDuct->DesCoilLoadSS >= SmallLoad) {
3088 :
3089 : rho =
3090 1871 : state.dataPlnt->PlantLoop(this->HWplantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
3091 :
3092 1871 : Cp = state.dataPlnt->PlantLoop(this->HWplantLoc.loopNum)
3093 1871 : .glycol->getSpecificHeat(state, Constant::HWInitConvTemp, RoutineName);
3094 :
3095 1871 : MaxReheatWaterVolFlowDes =
3096 1871 : state.dataSingleDuct->DesCoilLoadSS / (state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp * rho);
3097 : } else {
3098 0 : MaxReheatWaterVolFlowDes = 0.0;
3099 : }
3100 : } else {
3101 0 : ShowSevereError(state, "Autosizing of water flow requires a heating loop Sizing:Plant object");
3102 0 : ShowContinueError(state, format("Occurs in AirTerminal Object={}", this->SysName));
3103 0 : ErrorsFound = true;
3104 : }
3105 1871 : this->MaxReheatWaterVolFlow = MaxReheatWaterVolFlowDes;
3106 1871 : BaseSizer::reportSizerOutput(
3107 : state, this->sysType, this->SysName, "Design Size Maximum Reheat Water Flow Rate [m3/s]", MaxReheatWaterVolFlowDes);
3108 3742 : BaseSizer::reportSizerOutput(state,
3109 : this->sysType,
3110 : this->SysName,
3111 : "Design Size Reheat Coil Sizing Air Volume Flow Rate [m3/s]",
3112 1871 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow);
3113 3742 : BaseSizer::reportSizerOutput(state,
3114 : this->sysType,
3115 : this->SysName,
3116 : "Design Size Reheat Coil Sizing Inlet Air Temperature [C]",
3117 1871 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInTempTU);
3118 3742 : BaseSizer::reportSizerOutput(state,
3119 : this->sysType,
3120 : this->SysName,
3121 : "Design Size Reheat Coil Sizing Inlet Air Humidity Ratio [kgWater/kgDryAir]",
3122 1871 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInHumRatTU);
3123 : } else { // Hard-size with sizing data
3124 56 : if (this->MaxReheatWaterVolFlow > 0.0 && MaxReheatWaterVolFlowDes > 0.0) {
3125 0 : MaxReheatWaterVolFlowUser = this->MaxReheatWaterVolFlow;
3126 0 : BaseSizer::reportSizerOutput(state,
3127 : this->sysType,
3128 : this->SysName,
3129 : "Design Size Maximum Reheat Water Flow Rate [m3/s]",
3130 : MaxReheatWaterVolFlowDes,
3131 : "User-Specified Maximum Reheat Water Flow Rate [m3/s]",
3132 : MaxReheatWaterVolFlowUser);
3133 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3134 0 : if ((std::abs(MaxReheatWaterVolFlowDes - MaxReheatWaterVolFlowUser) / MaxReheatWaterVolFlowUser) >
3135 0 : state.dataSize->AutoVsHardSizingThreshold) {
3136 0 : ShowMessage(state,
3137 0 : format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".",
3138 0 : this->sysType,
3139 0 : this->SysName));
3140 0 : ShowContinueError(
3141 0 : state, format("User-Specified Maximum Reheat Water Flow Rate of {:.5R} [m3/s]", MaxReheatWaterVolFlowUser));
3142 0 : ShowContinueError(
3143 : state,
3144 0 : format("differs from Design Size Maximum Reheat Water Flow Rate of {:.5R} [m3/s]", MaxReheatWaterVolFlowDes));
3145 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3146 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3147 : }
3148 : }
3149 : }
3150 : }
3151 : }
3152 : }
3153 : } else {
3154 0 : this->MaxReheatWaterVolFlow = 0.0;
3155 : }
3156 :
3157 3602 : IsAutoSize = false;
3158 3602 : if (this->MaxReheatSteamVolFlow == AutoSize) {
3159 13 : IsAutoSize = true;
3160 : }
3161 3602 : if (state.dataSize->CurTermUnitSizingNum > 0) {
3162 3602 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) {
3163 515 : if (this->MaxReheatSteamVolFlow > 0.0) {
3164 0 : BaseSizer::reportSizerOutput(
3165 : state, this->sysType, this->SysName, "User-Specified Maximum Reheat Steam Flow Rate [m3/s]", this->MaxReheatSteamVolFlow);
3166 : }
3167 : } else {
3168 3087 : CheckZoneSizing(state, this->sysType, this->SysName);
3169 3087 : if (Util::SameString(this->ReheatComp, "Coil:Heating:Steam")) {
3170 26 : state.dataSingleDuct->CoilSteamInletNodeSS = GetCoilSteamInletNode(state, "Coil:Heating:Steam", this->ReheatName, ErrorsFound);
3171 13 : state.dataSingleDuct->CoilSteamOutletNodeSS = GetCoilSteamOutletNode(state, "Coil:Heating:Steam", this->ReheatName, ErrorsFound);
3172 13 : if (IsAutoSize) {
3173 13 : PlantSizingErrorsFound = false;
3174 13 : PltSizHeatNum = MyPlantSizingIndex(state,
3175 : "Coil:Heating:Steam",
3176 : this->ReheatName,
3177 13 : state.dataSingleDuct->CoilSteamInletNodeSS,
3178 13 : state.dataSingleDuct->CoilSteamOutletNodeSS,
3179 : PlantSizingErrorsFound);
3180 13 : if (PlantSizingErrorsFound) {
3181 0 : ShowContinueError(state, format("...Occurs in {}:{}", this->sysType, this->SysName));
3182 0 : ErrorsFound = true;
3183 : }
3184 13 : if (PltSizHeatNum > 0) {
3185 26 : state.dataSingleDuct->CoilInTempSS =
3186 13 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInTempTU;
3187 13 : DesMassFlow = state.dataEnvrn->StdRhoAir * TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow;
3188 26 : state.dataSingleDuct->DesZoneHeatLoadSS =
3189 13 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatLoad;
3190 26 : state.dataSingleDuct->ZoneDesTempSS =
3191 13 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtHeatPeak;
3192 26 : state.dataSingleDuct->ZoneDesHumRatSS =
3193 13 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneHumRatAtHeatPeak;
3194 : // the coil load is the zone design heating load plus (or minus!) the reheat load
3195 26 : state.dataSingleDuct->DesCoilLoadSS =
3196 13 : state.dataSingleDuct->DesZoneHeatLoadSS + PsyCpAirFnW(state.dataSingleDuct->ZoneDesHumRatSS) * DesMassFlow *
3197 13 : (state.dataSingleDuct->ZoneDesTempSS - state.dataSingleDuct->CoilInTempSS);
3198 13 : if (state.dataSingleDuct->DesCoilLoadSS >= SmallLoad) {
3199 13 : TempSteamIn = 100.00;
3200 13 : auto *steam = Fluid::GetSteam(state);
3201 13 : EnthSteamInDry = steam->getSatEnthalpy(state, TempSteamIn, 1.0, RoutineNameFull);
3202 13 : EnthSteamOutWet = steam->getSatEnthalpy(state, TempSteamIn, 0.0, RoutineNameFull);
3203 13 : LatentHeatSteam = EnthSteamInDry - EnthSteamOutWet;
3204 13 : SteamDensity = steam->getSatDensity(state, TempSteamIn, 1.0, RoutineNameFull);
3205 :
3206 13 : Cp = Fluid::GetWater(state)->getSpecificHeat(state, state.dataSize->PlantSizData(PltSizHeatNum).ExitTemp, RoutineName);
3207 13 : MaxReheatSteamVolFlowDes = state.dataSingleDuct->DesCoilLoadSS /
3208 13 : (SteamDensity * (LatentHeatSteam + state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp));
3209 : } else {
3210 0 : MaxReheatSteamVolFlowDes = 0.0;
3211 : }
3212 : } else {
3213 0 : ShowSevereError(state, "Autosizing of Steam flow requires a heating loop Sizing:Plant object");
3214 0 : ShowContinueError(state, format("Occurs in AirTerminal:SingleDuct:ConstantVolume:Reheat Object={}", this->SysName));
3215 0 : ErrorsFound = true;
3216 : }
3217 13 : this->MaxReheatSteamVolFlow = MaxReheatSteamVolFlowDes;
3218 13 : BaseSizer::reportSizerOutput(
3219 : state, this->sysType, this->SysName, "Design Size Maximum Reheat Steam Flow Rate [m3/s]", MaxReheatSteamVolFlowDes);
3220 : } else {
3221 0 : if (this->MaxReheatSteamVolFlow > 0.0 && MaxReheatSteamVolFlowDes > 0.0) {
3222 0 : MaxReheatSteamVolFlowUser = this->MaxReheatSteamVolFlow;
3223 0 : BaseSizer::reportSizerOutput(state,
3224 : this->sysType,
3225 : this->SysName,
3226 : "Design Size Maximum Reheat Steam Flow Rate [m3/s]",
3227 : MaxReheatSteamVolFlowDes,
3228 : "User-Specified Maximum Reheat Steam Flow Rate [m3/s]",
3229 : MaxReheatSteamVolFlowUser);
3230 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3231 0 : if ((std::abs(MaxReheatSteamVolFlowDes - MaxReheatSteamVolFlowUser) / MaxReheatSteamVolFlowUser) >
3232 0 : state.dataSize->AutoVsHardSizingThreshold) {
3233 0 : ShowMessage(state,
3234 0 : format("SizeHVACSingleDuct: Potential issue with equipment sizing for {} = \"{}\".",
3235 0 : this->sysType,
3236 0 : this->SysName));
3237 0 : ShowContinueError(
3238 0 : state, format("User-Specified Maximum Reheat Steam Flow Rate of {:.5R} [m3/s]", MaxReheatSteamVolFlowUser));
3239 0 : ShowContinueError(
3240 : state,
3241 0 : format("differs from Design Size Maximum Reheat Steam Flow Rate of {:.5R} [m3/s]", MaxReheatSteamVolFlowDes));
3242 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3243 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3244 : }
3245 : }
3246 : }
3247 : }
3248 : }
3249 : }
3250 : } else {
3251 0 : this->MaxReheatSteamVolFlow = 0.0;
3252 : }
3253 :
3254 3602 : if (state.dataSize->CurTermUnitSizingNum > 0) {
3255 3602 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).MinPriFlowFrac = this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
3256 3602 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).MaxHWVolFlow = this->MaxReheatWaterVolFlow;
3257 3602 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).MaxSTVolFlow = this->MaxReheatSteamVolFlow;
3258 3602 : TermUnitSizing(state.dataSize->CurTermUnitSizingNum).DesHeatingLoad = state.dataSingleDuct->DesCoilLoadSS; // Coil Summary report
3259 3602 : if (this->ReheatComp_Num == HeatingCoilType::SimpleHeating) {
3260 2141 : if (this->DamperHeatingAction == Action::Normal) {
3261 880 : SetCoilDesFlow(state, this->ReheatComp, this->ReheatName, this->ZoneMinAirFracDes * this->MaxAirVolFlowRate, ErrorsFound);
3262 : } else {
3263 1261 : SetCoilDesFlow(
3264 1261 : state, this->ReheatComp, this->ReheatName, TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow, ErrorsFound);
3265 : }
3266 : }
3267 : }
3268 :
3269 3602 : if (this->MaxAirVolFlowRateDuringReheat > 0.0) {
3270 : // check for inconsistent dual max input
3271 1114 : if (this->MaxAirVolFlowRateDuringReheat < (this->ZoneMinAirFracDes * this->MaxAirVolFlowRate)) {
3272 : // Only warn when really out of bounds
3273 0 : if ((this->ZoneMinAirFracDes * this->MaxAirVolFlowRate) - this->MaxAirVolFlowRateDuringReheat > 1.e-8) {
3274 0 : ShowWarningError(state,
3275 : "SingleDuctSystem:SizeSys: Air Terminal Unit flow limits are not consistent, minimum flow limit is larger than "
3276 : "reheat maximum");
3277 0 : ShowContinueError(state, format("Air Terminal Unit name = {}", this->SysName));
3278 0 : ShowContinueError(state,
3279 0 : format("Maximum terminal flow during reheat = {:.6R} [m3/s] or flow fraction = {:.4R}",
3280 0 : this->MaxAirVolFlowRateDuringReheat,
3281 0 : (this->MaxAirVolFlowRateDuringReheat / this->MaxAirVolFlowRate)));
3282 0 : ShowContinueError(state,
3283 0 : format("Minimum terminal flow = {:.6R} [m3/s] or flow fraction = {:.4R}",
3284 0 : (this->ZoneMinAirFracDes * this->MaxAirVolFlowRate),
3285 0 : this->ZoneMinAirFracDes));
3286 0 : ShowContinueError(state, "The reheat maximum flow limit will be replaced by the minimum limit, and the simulation continues");
3287 : }
3288 0 : this->MaxAirVolFlowRateDuringReheat = (this->ZoneMinAirFracDes * this->MaxAirVolFlowRate);
3289 : }
3290 : }
3291 :
3292 3602 : if (ErrorsFound) {
3293 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
3294 : }
3295 3602 : }
3296 :
3297 : // End Initialization Section of the Module
3298 : //******************************************************************************
3299 :
3300 : // Begin Algorithm Section of the Module
3301 : //******************************************************************************
3302 :
3303 27022691 : void SingleDuctAirTerminal::SimVAV(EnergyPlusData &state, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum)
3304 : {
3305 :
3306 : // SUBROUTINE INFORMATION:
3307 : // AUTHOR Richard J. Liesen
3308 : // DATE WRITTEN January 2000
3309 : // MODIFIED Fred Buhl: added reverse action damper heating action: August 2001
3310 : // KHL/TH 7/2010: revise to support dual max
3311 : // FB/KHL/TH 9/2010: added maximum supply air temperature leaving reheat coil
3312 : // TH 3/2012: added supply air flow adjustment based on zone maximum outdoor
3313 : // air fraction - a TRACE feature
3314 : // Brent Griffith, 5/2012, general cleanup, fix negatives CR 8767, fix phantom coil flows CR 8854
3315 :
3316 : // PURPOSE OF THIS SUBROUTINE:
3317 : // This subroutine simulates the simple single duct volume VAV.
3318 :
3319 : // METHODOLOGY EMPLOYED:
3320 : // There is method to this madness.
3321 :
3322 : // Using/Aliasing
3323 : using namespace DataZoneEnergyDemands;
3324 : // unused USE DataHeatBalFanSys, ONLY: Mat
3325 : using HeatingCoils::SimulateHeatingCoilComponents;
3326 : using HVAC::SmallLoad;
3327 : using PlantUtilities::SetActuatedBranchFlowRate;
3328 : using SteamCoils::SimulateSteamCoilComponents;
3329 : using WaterCoils::SimulateWaterCoilComponents;
3330 :
3331 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3332 : Real64 MassFlow; // [kg/sec] Total Mass Flow Rate from Hot & Cold Inlets
3333 : Real64 QTotLoad; // [Watts] Remaining load required for this zone
3334 : Real64 QZnReq; // [Watts] Load calculated for heating coil
3335 : Real64 QToHeatSetPt; // [W] remaining load to heating setpoint
3336 : Real64 CpAirAvg;
3337 : Real64 DeltaTemp;
3338 : int SysOutletNode; // The node number of the terminal unit outlet node
3339 : int SysInletNode; // the node number of the terminal unit inlet node
3340 : Real64 MaxFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
3341 : Real64 MinFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
3342 : Real64 QActualHeating; // the heating load seen by the reheat coil
3343 : Real64 QHeatingDelivered; // the actual output from heating coil
3344 : Real64 LeakLoadMult; // load multiplier to adjust for downstream leaks
3345 : Real64 MinFlowFrac; // minimum flow fraction (and minimum damper position)
3346 : Real64 MassFlowBasedOnOA; // supply air mass flow rate based on zone OA requirements
3347 : Real64 AirLoopOAFrac; // fraction of outside air entering air loop
3348 : Real64 DummyMdot; // temporary mass flow rate argument
3349 :
3350 : // Note to the perplexed
3351 : // The SINGLE DUCT:VAV:REHEAT terminal unit originally contained 2 components: a damper
3352 : // and a reheat coil. The damper has become a virtual component - it consists only of
3353 : // an air inlet node and an air outlet node. The damper is upstream of the heating coil.
3354 : // sd_airterminal(SysNum)%InletNodeNum is the inlet node to the terminal unit and the damper
3355 : // sd_airterminal(SysNum)%OutletNodeNum is the outlet node of the damper and the inlet node of the heating coil
3356 : // sd_airterminal(SysNum)%ReheatAirOutletNode is the outlet node of the terminal unit and the heating coil
3357 :
3358 : // The calculated load from the Heat Balance
3359 27022691 : LeakLoadMult = state.dataDefineEquipment->AirDistUnit(this->ADUNum).LeakLoadMult;
3360 27022691 : QTotLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired * LeakLoadMult;
3361 27022691 : QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP * LeakLoadMult;
3362 27022691 : SysOutletNode = this->ReheatAirOutletNode;
3363 27022691 : SysInletNode = this->InletNodeNum;
3364 27022691 : CpAirAvg = PsyCpAirFnW(0.5 * (state.dataLoopNodes->Node(ZoneNodeNum).HumRat + this->sd_airterminalInlet.AirHumRat));
3365 27022691 : MinFlowFrac = this->ZoneMinAirFrac;
3366 27022691 : MassFlowBasedOnOA = 0.0;
3367 27022691 : state.dataSingleDuct->ZoneTempSDAT = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
3368 27022691 : state.dataSingleDuct->MinMassAirFlowSDAT = MinFlowFrac * state.dataEnvrn->StdRhoAir * this->MaxAirVolFlowRate;
3369 :
3370 : // Then depending on if the Load is for heating or cooling it is handled differently. First
3371 : // the massflow rate for cooling is determined to meet the entire load. Then
3372 : // if the massflow is below the minimum or greater than the Max it is set to either the Min
3373 : // or the Max as specified for the VAV model.
3374 9472132 : if ((QTotLoad < 0.0) && (this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0) &&
3375 36494823 : (state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleHeat) && (this->availSched->getCurrentVal() > 0.0)) {
3376 : // Calculate the flow required for cooling
3377 :
3378 9061063 : DeltaTemp = CpAirAvg * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSDAT);
3379 :
3380 : // Need to check DeltaTemp and ensure that it is not zero
3381 9061063 : if (DeltaTemp != 0.0) {
3382 9060648 : MassFlow = QTotLoad / DeltaTemp;
3383 : } else {
3384 415 : MassFlow = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
3385 : }
3386 :
3387 : // Apply the zone maximum outdoor air fraction FOR VAV boxes - a TRACE feature
3388 9061063 : if (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor > 1.0) {
3389 0 : MassFlow *= state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor;
3390 : }
3391 :
3392 : // calculate supply air flow rate based on user specified OA requirement
3393 9061063 : this->CalcOAMassFlow(state, MassFlowBasedOnOA, AirLoopOAFrac);
3394 9061063 : MassFlow = max(MassFlow, MassFlowBasedOnOA);
3395 :
3396 : // used for normal acting damper
3397 9061063 : state.dataSingleDuct->MinMassAirFlowSDAT = max(state.dataSingleDuct->MinMassAirFlowSDAT, MassFlowBasedOnOA);
3398 9061063 : state.dataSingleDuct->MinMassAirFlowSDAT = max(state.dataSingleDuct->MinMassAirFlowSDAT, this->sd_airterminalInlet.AirMassFlowRateMinAvail);
3399 9061063 : state.dataSingleDuct->MinMassAirFlowSDAT = min(state.dataSingleDuct->MinMassAirFlowSDAT, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
3400 :
3401 : // limit the OA based supply air flow rate based on optional user input
3402 : // Check to see if the flow is < the Min or > the Max air Fraction to the zone; then set to min or max
3403 9061063 : MassFlow = max(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMinAvail);
3404 9061063 : MassFlow = min(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
3405 :
3406 9061063 : if (state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated && state.afn->VAVTerminalRatio > 0.0) {
3407 0 : MassFlow *= state.afn->VAVTerminalRatio;
3408 0 : if (MassFlow > state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate) {
3409 0 : MassFlow = state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate;
3410 : }
3411 : }
3412 :
3413 14430118 : } else if ((this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0) &&
3414 32408747 : (QTotLoad >= 0.0 || state.dataHeatBalFanSys->TempControlType(ZoneNum) == HVAC::SetptType::SingleHeat) &&
3415 14430118 : (this->availSched->getCurrentVal() > 0.0)) {
3416 : // IF (sd_airterminal(SysNum)%DamperHeatingAction .EQ. ReverseAction .AND. this->sd_airterminalInlet%AirMassFlowRateMinAvail <=
3417 : // SmallMassFlow) THEN
3418 : // special case for heating: reverse action and damper allowed to close - set the minimum flow rate to a small but nonzero value
3419 : // MassFlow = 0.01d0*this->sd_airterminalInlet%AirMassFlowRateMaxAvail
3420 : // ELSE
3421 : // usual case for heating: set the air mass flow rate to the minimum
3422 14430118 : MassFlow = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
3423 : // END IF
3424 :
3425 : // Apply the zone maximum outdoor air fraction for VAV boxes - a TRACE feature
3426 14430118 : if (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor > 1.0) {
3427 0 : MassFlow *= state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor;
3428 : }
3429 :
3430 : // calculate supply air flow rate based on user specified OA requirement
3431 14430118 : this->CalcOAMassFlow(state, MassFlowBasedOnOA, AirLoopOAFrac);
3432 14430118 : MassFlow = max(MassFlow, MassFlowBasedOnOA);
3433 :
3434 : // Check to see if the flow is < the Min or > the Max air Fraction to the zone; then set to min or max
3435 14430118 : if (MassFlow <= this->sd_airterminalInlet.AirMassFlowRateMinAvail) {
3436 13820544 : MassFlow = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
3437 609574 : } else if (MassFlow >= this->sd_airterminalInlet.AirMassFlowRateMaxAvail) {
3438 497041 : MassFlow = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
3439 : }
3440 :
3441 : // the AirflowNetwork model overrids the mass flow rate value
3442 14430118 : if (state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated && state.afn->VAVTerminalRatio > 0.0) {
3443 0 : MassFlow *= state.afn->VAVTerminalRatio;
3444 0 : if (MassFlow > state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate) {
3445 0 : MassFlow = state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate;
3446 : }
3447 : }
3448 :
3449 : } else {
3450 : // System is Off set massflow to 0.0
3451 3531510 : MassFlow = 0.0;
3452 3531510 : AirLoopOAFrac = 0.0;
3453 : }
3454 :
3455 : // look for bang-bang condition: flow rate oscillating between 2 values during the air loop / zone
3456 : // equipment iteration. If detected, set flow rate to previous value.
3457 33747468 : if (((std::abs(MassFlow - this->MassFlow2) < this->MassFlowDiff) || (std::abs(MassFlow - this->MassFlow3) < this->MassFlowDiff)) &&
3458 6724777 : (std::abs(MassFlow - this->MassFlow1) >= this->MassFlowDiff)) {
3459 18771 : if (MassFlow > 0.0) {
3460 18766 : MassFlow = this->MassFlow1;
3461 : }
3462 : }
3463 :
3464 : // Move data to the damper outlet node
3465 27022691 : this->sd_airterminalOutlet.AirTemp = this->sd_airterminalInlet.AirTemp;
3466 27022691 : this->sd_airterminalOutlet.AirHumRat = this->sd_airterminalInlet.AirHumRat;
3467 27022691 : this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
3468 27022691 : this->sd_airterminalOutlet.AirMassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
3469 27022691 : this->sd_airterminalOutlet.AirMassFlowRateMinAvail = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
3470 27022691 : this->sd_airterminalOutlet.AirEnthalpy = this->sd_airterminalInlet.AirEnthalpy;
3471 :
3472 : // ! Calculate the Damper Position when there is a Max air flow specified.
3473 : // If (MassFlow == 0.0D0) THEN
3474 : // sd_airterminal(SysNum)%DamperPosition = 0.0D0
3475 : // ELSE IF (this->sd_airterminalInlet%AirMassFlowRateMaxAvail > this->sd_airterminalInlet%AirMassFlowRateMinAvail) THEN
3476 : // sd_airterminal(SysNum)%DamperPosition = ((MassFlow-this->sd_airterminalInlet%AirMassFlowRateMinAvail) / &
3477 : // (this->sd_airterminalInlet%AirMassFlowRateMaxAvail-this->sd_airterminalInlet%AirMassFlowRateMinAvail)) *
3478 : // &
3479 : // (1.0d0-MinFlowFrac) + MinFlowFrac
3480 : // ELSE
3481 : // sd_airterminal(SysNum)%DamperPosition = 1.0D0
3482 : // END IF
3483 :
3484 27022691 : if (MassFlow == 0.0) {
3485 3532227 : this->DamperPosition = 0.0;
3486 3532227 : this->ZoneMinAirFracReport = 0.0;
3487 23490464 : } else if ((MassFlow > 0.0) && (MassFlow < this->AirMassFlowRateMax)) {
3488 16694565 : this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
3489 16694565 : this->ZoneMinAirFracReport = this->ZoneMinAirFrac;
3490 6795899 : } else if (MassFlow == this->AirMassFlowRateMax) {
3491 6795899 : this->DamperPosition = 1.0;
3492 6795899 : this->ZoneMinAirFracReport = this->ZoneMinAirFrac;
3493 : }
3494 :
3495 : // Need to make sure that the damper outlets are passed to the coil inlet
3496 27022691 : this->UpdateSys(state);
3497 :
3498 : // At the current air mass flow rate, calculate heating coil load
3499 27022691 : QActualHeating = QToHeatSetPt - MassFlow * CpAirAvg * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSDAT); // reheat needed
3500 :
3501 : // do the reheat calculation if there's some air nass flow (or the damper action is "reverse action"), the flow is <= minimum ,
3502 : // there's a heating requirement, and there's a thermostat with a heating setpoint
3503 : // Reverse damper option is working only for water coils for now.
3504 27022691 : if ((MassFlow > SmallMassFlow) && (QActualHeating > 0.0) && (state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleCool)) {
3505 : // At this point we know that there is a heating requirement: i.e., the heating coil needs to
3506 : // be activated (there's a zone heating load or there's a reheat requirement). There are 3 possible
3507 : // situations: 1) the coil load can be met by variable temperature air (below the max heat temp) at
3508 : // the minimum air mass flow rate; 2) the coil load can be met by variable air flow rate with the air
3509 : // temperature fixed at the max heat temp; 3) the load cannot be met (we will run at max air temp and
3510 : // max air flow rate). We check for condition 2 by assuming the air temperatute is at the max heat temp
3511 : // and solving for the air mass flow rate that will meet the load. If the flow rate is between the min and
3512 : // max we are in condition 2.
3513 :
3514 12072410 : state.dataSingleDuct->QZoneMax2SDAT = QToHeatSetPt;
3515 :
3516 : // fill dual-max reheat flow limit, if any
3517 12072410 : if (this->DamperHeatingAction == Action::Reverse) {
3518 85724 : state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT = this->AirMassFlowRateMax;
3519 11986686 : } else if (this->DamperHeatingAction == Action::ReverseWithLimits) {
3520 5643659 : state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT = this->AirMassFlowDuringReheatMax;
3521 6343027 : } else if (this->DamperHeatingAction == Action::Normal) {
3522 5468141 : state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT = this->ZoneMinAirFrac * this->AirMassFlowRateMax;
3523 : } else {
3524 : // used for AIRTERMINAL_SINGLEDUCT_VAV_NOREHEAT or SingleDuctVAVNoReheat
3525 874886 : state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT = this->AirMassFlowRateMax;
3526 : }
3527 :
3528 : // determine flow based on leaving reheat temperature limit
3529 12072410 : if (this->MaxReheatTempSetByUser) {
3530 :
3531 2593700 : state.dataSingleDuct->MaxHeatTempSDAT = this->MaxReheatTemp;
3532 2593700 : if (QToHeatSetPt > SmallLoad) { // zone has a positive load to heating setpoint
3533 2165628 : state.dataSingleDuct->MassFlowReqToLimitLeavingTempSDAT =
3534 2165628 : QToHeatSetPt / (CpAirAvg * (state.dataSingleDuct->MaxHeatTempSDAT - state.dataSingleDuct->ZoneTempSDAT));
3535 : } else {
3536 428072 : state.dataSingleDuct->MassFlowReqToLimitLeavingTempSDAT = 0.0;
3537 : }
3538 : }
3539 :
3540 : // (re)apply limits to find air mass flow
3541 12072410 : MassFlow = max(MassFlow, state.dataSingleDuct->MassFlowReqToLimitLeavingTempSDAT);
3542 12072410 : MassFlow = min(MassFlow, state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT);
3543 12072410 : MassFlow = max(MassFlow, MassFlowBasedOnOA);
3544 12072410 : MassFlow = min(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
3545 12072410 : MassFlow = max(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMinAvail);
3546 :
3547 12072410 : if (state.afn->distribution_simulated && state.afn->AirflowNetworkFanActivated && state.afn->VAVTerminalRatio > 0.0) {
3548 0 : MassFlow *= state.afn->VAVTerminalRatio;
3549 0 : if (MassFlow > state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate) {
3550 0 : MassFlow = state.dataLoopNodes->Node(this->InletNodeNum).MassFlowRate;
3551 : }
3552 : }
3553 :
3554 : // now make any corrections to heating coil loads
3555 12072410 : if (this->MaxReheatTempSetByUser) {
3556 5187400 : state.dataSingleDuct->QZoneMaxRHTempLimitSDAT =
3557 2593700 : MassFlow * CpAirAvg * (state.dataSingleDuct->MaxHeatTempSDAT - state.dataSingleDuct->ZoneTempSDAT);
3558 2593700 : state.dataSingleDuct->QZoneMax2SDAT = min(state.dataSingleDuct->QZoneMaxRHTempLimitSDAT, QToHeatSetPt);
3559 : }
3560 :
3561 12072410 : this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
3562 :
3563 12072410 : this->UpdateSys(state);
3564 :
3565 : // Now do the heating coil calculation for each heating coil type
3566 12072410 : switch (this->ReheatComp_Num) { // Reverse damper option is working only for water coils for now.
3567 : // hot water heating coil
3568 9673211 : case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
3569 : // Determine the load required to pass to the Component controller
3570 : // Although this equation looks strange (using temp instead of deltaT), it is corrected later in ControlCompOutput
3571 : // and is working as-is, temperature setpoints are maintained as expected.
3572 9673211 : QZnReq = state.dataSingleDuct->QZoneMax2SDAT + MassFlow * CpAirAvg * state.dataSingleDuct->ZoneTempSDAT;
3573 :
3574 : // Initialize hot water flow rate to zero.
3575 9673211 : DummyMdot = 0.0;
3576 9673211 : SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
3577 : // On the first HVAC iteration the system values are given to the controller, but after that
3578 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
3579 9673211 : if (FirstHVACIteration) {
3580 3883970 : MaxFlowWater = this->MaxReheatWaterFlow;
3581 3883970 : MinFlowWater = this->MinReheatWaterFlow;
3582 : } else {
3583 5789241 : int WaterControlNode = this->ReheatControlNode;
3584 5789241 : MaxFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMaxAvail;
3585 5789241 : MinFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMinAvail;
3586 : }
3587 :
3588 : // Simulate the reheat coil at constant air flow. Control by varying the
3589 : // hot water flow rate.
3590 : // FB use QActualHeating, change ControlCompOutput to use new
3591 29019633 : ControlCompOutput(state,
3592 9673211 : this->ReheatName,
3593 9673211 : this->ReheatComp,
3594 9673211 : this->ReheatComp_Index,
3595 : FirstHVACIteration,
3596 : QZnReq,
3597 : this->ReheatControlNode,
3598 : MaxFlowWater,
3599 : MinFlowWater,
3600 : this->ControllerOffset,
3601 9673211 : this->ControlCompTypeNum,
3602 9673211 : this->CompErrIndex,
3603 : _,
3604 : SysOutletNode,
3605 : MassFlow,
3606 : _,
3607 : _,
3608 9673211 : this->HWplantLoc);
3609 :
3610 : // If reverse action damper and the hot water flow is at maximum, simulate the
3611 : // hot water coil with fixed (maximum) hot water flow but allow the air flow to
3612 : // vary up to the maximum (air damper opens to try to meet zone load)
3613 9673211 : if (this->DamperHeatingAction == Action::Reverse || this->DamperHeatingAction == Action::ReverseWithLimits) {
3614 4826685 : if (state.dataLoopNodes->Node(this->ReheatControlNode).MassFlowRate == MaxFlowWater) {
3615 : // fill limits for air flow for controller
3616 1581245 : state.dataSingleDuct->MinAirMassFlowRevActSVAV = this->AirMassFlowRateMax * this->ZoneMinAirFrac;
3617 1581245 : state.dataSingleDuct->MinAirMassFlowRevActSVAV =
3618 1581245 : min(state.dataSingleDuct->MinAirMassFlowRevActSVAV, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
3619 1581245 : state.dataSingleDuct->MinAirMassFlowRevActSVAV =
3620 1581245 : max(state.dataSingleDuct->MinAirMassFlowRevActSVAV, this->sd_airterminalInlet.AirMassFlowRateMinAvail);
3621 :
3622 1581245 : state.dataSingleDuct->MaxAirMassFlowRevActSVAV = this->AirMassFlowRateMax;
3623 1581245 : state.dataSingleDuct->MaxAirMassFlowRevActSVAV =
3624 1581245 : min(state.dataSingleDuct->MaxAirMassFlowRevActSVAV, state.dataSingleDuct->MaxDeviceAirMassFlowReheatSDAT);
3625 1581245 : state.dataSingleDuct->MaxAirMassFlowRevActSVAV =
3626 1581245 : max(state.dataSingleDuct->MaxAirMassFlowRevActSVAV, state.dataSingleDuct->MinAirMassFlowRevActSVAV);
3627 1581245 : state.dataSingleDuct->MaxAirMassFlowRevActSVAV =
3628 1581245 : min(state.dataSingleDuct->MaxAirMassFlowRevActSVAV, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
3629 :
3630 1581245 : state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRateMaxAvail =
3631 1581245 : state.dataSingleDuct->MaxAirMassFlowRevActSVAV; // suspect, check how/if used in ControlCompOutput
3632 3162490 : ControlCompOutput(state,
3633 1581245 : this->ReheatName,
3634 1581245 : this->ReheatComp,
3635 1581245 : this->ReheatComp_Index,
3636 : FirstHVACIteration,
3637 1581245 : state.dataSingleDuct->QZoneMax2SDAT,
3638 : this->OutletNodeNum,
3639 1581245 : state.dataSingleDuct->MaxAirMassFlowRevActSVAV,
3640 1581245 : state.dataSingleDuct->MinAirMassFlowRevActSVAV,
3641 : this->ControllerOffset,
3642 1581245 : this->ControlCompTypeNum,
3643 1581245 : this->CompErrIndex,
3644 : ZoneNodeNum,
3645 : SysOutletNode);
3646 : // air flow controller, not on plant, don't pass plant topology info
3647 : // reset terminal unit inlet air mass flow to new value.
3648 1581245 : state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
3649 1581245 : MassFlow = state.dataLoopNodes->Node(SysOutletNode).MassFlowRate;
3650 :
3651 : // ! look for bang-bang condition: flow rate oscillating between 2 values during the air loop / zone
3652 : // ! equipment iteration. If detected, set flow rate to previous value and recalc HW flow.
3653 1581245 : if (((std::abs(MassFlow - this->MassFlow2) < this->MassFlowDiff) ||
3654 2004045 : (std::abs(MassFlow - this->MassFlow3) < this->MassFlowDiff)) &&
3655 422800 : (std::abs(MassFlow - this->MassFlow1) >= this->MassFlowDiff)) {
3656 2211 : if (MassFlow > 0.0) {
3657 2211 : MassFlow = this->MassFlow1;
3658 : }
3659 2211 : this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
3660 2211 : this->UpdateSys(state);
3661 :
3662 : // Although this equation looks strange (using temp instead of deltaT), it is corrected later in ControlCompOutput
3663 : // and is working as-is, temperature setpoints are maintained as expected.
3664 2211 : QZnReq = state.dataSingleDuct->QZoneMax2SDAT + MassFlow * CpAirAvg * state.dataSingleDuct->ZoneTempSDAT;
3665 6633 : ControlCompOutput(state,
3666 2211 : this->ReheatName,
3667 2211 : this->ReheatComp,
3668 2211 : this->ReheatComp_Index,
3669 : FirstHVACIteration,
3670 : QZnReq,
3671 : this->ReheatControlNode,
3672 : MaxFlowWater,
3673 : MinFlowWater,
3674 : this->ControllerOffset,
3675 2211 : this->ControlCompTypeNum,
3676 2211 : this->CompErrIndex,
3677 : _,
3678 : SysOutletNode,
3679 : MassFlow,
3680 : _,
3681 : _,
3682 2211 : this->HWplantLoc);
3683 : }
3684 :
3685 1581245 : this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
3686 : // reset OA report variable
3687 1581245 : this->UpdateSys(state);
3688 : } // IF (Node(sd_airterminal(SysNum)%ReheatControlNode)%MassFlowRate .EQ. MaxFlowWater) THEN
3689 : } // IF (sd_airterminal(SysNum)%DamperHeatingAction .EQ. ReverseAction) THEN
3690 :
3691 : // Recalculate the Damper Position.
3692 9673211 : if (MassFlow == 0.0) {
3693 0 : this->DamperPosition = 0.0;
3694 0 : this->ZoneMinAirFracReport = 0.0;
3695 9673211 : } else if ((MassFlow > 0.0) && (MassFlow < this->AirMassFlowRateMax)) {
3696 5869847 : this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
3697 5869847 : this->ZoneMinAirFracReport = this->ZoneMinAirFrac;
3698 3803364 : } else if (MassFlow == this->AirMassFlowRateMax) {
3699 3803364 : this->DamperPosition = 1.0;
3700 3803364 : this->ZoneMinAirFracReport = this->ZoneMinAirFrac;
3701 : }
3702 9673211 : } break;
3703 17699 : case HeatingCoilType::SteamAirHeating: { // ! COIL:STEAM:AIRHEATING
3704 : // Determine the load required to pass to the Component controller
3705 17699 : QZnReq =
3706 17699 : state.dataSingleDuct->QZoneMax2SDAT - MassFlow * CpAirAvg * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSDAT);
3707 :
3708 : // Simulate reheat coil for the VAV system
3709 17699 : SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, QZnReq);
3710 17699 : } break;
3711 1412559 : case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
3712 : // Determine the load required to pass to the Component controller
3713 1412559 : QZnReq =
3714 1412559 : state.dataSingleDuct->QZoneMax2SDAT - MassFlow * CpAirAvg * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSDAT);
3715 :
3716 : // Simulate reheat coil for the VAV system
3717 1412559 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index);
3718 1412559 : } break;
3719 94055 : case HeatingCoilType::Gas: { // COIL:GAS:HEATING
3720 : // Determine the load required to pass to the Component controller
3721 94055 : QZnReq =
3722 94055 : state.dataSingleDuct->QZoneMax2SDAT - MassFlow * CpAirAvg * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSDAT);
3723 :
3724 : // Simulate reheat coil for the VAV system
3725 94055 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index, QHeatingDelivered);
3726 94055 : } break;
3727 874886 : case HeatingCoilType::None: { // blank
3728 : // I no reheat is defined then assume that the damper is the only component.
3729 : // If something else is there that is not a reheat coil or a blank then give the error message
3730 874886 : } break;
3731 0 : default: {
3732 0 : ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
3733 0 : } break;
3734 : }
3735 :
3736 : // the COIL is OFF the properties are calculated for this special case.
3737 : } else {
3738 14950281 : switch (this->ReheatComp_Num) {
3739 10808025 : case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
3740 : // Simulate reheat coil for the Const Volume system
3741 10808025 : DummyMdot = 0.0;
3742 10808025 : SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
3743 : // call the reheat coil with the NO FLOW condition to make sure that the Node values
3744 : // are passed through to the coil outlet correctly
3745 10808025 : SimulateWaterCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index);
3746 10808025 : } break;
3747 29755 : case HeatingCoilType::SteamAirHeating: { // COIL:STEAM:AIRHEATING
3748 : // Simulate reheat coil for the VAV system
3749 29755 : SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, 0.0);
3750 29755 : } break;
3751 2210610 : case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
3752 : // Simulate reheat coil for the VAV system
3753 2210610 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
3754 2210610 : } break;
3755 470554 : case HeatingCoilType::Gas: { // COIL:GAS:HEATING
3756 : // Simulate reheat coil for the VAV system
3757 470554 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
3758 470554 : } break;
3759 1431337 : case HeatingCoilType::None: { // blank
3760 : // If no reheat is defined then assume that the damper is the only component.
3761 : // If something else is that is not a reheat coil or a blank then give the error message
3762 1431337 : } break;
3763 0 : default: {
3764 0 : ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
3765 0 : } break;
3766 : }
3767 : }
3768 :
3769 : // push the flow rate history
3770 27022691 : this->MassFlow3 = this->MassFlow2;
3771 27022691 : this->MassFlow2 = this->MassFlow1;
3772 27022691 : this->MassFlow1 = MassFlow;
3773 27022691 : }
3774 :
3775 23491181 : void SingleDuctAirTerminal::CalcOAMassFlow(EnergyPlusData &state,
3776 : Real64 &SAMassFlow, // outside air based on optional user input
3777 : Real64 &AirLoopOAFrac // outside air based on optional user input
3778 : ) const
3779 : {
3780 :
3781 : // FUNCTION INFORMATION:
3782 : // AUTHOR R. Raustad (FSEC)
3783 : // DATE WRITTEN Jan 2010
3784 : // MODIFIED Mangesh Basarkar, 06/2011: Modifying outside air based on airloop DCV flag
3785 :
3786 : // PURPOSE OF THIS FUNCTION:
3787 : // Calculates the amount of outside air required based on optional user input.
3788 : // Zone multipliers are included and are applied in GetInput.
3789 :
3790 : // METHODOLOGY EMPLOYED:
3791 : // User input defines method used to calculate OA.
3792 :
3793 : // Using/Aliasing
3794 : using Psychrometrics::PsyRhoAirFnPbTdbW;
3795 :
3796 : // FUNCTION PARAMETER DEFINITIONS:
3797 23491181 : bool constexpr UseMinOASchFlag(true); // Always use min OA schedule in calculations.
3798 :
3799 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
3800 : Real64 OAVolumeFlowRate; // outside air volume flow rate (m3/s)
3801 : Real64 OAMassFlow; // outside air mass flow rate (kg/s)
3802 :
3803 : // initialize OA flow rate and OA report variable
3804 23491181 : SAMassFlow = 0.0;
3805 23491181 : AirLoopOAFrac = 0.0;
3806 23491181 : int AirLoopNum = this->AirLoopNum;
3807 :
3808 : // Calculate the amount of OA based on optional user inputs
3809 23491181 : if (AirLoopNum > 0) {
3810 23490893 : AirLoopOAFrac = state.dataAirLoop->AirLoopFlow(AirLoopNum).OAFrac;
3811 : // If no additional input from user, RETURN from subroutine
3812 23490893 : if (this->NoOAFlowInputFromUser) {
3813 19011378 : return;
3814 : }
3815 : // Calculate outdoor air flow rate, zone multipliers are applied in GetInput
3816 4479515 : if (AirLoopOAFrac > 0.0) {
3817 8959030 : OAVolumeFlowRate = DataSizing::calcDesignSpecificationOutdoorAir(
3818 4479515 : state, this->OARequirementsPtr, this->CtrlZoneNum, state.dataAirLoop->AirLoopControlInfo(AirLoopNum).AirLoopDCVFlag, UseMinOASchFlag);
3819 4479515 : OAMassFlow = OAVolumeFlowRate * state.dataEnvrn->StdRhoAir;
3820 :
3821 : // convert OA mass flow rate to supply air flow rate based on air loop OA fraction
3822 4479515 : SAMassFlow = OAMassFlow / AirLoopOAFrac;
3823 : }
3824 : }
3825 : }
3826 :
3827 67274 : void SingleDuctAirTerminal::SimCBVAV(EnergyPlusData &state, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum)
3828 : {
3829 :
3830 : // SUBROUTINE INFORMATION:
3831 : // AUTHOR Richard Raustad
3832 : // DATE WRITTEN August 2006
3833 : // MODIFIED KHL/TH 10/2010: added maximum supply air temperature leaving reheat coil
3834 :
3835 : // PURPOSE OF THIS SUBROUTINE:
3836 : // This subroutine simulates the VAV box with varying airflow in heating and cooling.
3837 : // Modified version of SimVAV.
3838 :
3839 : // Using/Aliasing
3840 : using namespace DataZoneEnergyDemands;
3841 : using HVAC::SmallLoad;
3842 : // unused USE DataHeatBalFanSys, ONLY: Mat
3843 : using HeatingCoils::SimulateHeatingCoilComponents;
3844 : using SteamCoils::SimulateSteamCoilComponents;
3845 : using WaterCoils::SimulateWaterCoilComponents;
3846 : // unused USE DataHeatBalFanSys, ONLY: ZoneThermostatSetPointHi, ZoneThermostatSetPointLo
3847 : using PlantUtilities::SetActuatedBranchFlowRate;
3848 :
3849 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3850 : Real64 MassFlow; // Total Mass Flow Rate from Hot & Cold Inlets [kg/sec]
3851 : Real64 QTotLoad; // Total load based on thermostat setpoint temperature [Watts]
3852 : Real64 QZnReq; // Total load to be met by terminal heater [Watts]
3853 : Real64 QToHeatSetPt; // Remaining load to heating setpoint [W]
3854 : Real64 QSupplyAir; // Zone load met by VAVHeatandCool system
3855 : Real64 CpAirZn; // Specific heat of zone air [J/kg-C]
3856 : Real64 CpAirSysIn; // Specific heat of VAVHeatandCool box entering air [J/kg-C]
3857 : Real64 DeltaTemp; // Temperature difference multiplied by specific heat [J/kg]
3858 : Real64 MaxFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
3859 : Real64 MinFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
3860 : Real64 LeakLoadMult; // Load multiplier to adjust for downstream leaks
3861 : int SysOutletNode; // The node number of the terminal unit outlet node
3862 : int SysInletNode; // The node number of the terminal unit inlet node
3863 : Real64 DummyMdot;
3864 : Real64 QActualHeating;
3865 : Real64 MinFlowFrac; // minimum flow fraction (and minimum damper position)
3866 :
3867 : // sd_airterminal(SysNum)%InletNodeNum is the inlet node to the terminal unit and the damper
3868 : // sd_airterminal(SysNum)%OutletNodeNum is the outlet node of the damper and the inlet node of the heating coil
3869 : // sd_airterminal(SysNum)%ReheatAirOutletNode is the outlet node of the terminal unit and the heating coil
3870 :
3871 : // The calculated load from the Heat Balance
3872 67274 : LeakLoadMult = state.dataDefineEquipment->AirDistUnit(this->ADUNum).LeakLoadMult;
3873 67274 : QTotLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired * LeakLoadMult;
3874 67274 : QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP * LeakLoadMult;
3875 67274 : SysOutletNode = this->ReheatAirOutletNode;
3876 67274 : SysInletNode = this->InletNodeNum;
3877 67274 : CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
3878 67274 : MinFlowFrac = this->ZoneMinAirFrac;
3879 67274 : state.dataSingleDuct->MinMassAirFlowSCBVAV = MinFlowFrac * state.dataEnvrn->StdRhoAir * this->MaxAirVolFlowRate;
3880 67274 : state.dataSingleDuct->ZoneTempSCBVAV = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
3881 :
3882 : // Then depending on if the Load is for heating or cooling it is handled differently. First
3883 : // the massflow rate for cooling is determined to meet the entire load. Then
3884 : // if the massflow is below the minimum or greater than the Max it is set to either the Min
3885 : // or the Max as specified for the VAV model.
3886 67274 : if (this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0) {
3887 : // Calculate the flow required for cooling
3888 43670 : CpAirSysIn = PsyCpAirFnW(this->sd_airterminalInlet.AirHumRat);
3889 43670 : DeltaTemp = CpAirSysIn * this->sd_airterminalInlet.AirTemp - CpAirZn * state.dataSingleDuct->ZoneTempSCBVAV;
3890 :
3891 : // Need to check DeltaTemp and ensure that it is not zero
3892 43670 : if (DeltaTemp != 0.0) {
3893 43662 : MassFlow = QTotLoad / DeltaTemp;
3894 : } else {
3895 8 : MassFlow = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
3896 : }
3897 :
3898 : // Check to see if the flow is < the Min or > the Max air Fraction to the zone; then set to min or max
3899 43670 : MassFlow = max(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMinAvail);
3900 43670 : MassFlow = min(MassFlow, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
3901 : } else {
3902 : // System is Off set massflow to 0.0
3903 23604 : MassFlow = 0.0;
3904 : }
3905 : // look for bang-bang condition: flow rate oscillating between 2 values during the air loop / zone
3906 : // equipment iteration. If detected, set flow rate to previous value.
3907 91631 : if (((std::abs(MassFlow - this->MassFlow2) < this->MassFlowDiff) || (std::abs(MassFlow - this->MassFlow3) < this->MassFlowDiff)) &&
3908 24357 : (std::abs(MassFlow - this->MassFlow1) >= this->MassFlowDiff)) {
3909 0 : MassFlow = this->MassFlow1;
3910 : }
3911 :
3912 : // Move data to the damper outlet node
3913 67274 : this->sd_airterminalOutlet.AirTemp = this->sd_airterminalInlet.AirTemp;
3914 67274 : this->sd_airterminalOutlet.AirHumRat = this->sd_airterminalInlet.AirHumRat;
3915 67274 : this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
3916 67274 : this->sd_airterminalOutlet.AirMassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
3917 67274 : this->sd_airterminalOutlet.AirMassFlowRateMinAvail = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
3918 67274 : this->sd_airterminalOutlet.AirEnthalpy = this->sd_airterminalInlet.AirEnthalpy;
3919 :
3920 : // Calculate the Damper Position when there is a Max air flow specified.
3921 67274 : if (this->AirMassFlowRateMax == 0.0) {
3922 13 : this->DamperPosition = 0.0;
3923 : } else {
3924 67261 : this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
3925 : }
3926 :
3927 : // Need to make sure that the damper outlets are passed to the coil inlet
3928 67274 : this->UpdateSys(state);
3929 :
3930 67274 : QActualHeating = QToHeatSetPt - MassFlow * CpAirZn * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCBVAV);
3931 :
3932 67274 : if ((MassFlow > SmallMassFlow) && (QActualHeating > 0.0) && (state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleCool)) {
3933 : // VAVHeatandCool boxes operate at varying mass flow rates when reheating, VAV boxes operate at min flow
3934 : // (MassFlow <= this->sd_airterminalInlet%AirMassFlowRateMinAvail) .AND. &
3935 : // Per Fred Buhl, don't use DeadBandOrSetback to determine if heaters operate
3936 : // (.NOT. DeadBandOrSetback(ZoneNum))) Then
3937 :
3938 : // At this point we know that there is a heating requirement: i.e., the heating coil needs to
3939 : // be activated (there's a zone heating load or there's a reheat requirement). There are 3 possible
3940 : // situations: 1) the coil load can be met by variable temperature air (below the max heat temp) at
3941 : // the minimum air mass flow rate; 2) the coil load can be met by variable air flow rate with the air
3942 : // temperature fixed at the max heat temp; 3) the load cannot be met (we will run at max air temp and
3943 : // max air flow rate). We check for condition 2 by assuming the air temperatute is at the max heat temp
3944 : // and solving for the air mass flow rate that will meet the load. If the flow rate is between the min and
3945 : // max we are in condition 2.
3946 :
3947 20307 : state.dataSingleDuct->QZoneMax2SCBVAV = QToHeatSetPt;
3948 :
3949 20307 : if (this->MaxReheatTempSetByUser) {
3950 :
3951 5082 : state.dataSingleDuct->MaxHeatTempSCBVAV = this->MaxReheatTemp;
3952 5082 : if (QToHeatSetPt > SmallLoad) { // zone has a positive load to heating setpoint
3953 5082 : state.dataSingleDuct->MassFlowReqSCBVAV =
3954 5082 : QToHeatSetPt / (CpAirZn * (state.dataSingleDuct->MaxHeatTempSCBVAV - state.dataSingleDuct->ZoneTempSCBVAV));
3955 : } else {
3956 0 : state.dataSingleDuct->MassFlowReqSCBVAV = MassFlow;
3957 : }
3958 :
3959 10164 : state.dataSingleDuct->QZoneMax3SCBVAV =
3960 5082 : CpAirZn * (state.dataSingleDuct->MaxHeatTempSCBVAV - state.dataSingleDuct->ZoneTempSCBVAV) * MassFlow;
3961 :
3962 5082 : state.dataSingleDuct->MassFlowActualSCBVAV = MassFlow;
3963 :
3964 5082 : if (state.dataSingleDuct->QZoneMax3SCBVAV < QToHeatSetPt) {
3965 2395 : state.dataSingleDuct->MassFlowActualSCBVAV = state.dataSingleDuct->MassFlowReqSCBVAV;
3966 : // QZoneMax3 = CpAirZn * (MaxHeatTemp - ZoneTemp) * MassFlowActual
3967 : }
3968 :
3969 5082 : if (state.dataSingleDuct->MassFlowActualSCBVAV <= state.dataSingleDuct->MinMassAirFlowSCBVAV) {
3970 0 : state.dataSingleDuct->MassFlowActualSCBVAV = state.dataSingleDuct->MinMassAirFlowSCBVAV;
3971 5082 : } else if (state.dataSingleDuct->MassFlowActualSCBVAV >= this->AirMassFlowRateMax) {
3972 3802 : state.dataSingleDuct->MassFlowActualSCBVAV = this->AirMassFlowRateMax;
3973 : }
3974 :
3975 5082 : state.dataSingleDuct->QZoneMaxSCBVAV = CpAirZn * state.dataSingleDuct->MassFlowActualSCBVAV *
3976 5082 : (state.dataSingleDuct->MaxHeatTempSCBVAV - state.dataSingleDuct->ZoneTempSCBVAV);
3977 :
3978 : // temporary variable
3979 5082 : state.dataSingleDuct->QZoneMax2SCBVAV = min(state.dataSingleDuct->QZoneMaxSCBVAV, QToHeatSetPt);
3980 :
3981 5082 : MassFlow = state.dataSingleDuct->MassFlowActualSCBVAV;
3982 :
3983 : } // IF (sd_airterminal(SysNum)%MaxReheatTempSetByUser) THEN
3984 :
3985 20307 : this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
3986 :
3987 20307 : this->UpdateSys(state);
3988 :
3989 20307 : switch (this->ReheatComp_Num) { // hot water heating coil
3990 0 : case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
3991 : // Determine the load required to pass to the Component controller
3992 : // Although this equation looks strange (using temp instead of deltaT), it is corrected later in ControlCompOutput
3993 : // and is working as-is, temperature setpoints are maintained as expected.
3994 0 : QZnReq = state.dataSingleDuct->QZoneMax2SCBVAV + MassFlow * CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp;
3995 0 : if (QZnReq < SmallLoad) {
3996 0 : QZnReq = 0.0;
3997 : }
3998 :
3999 : // Initialize hot water flow rate to zero.
4000 : // Node(sd_airterminal(SysNum)%ReheatControlNode)%MassFlowRate = 0.0D0
4001 0 : DummyMdot = 0.0;
4002 0 : SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
4003 : // On the first HVAC iteration the system values are given to the controller, but after that
4004 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
4005 0 : if (FirstHVACIteration) {
4006 0 : MaxFlowWater = this->MaxReheatWaterFlow;
4007 0 : MinFlowWater = this->MinReheatWaterFlow;
4008 : } else {
4009 0 : int WaterControlNode = this->ReheatControlNode;
4010 0 : MaxFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMaxAvail;
4011 0 : MinFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMinAvail;
4012 : }
4013 :
4014 : // Simulate the reheat coil at constant air flow. Control by varying the
4015 : // hot water flow rate.
4016 0 : ControlCompOutput(state,
4017 0 : this->ReheatName,
4018 0 : this->ReheatComp,
4019 0 : this->ReheatComp_Index,
4020 : FirstHVACIteration,
4021 : QZnReq,
4022 : this->ReheatControlNode,
4023 : MaxFlowWater,
4024 : MinFlowWater,
4025 : this->ControllerOffset,
4026 0 : this->ControlCompTypeNum,
4027 0 : this->CompErrIndex,
4028 : _,
4029 : SysOutletNode,
4030 : MassFlow,
4031 : _,
4032 : _,
4033 0 : this->HWplantLoc);
4034 :
4035 : // If reverse action damper and the hot water flow is at maximum, simulate the
4036 : // hot water coil with fixed (maximum) hot water flow but allow the air flow to
4037 : // vary up to the maximum (air damper opens to try to meet zone load).
4038 0 : if (this->DamperHeatingAction == Action::Reverse) {
4039 0 : if (state.dataLoopNodes->Node(this->ReheatControlNode).MassFlowRate == this->MaxReheatWaterFlow) {
4040 0 : ControlCompOutput(state,
4041 0 : this->ReheatName,
4042 0 : this->ReheatComp,
4043 0 : this->ReheatComp_Index,
4044 : FirstHVACIteration,
4045 0 : state.dataSingleDuct->QZoneMax2SCBVAV,
4046 : this->OutletNodeNum,
4047 : this->sd_airterminalInlet.AirMassFlowRateMaxAvail,
4048 : this->sd_airterminalInlet.AirMassFlowRateMinAvail,
4049 : this->ControllerOffset,
4050 0 : this->ControlCompTypeNum,
4051 0 : this->CompErrIndex,
4052 : ZoneNodeNum,
4053 : SysOutletNode);
4054 : // ! air flow controller, not on plant, don't pass plant topology info
4055 :
4056 : // reset terminal unit inlet air mass flow to new value.
4057 0 : MassFlow = state.dataLoopNodes->Node(SysOutletNode).MassFlowRate;
4058 0 : this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
4059 0 : this->UpdateSys(state);
4060 : }
4061 : // look for bang-bang condition: flow rate oscillating between 2 values during the air loop / zone
4062 : // equipment iteration. If detected, set flow rate to previous value and recalc HW flow.
4063 0 : if (((std::abs(MassFlow - this->MassFlow2) < this->MassFlowDiff) || (std::abs(MassFlow - this->MassFlow3) < this->MassFlowDiff)) &&
4064 0 : (std::abs(MassFlow - this->MassFlow1) >= this->MassFlowDiff)) {
4065 0 : MassFlow = this->MassFlow1;
4066 0 : this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
4067 0 : this->UpdateSys(state);
4068 0 : ControlCompOutput(state,
4069 0 : this->ReheatName,
4070 0 : this->ReheatComp,
4071 0 : this->ReheatComp_Index,
4072 : FirstHVACIteration,
4073 : QZnReq,
4074 : this->ReheatControlNode,
4075 : MaxFlowWater,
4076 : MinFlowWater,
4077 : this->ControllerOffset,
4078 0 : this->ControlCompTypeNum,
4079 0 : this->CompErrIndex,
4080 : _,
4081 : SysOutletNode,
4082 : MassFlow,
4083 : _,
4084 : _,
4085 0 : this->HWplantLoc);
4086 : }
4087 : // recalculate damper position
4088 0 : if (this->AirMassFlowRateMax == 0.0) {
4089 0 : this->DamperPosition = 0.0;
4090 : } else {
4091 0 : this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
4092 : }
4093 : }
4094 0 : } break;
4095 0 : case HeatingCoilType::SteamAirHeating: { // ! COIL:STEAM:AIRHEATING
4096 : // Determine the load required to pass to the Component controller
4097 0 : QZnReq = state.dataSingleDuct->QZoneMax2SCBVAV -
4098 0 : MassFlow * CpAirZn * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCBVAV);
4099 0 : if (QZnReq < SmallLoad) {
4100 0 : QZnReq = 0.0;
4101 : }
4102 :
4103 : // Simulate reheat coil for the VAV system
4104 0 : SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, QZnReq);
4105 0 : } break;
4106 13145 : case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
4107 : // Determine the load required to pass to the Component controller
4108 13145 : QSupplyAir = MassFlow * CpAirZn * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCBVAV);
4109 13145 : QZnReq = state.dataSingleDuct->QZoneMax2SCBVAV - QSupplyAir;
4110 13145 : if (QZnReq < SmallLoad) {
4111 4105 : QZnReq = 0.0;
4112 : }
4113 :
4114 : // Simulate reheat coil for the VAV system
4115 13145 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index);
4116 13145 : } break;
4117 0 : case HeatingCoilType::Gas: { // COIL:GAS:HEATING
4118 : // Determine the load required to pass to the Component controller
4119 0 : QZnReq = state.dataSingleDuct->QZoneMax2SCBVAV -
4120 0 : MassFlow * CpAirZn * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCBVAV);
4121 0 : if (QZnReq < SmallLoad) {
4122 0 : QZnReq = 0.0;
4123 : }
4124 :
4125 : // Simulate reheat coil for the VAV system
4126 0 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index);
4127 0 : } break;
4128 7162 : case HeatingCoilType::None: { // blank
4129 : // If no reheat is defined then assume that the damper is the only component.
4130 : // If something else is there that is not a reheat coil then give the error message below.
4131 7162 : } break;
4132 0 : default: {
4133 0 : ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
4134 0 : } break;
4135 : }
4136 :
4137 : // the COIL is OFF the properties are calculated for this special case.
4138 : } else {
4139 46967 : switch (this->ReheatComp_Num) {
4140 0 : case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
4141 : // Simulate reheat coil for the Const Volume system
4142 : // Node(sd_airterminal(SysNum)%ReheatControlNode)%MassFlowRate = 0.0D0
4143 : // Initialize hot water flow rate to zero.
4144 0 : DummyMdot = 0.0;
4145 0 : SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
4146 :
4147 : // call the reheat coil with the NO FLOW condition to make sure that the Node values
4148 : // are passed through to the coil outlet correctly
4149 0 : SimulateWaterCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index);
4150 0 : } break;
4151 0 : case HeatingCoilType::SteamAirHeating: { // COIL:STEAM:AIRHEATING
4152 : // Simulate reheat coil for the VAV system
4153 0 : SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, 0.0);
4154 0 : } break;
4155 32905 : case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
4156 : // Simulate reheat coil for the VAV system
4157 32905 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
4158 32905 : } break;
4159 0 : case HeatingCoilType::Gas: { // COIL:GAS:HEATING
4160 : // Simulate reheat coil for the VAV system
4161 0 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
4162 0 : } break;
4163 14062 : case HeatingCoilType::None: { // blank
4164 : // If no reheat is defined then assume that the damper is the only component.
4165 : // If something else is there that is not a reheat coil then give the error message
4166 14062 : } break;
4167 0 : default: {
4168 0 : ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
4169 0 : } break;
4170 : }
4171 : }
4172 : // push the flow rate history
4173 67274 : this->MassFlow3 = this->MassFlow2;
4174 67274 : this->MassFlow2 = this->MassFlow1;
4175 67274 : this->MassFlow1 = MassFlow;
4176 67274 : }
4177 :
4178 30864 : void SingleDuctAirTerminal::SimVAVVS(EnergyPlusData &state, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum)
4179 : {
4180 :
4181 : // SUBROUTINE INFORMATION:
4182 : // AUTHOR Fred Buhl
4183 : // DATE WRITTEN July 2004
4184 :
4185 : // PURPOSE OF THIS SUBROUTINE:
4186 : // This subroutine simulates a single duct VAV terminal unit with a variable-speed fan upstream
4187 : // and a reheat coil on the downstream side.
4188 :
4189 : // METHODOLOGY EMPLOYED:
4190 : // Define a compound component in CalcVAVVS. Break the heating/cooling load into 4 regions based
4191 : // on equip on/off combinations. Assign the heating load to the appropriate region and iteratively
4192 : // solve for the appropriate control variable value using Regula-Falsi solver.
4193 :
4194 : // Using/Aliasing
4195 : using namespace DataZoneEnergyDemands;
4196 : using General::SolveRoot;
4197 : using SteamCoils::GetCoilCapacity;
4198 :
4199 : // SUBROUTINE PARAMETER DEFINITIONS:
4200 30864 : Real64 constexpr BigLoad(1.0e+20);
4201 :
4202 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4203 30864 : Real64 MassFlow = 0; // [kg/sec] Total Mass Flow Rate from Hot & Cold Inlets
4204 : Real64 QTotLoad; // [Watts]
4205 : // unused REAL(r64) :: QZnReq ! [Watts]
4206 : Real64 CpAirZn;
4207 : // unused REAL(r64) :: CpAirSysIn
4208 : // unused REAL(r64) :: DeltaTemp
4209 : int SysOutletNode; // The node number of the terminal unit outlet node
4210 : int SysInletNode; // the node number of the terminal unit inlet node
4211 : int WaterControlNode; // This is the Actuated Reheat Control Node
4212 : int SteamControlNode;
4213 : Real64 MaxFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
4214 : Real64 MinFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
4215 : Real64 MaxFlowSteam; // This is the value passed to the Controller depending if FirstHVACIteration or not
4216 : Real64 MinFlowSteam; // This is the value passed to the Controller depending if FirstHVACIteration or not
4217 : Real64 HWFlow; // the hot water flow rate [kg/s]
4218 : Real64 QCoolFanOnMax; // max cooling - fan at max flow; note that cooling is always < 0. [W]
4219 : Real64 QCoolFanOnMin; // min active cooling with fan on - fan at lowest speed. [W]
4220 : Real64 QHeatFanOnMax; // max heating - fan at heat flow max, hot water flow at max [W]
4221 : Real64 QHeatFanOnMin; // min heating - fan at min flow, hot water at max flow [W]
4222 : Real64 QHeatFanOffMax; // max heating - fan off, hot water flow at max [W]
4223 : Real64 QNoHeatFanOff; // min heating - fan off, hot water at min flow [W]
4224 : HeatingCoilType HCType; // heating coil type
4225 : HVAC::FanType fanType; // fan type (as a number)
4226 : int FanOp; // 1 if fan is on; 0 if off.
4227 : Real64 MaxCoolMassFlow; // air flow at max cooling [kg/s]
4228 : Real64 MaxHeatMassFlow; // air flow at max heating [kg/s]
4229 : Real64 MinMassFlow; // minimum air flow rate [kg/s]
4230 : Real64 UnitFlowToler; // flow rate tolerance
4231 : Real64 QDelivered;
4232 : Real64 FracDelivered;
4233 : int SolFlag;
4234 : Real64 ErrTolerance;
4235 : Real64 MaxSteamCap; // steam coil capacity at full load
4236 :
4237 : // The calculated load from the Heat Balance
4238 30864 : QTotLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired;
4239 30864 : SysOutletNode = this->ReheatAirOutletNode;
4240 30864 : SysInletNode = this->InletNodeNum;
4241 30864 : CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
4242 30864 : HCType = this->ReheatComp_Num;
4243 30864 : fanType = this->fanType;
4244 30864 : MaxCoolMassFlow = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
4245 30864 : MaxHeatMassFlow = min(this->HeatAirMassFlowRateMax, this->sd_airterminalInlet.AirMassFlowRateMaxAvail);
4246 30864 : MinMassFlow = MaxCoolMassFlow * this->ZoneMinAirFrac;
4247 30864 : UnitFlowToler = 0.001 * DataConvergParams::HVACFlowRateToler;
4248 30864 : QDelivered = 0.0;
4249 30864 : HWFlow = 0.0;
4250 30864 : if (this->sd_airterminalInlet.AirMassFlowRateMaxAvail <= 0.0 || state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
4251 7828 : MassFlow = 0.0;
4252 7828 : FanOp = 0;
4253 7828 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, 0.0, 0.0, fanType, MassFlow, FanOp, QDelivered);
4254 7828 : return;
4255 : }
4256 :
4257 23036 : if (HCType == HeatingCoilType::SimpleHeating) {
4258 23036 : WaterControlNode = this->ReheatControlNode;
4259 23036 : if (FirstHVACIteration) {
4260 11518 : MaxFlowWater = this->MaxReheatWaterFlow;
4261 11518 : MinFlowWater = this->MinReheatWaterFlow;
4262 : } else {
4263 11518 : WaterControlNode = this->ReheatControlNode;
4264 11518 : MaxFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMaxAvail;
4265 11518 : MinFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMinAvail;
4266 : }
4267 : } else {
4268 0 : WaterControlNode = 0;
4269 0 : MaxFlowWater = 0.0;
4270 0 : MinFlowWater = 0.0;
4271 : }
4272 :
4273 23036 : if (HCType == HeatingCoilType::SteamAirHeating) {
4274 0 : SteamControlNode = this->ReheatControlNode;
4275 0 : if (FirstHVACIteration) {
4276 0 : MaxFlowSteam = this->MaxReheatSteamFlow;
4277 0 : MinFlowSteam = this->MinReheatSteamFlow;
4278 : } else {
4279 0 : MaxFlowSteam = state.dataLoopNodes->Node(SteamControlNode).MassFlowRateMaxAvail;
4280 0 : MinFlowSteam = state.dataLoopNodes->Node(SteamControlNode).MassFlowRateMinAvail;
4281 : }
4282 : } else {
4283 23036 : SteamControlNode = 0;
4284 23036 : MaxFlowSteam = 0.0;
4285 23036 : MinFlowSteam = 0.0;
4286 : }
4287 :
4288 : // define 3 load regions and assign the current load to the correct region.
4289 : // region 1: active cooling with fan on
4290 23036 : FanOp = 1;
4291 23036 : if (HCType == HeatingCoilType::SteamAirHeating) {
4292 : bool ErrorsFound; // returned from mining function call
4293 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowSteam, 0.0, fanType, MaxCoolMassFlow, FanOp, QCoolFanOnMax);
4294 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowSteam, 0.0, fanType, MinMassFlow, FanOp, QCoolFanOnMin);
4295 : // region 2: active heating with fan on
4296 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowSteam, BigLoad, fanType, MaxHeatMassFlow, FanOp, QHeatFanOnMax);
4297 0 : MaxSteamCap = GetCoilCapacity(state, this->ReheatComp, this->ReheatName, ErrorsFound);
4298 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowSteam, 0.0, fanType, MinMassFlow, FanOp, QHeatFanOnMin);
4299 : // region 3: active heating with fan off
4300 0 : FanOp = 0;
4301 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowSteam, BigLoad, fanType, MinMassFlow, FanOp, QHeatFanOffMax);
4302 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowSteam, 0.0, fanType, MinMassFlow, FanOp, QNoHeatFanOff);
4303 : } else {
4304 23036 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowWater, 0.0, fanType, MaxCoolMassFlow, FanOp, QCoolFanOnMax);
4305 23036 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowWater, 0.0, fanType, MinMassFlow, FanOp, QCoolFanOnMin);
4306 : // region 2: active heating with fan on
4307 23036 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, BigLoad, fanType, MaxHeatMassFlow, FanOp, QHeatFanOnMax);
4308 23036 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, 0.0, fanType, MinMassFlow, FanOp, QHeatFanOnMin);
4309 : // region 3: active heating with fan off
4310 23036 : FanOp = 0;
4311 23036 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, BigLoad, fanType, MinMassFlow, FanOp, QHeatFanOffMax);
4312 23036 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowWater, 0.0, fanType, MinMassFlow, FanOp, QNoHeatFanOff);
4313 : }
4314 :
4315 : // Active cooling with fix for issue #5592
4316 32132 : if (QTotLoad < (-1.0 * SmallLoad) && QTotLoad < (QCoolFanOnMin - SmallLoad) && this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0 &&
4317 9096 : !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
4318 : // check that it can meet the load
4319 9096 : FanOp = 1;
4320 9096 : if (QCoolFanOnMax < QTotLoad - SmallLoad) {
4321 9096 : Real64 MinHWFlow = (HCType == HeatingCoilType::SteamAirHeating) ? MinFlowSteam : MinFlowWater;
4322 :
4323 45066 : auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, MinHWFlow, fanType, FanOp, QTotLoad](Real64 const SupplyAirMassFlow) {
4324 45066 : Real64 UnitOutput = 0.0; // cooling output [W] (cooling is negative)
4325 :
4326 45066 : state.dataSingleDuct->sd_airterminal(this->SysNum)
4327 45066 : .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinHWFlow, 0.0, fanType, SupplyAirMassFlow, FanOp, UnitOutput);
4328 45066 : return (QTotLoad - UnitOutput) / QTotLoad;
4329 9096 : };
4330 :
4331 9096 : SolveRoot(state, UnitFlowToler, 50, SolFlag, MassFlow, f, MinMassFlow, MaxCoolMassFlow);
4332 9096 : if (SolFlag == -1) {
4333 0 : if (this->IterationLimit == 0) {
4334 0 : ShowWarningError(state, format("Supply air flow control failed in VS VAV terminal unit {}", this->SysName));
4335 0 : ShowContinueError(state, " Iteration limit exceeded in calculating air flow rate");
4336 : }
4337 0 : ShowRecurringWarningErrorAtEnd(
4338 0 : state, "Supply air flow Iteration limit exceeded in VS VAV terminal unit " + this->SysName, this->IterationLimit);
4339 9096 : } else if (SolFlag == -2) {
4340 0 : if (this->IterationFailed == 0) {
4341 0 : ShowWarningError(state, format("Supply air flow control failed in VS VAV terminal unit {}", this->SysName));
4342 0 : ShowContinueError(state, " Bad air flow limits");
4343 : }
4344 0 : ShowRecurringWarningErrorAtEnd(
4345 0 : state, "Supply air flow control failed in VS VAV terminal unit " + this->SysName, this->IterationFailed);
4346 : }
4347 :
4348 : } else {
4349 :
4350 0 : MassFlow = MaxCoolMassFlow;
4351 :
4352 0 : if (HCType == HeatingCoilType::SteamAirHeating) {
4353 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowSteam, 0.0, fanType, MassFlow, FanOp, QDelivered);
4354 : } else {
4355 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowWater, 0.0, fanType, MassFlow, FanOp, QDelivered);
4356 : }
4357 : }
4358 :
4359 : // no active heating or cooling
4360 13940 : } else if ((QTotLoad >= QCoolFanOnMin - SmallLoad && QTotLoad <= QNoHeatFanOff + SmallLoad &&
4361 27880 : this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0) ||
4362 13940 : (this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0 && state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum))) {
4363 0 : MassFlow = MinMassFlow;
4364 0 : FanOp = 0;
4365 0 : if (HCType == HeatingCoilType::SteamAirHeating) {
4366 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowSteam, QTotLoad, fanType, MassFlow, FanOp, QNoHeatFanOff);
4367 : } else {
4368 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MinFlowWater, 0.0, fanType, MassFlow, FanOp, QNoHeatFanOff);
4369 : }
4370 :
4371 : // active heating
4372 27880 : } else if (QTotLoad > QNoHeatFanOff + SmallLoad && this->sd_airterminalInlet.AirMassFlowRateMaxAvail > 0.0 &&
4373 13940 : !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
4374 : // hot water coil
4375 13940 : if (HCType == HeatingCoilType::SimpleHeating) {
4376 13940 : if (QTotLoad < QHeatFanOffMax - SmallLoad) {
4377 : // vary HW flow, leave air flow at minimum
4378 7575 : ErrTolerance = this->ControllerOffset;
4379 7575 : MassFlow = MinMassFlow;
4380 7575 : FanOp = 0;
4381 :
4382 120869 : auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, MassFlow, fanType, FanOp, QTotLoad](Real64 const HWMassFlow) {
4383 120869 : Real64 UnitOutput = 0.0; // heating output [W]
4384 120869 : Real64 QSteamLoad = 0.0; // proportional load to calculate steam flow [W]
4385 :
4386 120869 : state.dataSingleDuct->sd_airterminal(this->SysNum)
4387 120869 : .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, HWMassFlow, QSteamLoad, fanType, MassFlow, FanOp, UnitOutput);
4388 :
4389 120869 : return (QTotLoad - UnitOutput) / QTotLoad;
4390 7575 : };
4391 :
4392 7575 : SolveRoot(state, ErrTolerance, 500, SolFlag, HWFlow, f, MinFlowWater, MaxFlowWater);
4393 7575 : if (SolFlag == -1) {
4394 0 : ShowRecurringWarningErrorAtEnd(state, "Hot Water flow control failed in VS VAV terminal unit " + this->SysName, this->ErrCount1);
4395 0 : ShowRecurringContinueErrorAtEnd(
4396 0 : state, "...Iteration limit (500) exceeded in calculating the hot water flow rate", this->ErrCount1c);
4397 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, HWFlow, 0.0, fanType, MassFlow, FanOp, QDelivered);
4398 7575 : } else if (SolFlag == -2) {
4399 0 : ShowRecurringWarningErrorAtEnd(
4400 0 : state, "Hot Water flow control failed (bad air flow limits) in VS VAV terminal unit " + this->SysName, this->ErrCount2);
4401 : }
4402 6365 : } else if (QTotLoad >= QHeatFanOffMax - SmallLoad && QTotLoad <= QHeatFanOnMin + SmallLoad) {
4403 14 : MassFlow = MinMassFlow;
4404 14 : FanOp = 0;
4405 14 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, 0.0, fanType, MassFlow, FanOp, QDelivered);
4406 6351 : } else if (QTotLoad > QHeatFanOnMin + SmallLoad && QTotLoad < QHeatFanOnMax - SmallLoad) {
4407 : // set hot water flow to max and vary the supply air flow rate
4408 6351 : FanOp = 1;
4409 47467 : auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, fanType, FanOp, QTotLoad](Real64 const SupplyAirMassFlow) {
4410 47467 : Real64 UnitOutput = 0.0; // heating output [W]
4411 47467 : state.dataSingleDuct->sd_airterminal(this->SysNum)
4412 47467 : .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, QTotLoad, fanType, SupplyAirMassFlow, FanOp, UnitOutput);
4413 :
4414 47467 : return (QTotLoad - UnitOutput) / QTotLoad;
4415 6351 : };
4416 6351 : SolveRoot(state, UnitFlowToler, 50, SolFlag, MassFlow, f, MinMassFlow, MaxHeatMassFlow);
4417 6351 : if (SolFlag == -1) {
4418 0 : if (this->IterationLimit == 0) {
4419 0 : ShowWarningError(state, format("Supply air flow control failed in VS VAV terminal unit {}", this->SysName));
4420 0 : ShowContinueError(state, " Iteration limit exceeded in calculating air flow rate");
4421 : }
4422 0 : ShowRecurringWarningErrorAtEnd(
4423 0 : state, "Supply air flow Iteration limit exceeded in VS VAV terminal unit " + this->SysName, this->IterationLimit);
4424 6351 : } else if (SolFlag == -2) {
4425 0 : if (this->IterationFailed == 0) {
4426 0 : ShowWarningError(state, format("Supply air flow control failed in VS VAV terminal unit {}", this->SysName));
4427 0 : ShowContinueError(state, " Bad air flow limits");
4428 : }
4429 0 : ShowRecurringWarningErrorAtEnd(
4430 0 : state, "Supply air flow control failed in VS VAV terminal unit " + this->SysName, this->IterationFailed);
4431 : }
4432 6351 : } else {
4433 0 : MassFlow = MaxHeatMassFlow;
4434 0 : FanOp = 1;
4435 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, 0.0, fanType, MassFlow, FanOp, QDelivered);
4436 : }
4437 0 : } else if (HCType == HeatingCoilType::SteamAirHeating) {
4438 : // IF (QTotLoad > QNoHeatFanOff + SmallLoad .AND. QTotLoad < QHeatFanOffMax - SmallLoad) THEN
4439 0 : if (QTotLoad < QHeatFanOffMax - SmallLoad) {
4440 0 : ErrTolerance = this->ControllerOffset;
4441 0 : MassFlow = MinMassFlow;
4442 0 : FanOp = 0;
4443 0 : auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, MassFlow, fanType, FanOp, QTotLoad, MinFlowSteam, MaxFlowSteam, MaxSteamCap](
4444 : Real64 const HWMassFlow) {
4445 0 : Real64 UnitOutput = 0.0; // heating output [W]
4446 0 : Real64 QSteamLoad = 0.0; // proportional load to calculate steam flow [W]
4447 :
4448 : // vary the load to be met by the steam coil to converge on a steam flow rate to meet the load
4449 : // backwards way of varying steam flow rate. Steam coil calculates a flow rate to meet a load.
4450 0 : if ((MaxFlowSteam - MinFlowSteam) == 0.0) {
4451 0 : QSteamLoad = QTotLoad; // Use QTotLoad, bad starting value error for RegulaFalsi will occur
4452 : } else {
4453 0 : QSteamLoad = MaxSteamCap * HWMassFlow / (MaxFlowSteam - MinFlowSteam);
4454 : }
4455 0 : state.dataSingleDuct->sd_airterminal(this->SysNum)
4456 0 : .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, HWMassFlow, QSteamLoad, fanType, MassFlow, FanOp, UnitOutput);
4457 :
4458 0 : return (QTotLoad - UnitOutput) / QTotLoad;
4459 0 : };
4460 0 : SolveRoot(state, ErrTolerance, 500, SolFlag, HWFlow, f, MinFlowSteam, MaxFlowSteam);
4461 0 : if (SolFlag == -1) {
4462 0 : ShowRecurringWarningErrorAtEnd(state, "Steam flow control failed in VS VAV terminal unit " + this->SysName, this->ErrCount1);
4463 0 : ShowRecurringContinueErrorAtEnd(
4464 0 : state, "...Iteration limit (500) exceeded in calculating the hot water flow rate", this->ErrCount1c);
4465 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, HWFlow, 0.0, fanType, MassFlow, FanOp, QDelivered);
4466 0 : } else if (SolFlag == -2) {
4467 0 : ShowRecurringWarningErrorAtEnd(
4468 0 : state, "Steam flow control failed (bad air flow limits) in VS VAV terminal unit " + this->SysName, this->ErrCount2);
4469 : }
4470 0 : } else if (QTotLoad >= QHeatFanOffMax - SmallLoad && QTotLoad <= QHeatFanOnMin + SmallLoad) {
4471 0 : MassFlow = MinMassFlow;
4472 0 : FanOp = 0;
4473 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowWater, 0.0, fanType, MassFlow, FanOp, QDelivered);
4474 0 : } else if (QTotLoad > QHeatFanOnMin + SmallLoad && QTotLoad < QHeatFanOnMax - SmallLoad) {
4475 0 : FanOp = 1;
4476 :
4477 0 : auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, MaxFlowSteam, fanType, FanOp, QTotLoad](Real64 const SupplyAirMassFlow) {
4478 0 : Real64 UnitOutput = 0.0; // heating output [W]
4479 :
4480 0 : state.dataSingleDuct->sd_airterminal(this->SysNum)
4481 0 : .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, MaxFlowSteam, QTotLoad, fanType, SupplyAirMassFlow, FanOp, UnitOutput);
4482 :
4483 0 : return (QTotLoad - UnitOutput) / QTotLoad;
4484 0 : };
4485 :
4486 0 : SolveRoot(state, UnitFlowToler, 50, SolFlag, MassFlow, f, MinMassFlow, MaxHeatMassFlow);
4487 0 : if (SolFlag == -1) {
4488 0 : if (this->IterationLimit == 0) {
4489 0 : ShowWarningError(state, format("Steam heating coil control failed in VS VAV terminal unit {}", this->SysName));
4490 0 : ShowContinueError(state, " Iteration limit exceeded in calculating air flow rate");
4491 : }
4492 0 : ShowRecurringWarningErrorAtEnd(
4493 0 : state, "Steam heating coil iteration limit exceeded in VS VAV terminal unit " + this->SysName, this->IterationLimit);
4494 0 : } else if (SolFlag == -2) {
4495 0 : if (this->IterationFailed == 0) {
4496 0 : ShowWarningError(state, format("Steam heating coil control failed in VS VAV terminal unit {}", this->SysName));
4497 0 : ShowContinueError(state, " Bad air flow limits");
4498 : }
4499 0 : ShowRecurringWarningErrorAtEnd(
4500 0 : state, "Steam heating coil control failed in VS VAV terminal unit " + this->SysName, this->IterationFailed);
4501 : }
4502 0 : } else {
4503 0 : MassFlow = MaxHeatMassFlow;
4504 0 : FanOp = 1;
4505 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, QTotLoad, QTotLoad, fanType, MassFlow, FanOp, QDelivered);
4506 : }
4507 0 : } else if (HCType == HeatingCoilType::Gas || HCType == HeatingCoilType::Electric) {
4508 0 : if (QTotLoad <= QHeatFanOnMin + SmallLoad) {
4509 : // vary heating coil power, leave mass flow at minimum
4510 0 : MassFlow = MinMassFlow;
4511 0 : FanOp = 0;
4512 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, 0.0, QTotLoad, fanType, MassFlow, FanOp, QDelivered);
4513 0 : } else if (QTotLoad > QHeatFanOnMin + SmallLoad && QTotLoad < QHeatFanOnMax - SmallLoad) {
4514 0 : FanOp = 1;
4515 :
4516 0 : auto f = [&state, this, FirstHVACIteration, ZoneNodeNum, fanType, FanOp, QTotLoad](Real64 const HeatingFrac) {
4517 0 : Real64 MaxHeatOut{this->ReheatCoilMaxCapacity}; // maximum heating output [W]
4518 : Real64 UnitOutput; // heating output [W]
4519 : Real64 AirMassFlowRate; // [kg/s]
4520 : Real64 HeatOut; // heating coil output [W]
4521 :
4522 0 : HeatOut = HeatingFrac * MaxHeatOut;
4523 0 : AirMassFlowRate = max(HeatingFrac * state.dataSingleDuct->sd_airterminal(this->SysNum).HeatAirMassFlowRateMax,
4524 0 : state.dataSingleDuct->sd_airterminal(this->SysNum).sd_airterminalInlet.AirMassFlowRateMaxAvail *
4525 0 : state.dataSingleDuct->sd_airterminal(this->SysNum).ZoneMinAirFrac);
4526 :
4527 0 : state.dataSingleDuct->sd_airterminal(this->SysNum)
4528 0 : .CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, 0.0, HeatOut, fanType, AirMassFlowRate, FanOp, UnitOutput);
4529 :
4530 0 : return (QTotLoad - UnitOutput) / QTotLoad;
4531 0 : };
4532 :
4533 0 : SolveRoot(state, UnitFlowToler, 50, SolFlag, FracDelivered, f, 0.0, 1.0);
4534 0 : MassFlow = state.dataLoopNodes->Node(SysInletNode).MassFlowRate;
4535 0 : if (SolFlag == -1) {
4536 0 : if (this->IterationLimit == 0) {
4537 0 : ShowWarningError(state, format("Heating coil control failed in VS VAV terminal unit {}", this->SysName));
4538 0 : ShowContinueError(state, " Iteration limit exceeded in calculating air flow rate");
4539 : }
4540 0 : ShowRecurringWarningErrorAtEnd(
4541 0 : state, "Heating coil control iteration limit exceeded in VS VAV terminal unit " + this->SysName, this->IterationLimit);
4542 0 : } else if (SolFlag == -2) {
4543 0 : if (this->IterationFailed == 0) {
4544 0 : ShowWarningError(state, format("Heating coil control failed in VS VAV terminal unit {}", this->SysName));
4545 0 : ShowContinueError(state, " Bad air flow limits");
4546 : }
4547 0 : ShowRecurringWarningErrorAtEnd(
4548 0 : state, "Heating coil control failed in VS VAV terminal unit " + this->SysName, this->IterationFailed);
4549 : }
4550 0 : } else {
4551 0 : MassFlow = MaxHeatMassFlow;
4552 0 : FanOp = 1;
4553 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, 0.0, QTotLoad, fanType, MassFlow, FanOp, QDelivered);
4554 : }
4555 0 : } else {
4556 0 : ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
4557 : }
4558 :
4559 : } else {
4560 :
4561 0 : MassFlow = 0.0;
4562 0 : FanOp = 0;
4563 0 : this->CalcVAVVS(state, FirstHVACIteration, ZoneNodeNum, 0.0, 0.0, fanType, MassFlow, FanOp, QDelivered);
4564 : }
4565 :
4566 : // Move mass flow rates to the damper outlet node
4567 23036 : this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
4568 23036 : this->sd_airterminalOutlet.AirMassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
4569 23036 : this->sd_airterminalOutlet.AirMassFlowRateMinAvail = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
4570 :
4571 : // calculate VAV damper Position.
4572 23036 : if (this->AirMassFlowRateMax == 0.0) {
4573 0 : this->DamperPosition = 0.0;
4574 : } else {
4575 23036 : this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
4576 : }
4577 : // update the air terminal outlet node data
4578 23036 : this->UpdateSys(state);
4579 : }
4580 :
4581 1656582 : void SingleDuctAirTerminal::SimConstVol(EnergyPlusData &state, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum)
4582 : {
4583 :
4584 : // SUBROUTINE INFORMATION:
4585 : // AUTHOR Richard J. Liesen
4586 : // DATE WRITTEN February 2000
4587 : // MODIFIED FB/KHL/TH 2/2011: added maximum supply air temperature leaving reheat coil
4588 :
4589 : // PURPOSE OF THIS SUBROUTINE:
4590 : // This subroutine simulates the simple single duct constant volume systems.
4591 :
4592 : // Using/Aliasing
4593 : using namespace DataZoneEnergyDemands;
4594 : // unused USE DataHeatBalFanSys, ONLY: Mat
4595 : using HeatingCoils::SimulateHeatingCoilComponents;
4596 : using PlantUtilities::SetActuatedBranchFlowRate;
4597 : using SteamCoils::SimulateSteamCoilComponents;
4598 : using WaterCoils::SimulateWaterCoilComponents;
4599 :
4600 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4601 : Real64 MaxFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
4602 : Real64 MinFlowWater; // This is the value passed to the Controller depending if FirstHVACIteration or not
4603 : Real64 DummyMdot; // local fluid mass flow rate
4604 :
4605 : Real64 QToHeatSetPt =
4606 1656582 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP; // The calculated load from the Heat Balance
4607 1656582 : Real64 MassFlow = this->sd_airterminalInlet.AirMassFlowRateMaxAvail; // System massflow is set to the Available
4608 1656582 : state.dataSingleDuct->QMax2SCV = QToHeatSetPt;
4609 1656582 : state.dataSingleDuct->ZoneTempSCV = state.dataLoopNodes->Node(ZoneNodeNum).Temp;
4610 1656582 : Real64 CpAir = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNodeNum).HumRat); // zone air specific heat
4611 1656582 : if (this->MaxReheatTempSetByUser) {
4612 13970 : state.dataSingleDuct->TAirMaxSCV = this->MaxReheatTemp;
4613 13970 : state.dataSingleDuct->QMaxSCV = CpAir * MassFlow * (state.dataSingleDuct->TAirMaxSCV - state.dataSingleDuct->ZoneTempSCV);
4614 13970 : state.dataSingleDuct->QMax2SCV = min(QToHeatSetPt, state.dataSingleDuct->QMaxSCV);
4615 : } // if (this->MaxReheatTempSetByUser) {
4616 :
4617 1656582 : if (((this->sd_airterminalInlet.AirMassFlowRateMaxAvail == 0.0) && (this->sd_airterminalInlet.AirMassFlowRateMinAvail == 0.0)) ||
4618 1023023 : (this->sd_airterminalInlet.AirMassFlowRate == 0.0)) {
4619 : // System is Off set massflow to 0.0
4620 633559 : MassFlow = 0.0;
4621 : }
4622 :
4623 : // Calculate the Damper Position when there is a Max air flow specified.
4624 1656582 : if (this->AirMassFlowRateMax == 0.0) {
4625 47 : this->DamperPosition = 0.0;
4626 : } else {
4627 1656535 : this->DamperPosition = MassFlow / this->AirMassFlowRateMax;
4628 : }
4629 :
4630 : // make sure the inlet node flow rate is updated if the mass flow has been limited
4631 1656582 : this->sd_airterminalOutlet.AirMassFlowRate = MassFlow;
4632 1656582 : this->sd_airterminalOutlet.AirMassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
4633 1656582 : this->sd_airterminalOutlet.AirMassFlowRateMinAvail = this->sd_airterminalInlet.AirMassFlowRateMinAvail;
4634 1656582 : this->UpdateSys(state);
4635 :
4636 : Real64 QActualHeating =
4637 1656582 : QToHeatSetPt - MassFlow * CpAir * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCV); // reheat needed
4638 : // Now the massflow for reheating has been determined. If it is zero, or in SetBack, or the
4639 : // system scheduled OFF then not operational and shut the system down.
4640 1656582 : if ((MassFlow > SmallMassFlow) && (QActualHeating > 0.0) && (state.dataHeatBalFanSys->TempControlType(ZoneNum) != HVAC::SetptType::SingleCool)) {
4641 :
4642 : Real64 QZnReq;
4643 :
4644 487632 : switch (this->ReheatComp_Num) {
4645 436108 : case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
4646 : // Determine the load required to pass to the Component controller
4647 436108 : QZnReq = state.dataSingleDuct->QMax2SCV + MassFlow * CpAir * state.dataSingleDuct->ZoneTempSCV;
4648 :
4649 : // Before Iterating through the Reheat Coil and Controller set the flags for the
4650 : // Do Loop to initialized conditions.
4651 : // Node(sd_airterminal(SysNum)%ReheatControlNode)%MassFlowRate = 0.0D0
4652 : // Initialize hot water flow rate to zero.
4653 436108 : DummyMdot = 0.0;
4654 436108 : SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
4655 :
4656 : // On the first HVAC iteration the system values are given to the controller, but after that
4657 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
4658 436108 : if (FirstHVACIteration) {
4659 218354 : MaxFlowWater = this->MaxReheatWaterFlow;
4660 218354 : MinFlowWater = this->MinReheatWaterFlow;
4661 : } else {
4662 217754 : int WaterControlNode = this->ReheatControlNode;
4663 217754 : MaxFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMaxAvail;
4664 217754 : MinFlowWater = state.dataLoopNodes->Node(WaterControlNode).MassFlowRateMinAvail;
4665 : }
4666 :
4667 : // Simulate reheat coil for the Const Volume system
4668 : // Set Converged to True & when controller is not converged it will set to False.
4669 1744432 : ControlCompOutput(state,
4670 436108 : this->ReheatName,
4671 436108 : this->ReheatComp,
4672 436108 : this->ReheatComp_Index,
4673 : FirstHVACIteration,
4674 : QZnReq,
4675 : this->ReheatControlNode,
4676 : MaxFlowWater,
4677 : MinFlowWater,
4678 : this->ControllerOffset,
4679 436108 : this->ControlCompTypeNum,
4680 436108 : this->CompErrIndex,
4681 : _,
4682 436108 : this->ReheatAirOutletNode,
4683 : MassFlow,
4684 : _,
4685 : _,
4686 436108 : this->HWplantLoc);
4687 :
4688 436108 : } break;
4689 0 : case HeatingCoilType::SteamAirHeating: { // COIL:STEAM:STEAMAIRHEATING
4690 : // Determine the load required to pass to the Component controller
4691 0 : QZnReq = state.dataSingleDuct->QMax2SCV - MassFlow * CpAir * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCV);
4692 :
4693 : // Simulate reheat coil for the VAV system
4694 0 : SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, QZnReq);
4695 0 : } break;
4696 4576 : case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
4697 : // Determine the load required to pass to the Component controller
4698 4576 : QZnReq = state.dataSingleDuct->QMax2SCV - MassFlow * CpAir * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCV);
4699 :
4700 : // Simulate reheat coil for the VAV system
4701 4576 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index);
4702 :
4703 4576 : } break;
4704 46948 : case HeatingCoilType::Gas: { // COIL:GAS:HEATING
4705 : // Determine the load required to pass to the Component controller
4706 46948 : QZnReq = state.dataSingleDuct->QMax2SCV - MassFlow * CpAir * (this->sd_airterminalInlet.AirTemp - state.dataSingleDuct->ZoneTempSCV);
4707 :
4708 : // Simulate reheat coil for the VAV system
4709 46948 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, QZnReq, this->ReheatComp_Index);
4710 46948 : } break;
4711 0 : default: {
4712 0 : ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
4713 0 : } break;
4714 : }
4715 :
4716 : // the COIL is OFF the properties are calculated for this special case.
4717 : } else {
4718 1168950 : switch (this->ReheatComp_Num) {
4719 945001 : case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
4720 : // Simulate reheat coil for the Const Volume system
4721 : // Node(sd_airterminal(SysNum)%ReheatControlNode)%MassFlowRate = 0.0D0
4722 : // Initialize hot water flow rate to zero.
4723 945001 : DummyMdot = 0.0;
4724 945001 : SetActuatedBranchFlowRate(state, DummyMdot, this->ReheatControlNode, this->HWplantLoc, true);
4725 :
4726 : // call the reheat coil with the NO FLOW condition to make sure that the Node values
4727 : // are passed through to the coil outlet correctly
4728 945001 : SimulateWaterCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index);
4729 945001 : } break;
4730 0 : case HeatingCoilType::SteamAirHeating: { // COIL:STEAM:AIRHEATING
4731 : // Simulate reheat coil for the Const Volume system
4732 0 : SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, 0.0);
4733 0 : } break;
4734 19886 : case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
4735 : // Simulate reheat coil for the Const Volume system
4736 19886 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
4737 19886 : } break;
4738 204063 : case HeatingCoilType::Gas: { // COIL:GAS:HEATING
4739 : // Simulate reheat coil for the Const Volume system
4740 204063 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, 0.0, this->ReheatComp_Index);
4741 204063 : } break;
4742 0 : default: {
4743 0 : ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
4744 0 : } break;
4745 : }
4746 : }
4747 1656582 : }
4748 :
4749 8544703 : void SingleDuctAirTerminal::SimConstVolNoReheat(EnergyPlusData &state)
4750 : {
4751 :
4752 : // PURPOSE OF THIS SUBROUTINE:
4753 : // Sets outlet flow rate and conditions for singleduct constantvolume with no reheat air terminal.
4754 :
4755 8544703 : this->sd_airterminalOutlet = this->sd_airterminalInlet;
4756 :
4757 : // update the air terminal outlet node data
4758 8544703 : this->UpdateSys(state);
4759 8544703 : }
4760 :
4761 359460 : void SingleDuctAirTerminal::CalcVAVVS(EnergyPlusData &state,
4762 : bool const FirstHVACIteration, // flag for 1st HVAV iteration in the time step
4763 : int const ZoneNode, // zone node number
4764 : Real64 const HWFlow, // hot water flow (kg/s)
4765 : Real64 const HCoilReq, // gas or elec coil demand requested
4766 : [[maybe_unused]] HVAC::FanType fanType, // type of fan
4767 : Real64 const AirFlow, // air flow rate (kg/s)
4768 : int const FanOn, // 1 means fan is on
4769 : Real64 &LoadMet // load met by unit (watts)
4770 : )
4771 : {
4772 :
4773 : // SUBROUTINE INFORMATION:
4774 : // AUTHOR Fred Buhl
4775 : // DATE WRITTEN July 2004
4776 :
4777 : // PURPOSE OF THIS SUBROUTINE:
4778 : // Simulate the components making up the VAV terminal unit with variable speed fan.
4779 :
4780 : // METHODOLOGY EMPLOYED:
4781 : // Simulates the unit components sequentially in the air flow direction.
4782 :
4783 : // Using/Aliasing
4784 : using HeatingCoils::SimulateHeatingCoilComponents;
4785 : using PlantUtilities::SetComponentFlowRate;
4786 : using SteamCoils::SimulateSteamCoilComponents;
4787 : using WaterCoils::SimulateWaterCoilComponents;
4788 :
4789 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4790 : int FanInNode; // unit air inlet node (fan inlet)
4791 : int FanOutNode; // fan outlet node (heating coil inlet node)
4792 : int HCOutNode; // unit air outlet node (heating coil air outlet node)
4793 : int HotControlNode; // the hot water inlet node
4794 : Real64 AirMassFlow; // total air mass flow rate [kg/s]
4795 : Real64 CpAirZn; // zone air specific heat [J/kg-C]
4796 : bool TurnFansOffSav; // save the fan off flag
4797 : Real64 mdot;
4798 :
4799 359460 : TurnFansOffSav = state.dataHVACGlobal->TurnFansOff;
4800 359460 : FanInNode = this->InletNodeNum;
4801 359460 : FanOutNode = this->OutletNodeNum;
4802 359460 : HCOutNode = this->ReheatAirOutletNode;
4803 359460 : HotControlNode = this->ReheatControlNode;
4804 359460 : AirMassFlow = AirFlow;
4805 359460 : state.dataLoopNodes->Node(FanInNode).MassFlowRate = AirMassFlow;
4806 359460 : CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNode).HumRat);
4807 359460 : if (FanOn == 1) {
4808 184677 : state.dataFans->fans(this->Fan_Index)->simulate(state, FirstHVACIteration, _, _);
4809 :
4810 : } else { // pass through conditions
4811 174783 : state.dataHVACGlobal->TurnFansOff = true;
4812 174783 : state.dataFans->fans(this->Fan_Index)->simulate(state, FirstHVACIteration, _, _);
4813 174783 : state.dataHVACGlobal->TurnFansOff = TurnFansOffSav;
4814 174783 : state.dataLoopNodes->Node(FanOutNode).MassFlowRate = state.dataLoopNodes->Node(FanInNode).MassFlowRate;
4815 174783 : state.dataLoopNodes->Node(FanOutNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(FanInNode).MassFlowRateMaxAvail;
4816 174783 : state.dataLoopNodes->Node(FanOutNode).MassFlowRateMinAvail = state.dataLoopNodes->Node(FanInNode).MassFlowRateMinAvail;
4817 : }
4818 359460 : switch (this->ReheatComp_Num) {
4819 359460 : case HeatingCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
4820 359460 : mdot = HWFlow;
4821 359460 : if (this->HWplantLoc.loopNum > 0) {
4822 359460 : SetComponentFlowRate(state, mdot, this->ReheatControlNode, this->ReheatCoilOutletNode, this->HWplantLoc);
4823 : }
4824 :
4825 359460 : SimulateWaterCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index);
4826 359460 : } break;
4827 0 : case HeatingCoilType::SteamAirHeating: { // HW Flow is steam mass flow here
4828 0 : mdot = HWFlow;
4829 0 : if (this->HWplantLoc.loopNum > 0) {
4830 0 : SetComponentFlowRate(state, mdot, this->ReheatControlNode, this->ReheatCoilOutletNode, this->HWplantLoc);
4831 : }
4832 0 : SimulateSteamCoilComponents(state, this->ReheatName, FirstHVACIteration, this->ReheatComp_Index, HCoilReq);
4833 0 : } break;
4834 0 : case HeatingCoilType::Electric: { // COIL:ELECTRIC:HEATING
4835 0 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, HCoilReq, this->ReheatComp_Index);
4836 0 : } break;
4837 0 : case HeatingCoilType::Gas: { // COIL:GAS:HEATING
4838 0 : SimulateHeatingCoilComponents(state, this->ReheatName, FirstHVACIteration, HCoilReq, this->ReheatComp_Index);
4839 0 : } break;
4840 0 : default: {
4841 0 : ShowFatalError(state, format("Invalid Reheat Component={}", this->ReheatComp));
4842 0 : } break;
4843 : }
4844 :
4845 359460 : LoadMet = AirMassFlow * CpAirZn * (state.dataLoopNodes->Node(HCOutNode).Temp - state.dataLoopNodes->Node(ZoneNode).Temp);
4846 359460 : }
4847 :
4848 : // End Algorithm Section of the Module
4849 : // *****************************************************************************
4850 :
4851 : // Beginning of Update subroutines for the Sys Module
4852 : // *****************************************************************************
4853 :
4854 50990459 : void SingleDuctAirTerminal::UpdateSys(EnergyPlusData &state) const
4855 : {
4856 :
4857 : // SUBROUTINE INFORMATION:
4858 : // AUTHOR Richard J. Liesen
4859 : // DATE WRITTEN january 2000
4860 :
4861 : // PURPOSE OF THIS SUBROUTINE:
4862 : // This subroutine updates the Syss.
4863 :
4864 50990459 : int OutletNode = this->OutletNodeNum;
4865 50990459 : int InletNode = this->InletNodeNum;
4866 :
4867 50990459 : if (this->SysType_Num == SysType::SingleDuctVAVReheat || this->SysType_Num == SysType::SingleDuctCBVAVReheat ||
4868 13433816 : this->SysType_Num == SysType::SingleDuctCBVAVNoReheat || this->SysType_Num == SysType::SingleDuctVAVNoReheat ||
4869 10224321 : this->SysType_Num == SysType::SingleDuctConstVolNoReheat) {
4870 : // Set the outlet air nodes of the Sys
4871 49310841 : state.dataLoopNodes->Node(OutletNode).MassFlowRate = this->sd_airterminalOutlet.AirMassFlowRate;
4872 49310841 : state.dataLoopNodes->Node(OutletNode).Temp = this->sd_airterminalOutlet.AirTemp;
4873 49310841 : state.dataLoopNodes->Node(OutletNode).HumRat = this->sd_airterminalOutlet.AirHumRat;
4874 49310841 : state.dataLoopNodes->Node(OutletNode).Enthalpy = this->sd_airterminalOutlet.AirEnthalpy;
4875 : // Set the outlet nodes for properties that just pass through & not used
4876 49310841 : state.dataLoopNodes->Node(OutletNode).Quality = state.dataLoopNodes->Node(InletNode).Quality;
4877 49310841 : state.dataLoopNodes->Node(OutletNode).Press = state.dataLoopNodes->Node(InletNode).Press;
4878 : }
4879 :
4880 : // After all of the Outlets are updated the mass flow information needs to be
4881 : // passed back to the system inlet.
4882 50990459 : state.dataLoopNodes->Node(InletNode).MassFlowRate = this->sd_airterminalOutlet.AirMassFlowRate;
4883 50990459 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail =
4884 50990459 : min(this->sd_airterminalOutlet.AirMassFlowRateMaxAvail, state.dataLoopNodes->Node(OutletNode).MassFlowRateMax);
4885 50990459 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = this->sd_airterminalOutlet.AirMassFlowRateMinAvail;
4886 :
4887 50990459 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
4888 98625 : state.dataLoopNodes->Node(OutletNode).CO2 = state.dataLoopNodes->Node(InletNode).CO2;
4889 : }
4890 :
4891 50990459 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
4892 34833 : state.dataLoopNodes->Node(OutletNode).GenContam = state.dataLoopNodes->Node(InletNode).GenContam;
4893 : }
4894 50990459 : }
4895 :
4896 : // End of Update subroutines for the Sys Module
4897 : // *****************************************************************************
4898 :
4899 : // Beginning of Reporting subroutines for the Sys Module
4900 : // *****************************************************************************
4901 :
4902 37322114 : void SingleDuctAirTerminal::ReportSys(EnergyPlusData &state) // unused1208
4903 : {
4904 :
4905 : // set zone OA volume flow rate
4906 37322114 : this->CalcOutdoorAirVolumeFlowRate(state);
4907 37322114 : }
4908 :
4909 111 : void GetHVACSingleDuctSysIndex(EnergyPlusData &state,
4910 : std::string const &SDSName,
4911 : int &SDSIndex,
4912 : bool &ErrorsFound,
4913 : std::string_view const ThisObjectType,
4914 : ObjexxFCL::Optional_int DamperInletNode, // Damper inlet node number
4915 : ObjexxFCL::Optional_int DamperOutletNode // Damper outlet node number
4916 : )
4917 : {
4918 :
4919 : // SUBROUTINE INFORMATION:
4920 : // AUTHOR Lixing Gu
4921 : // DATE WRITTEN February 2006
4922 :
4923 : // PURPOSE OF THIS SUBROUTINE:
4924 : // This subroutine sets an index for a given single duct system -- issues error message if that system
4925 : // is not a legal system.
4926 :
4927 111 : if (state.dataSingleDuct->GetInputFlag) { // First time subroutine has been entered
4928 0 : GetSysInput(state);
4929 0 : state.dataSingleDuct->GetInputFlag = false;
4930 : }
4931 :
4932 111 : SDSIndex = Util::FindItemInList(SDSName, state.dataSingleDuct->sd_airterminal, &SingleDuctAirTerminal::SysName);
4933 111 : if (SDSIndex == 0) {
4934 0 : if (!ThisObjectType.empty()) {
4935 0 : ShowSevereError(state, fmt::format("{}, GetHVACSingleDuctSysIndex: Single duct system not found={}", ThisObjectType, SDSName));
4936 : } else {
4937 0 : ShowSevereError(state, format("GetHVACSingleDuctSysIndex: Single duct system not found={}", SDSName));
4938 : }
4939 0 : ErrorsFound = true;
4940 : } else {
4941 201 : if ((state.dataSingleDuct->sd_airterminal(SDSIndex).SysType_Num != SysType::SingleDuctConstVolReheat) &&
4942 90 : (state.dataSingleDuct->sd_airterminal(SDSIndex).SysType_Num != SysType::SingleDuctVAVReheat)) {
4943 0 : if (!ThisObjectType.empty()) {
4944 0 : ShowSevereError(state, fmt::format("{}, GetHVACSingleDuctSysIndex: Could not find allowed types={}", ThisObjectType, SDSName));
4945 : } else {
4946 0 : ShowSevereError(state, format("GetHVACSingleDuctSysIndex: Could not find allowed types={}", SDSName));
4947 : }
4948 0 : ShowContinueError(state, "The allowed types are: AirTerminal:SingleDuct:ConstantVolume:Reheat and AirTerminal:SingleDuct:VAV:Reheat");
4949 0 : ErrorsFound = true;
4950 : }
4951 111 : if (state.dataSingleDuct->sd_airterminal(SDSIndex).SysType_Num == SysType::SingleDuctVAVReheat) {
4952 90 : if (present(DamperInletNode)) {
4953 90 : DamperInletNode = state.dataSingleDuct->sd_airterminal(SDSIndex).InletNodeNum;
4954 : }
4955 90 : if (present(DamperOutletNode)) {
4956 90 : DamperOutletNode = state.dataSingleDuct->sd_airterminal(SDSIndex).OutletNodeNum;
4957 : }
4958 : }
4959 : }
4960 111 : }
4961 :
4962 1862128 : void SimATMixer(EnergyPlusData &state, std::string const &SysName, bool const FirstHVACIteration, int &SysIndex)
4963 : {
4964 :
4965 : // SUBROUTINE INFORMATION:
4966 : // DATE WRITTEN March 2012
4967 :
4968 : // PURPOSE OF THIS SUBROUTINE
4969 : // Simulate an Air Terminal Mixer component
4970 :
4971 1862128 : if (state.dataSingleDuct->GetATMixerFlag) {
4972 0 : state.dataSingleDuct->GetATMixerFlag = false;
4973 : }
4974 :
4975 1862128 : if (SysIndex == 0) {
4976 0 : state.dataSingleDuct->SysNumSATM = Util::FindItemInList(SysName, state.dataSingleDuct->SysATMixer);
4977 0 : SysIndex = state.dataSingleDuct->SysNumSATM;
4978 0 : if (state.dataSingleDuct->SysNumSATM == 0) {
4979 0 : ShowFatalError(state, format("Object {} not found", SysName));
4980 : }
4981 : } else {
4982 1862128 : state.dataSingleDuct->SysNumSATM = SysIndex;
4983 : }
4984 :
4985 1862128 : state.dataSingleDuct->SysATMixer(state.dataSingleDuct->SysNumSATM).InitATMixer(state, FirstHVACIteration);
4986 :
4987 1862128 : CalcATMixer(state, state.dataSingleDuct->SysNumSATM);
4988 :
4989 1862128 : UpdateATMixer(state, state.dataSingleDuct->SysNumSATM);
4990 1862128 : }
4991 :
4992 235659 : void GetATMixers(EnergyPlusData &state)
4993 : {
4994 :
4995 : // SUBROUTINE INFORMATION:
4996 : // DATE WRITTEN March 2012
4997 :
4998 : // PURPOSE OF THIS SUBROUTINE
4999 : // Get input for inlet side air terminal mixers and store it in the inlet side air terminal mixer array
5000 :
5001 : // METHODOLOGY EMPLOYED:
5002 : // Use the Get routines from the InputProcessor module.
5003 :
5004 : // Using/Aliasing
5005 : using DataZoneEquipment::EquipmentData;
5006 : using DataZoneEquipment::SubEquipmentData;
5007 : using NodeInputManager::GetOnlySingleNode;
5008 : using namespace DataLoopNode;
5009 : using BranchNodeConnections::TestCompSet;
5010 :
5011 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5012 : int NumNums; // Number of REAL(r64) numbers returned by GetObjectItem
5013 : int NumAlphas; // Number of alphanumerics returned by GetObjectItem
5014 : int ATMixerNum; // Index of inlet side mixer air terminal unit
5015 : int IOStat;
5016 : static constexpr std::string_view RoutineName("GetATMixers: "); // include trailing blank space
5017 235659 : bool ErrorsFound(false); // Error flag
5018 : int NodeNum; // Index to node number
5019 : int CtrlZone; // Index to control zone
5020 : bool ZoneNodeNotFound; // Flag for error checking
5021 : bool errFlag; // error flag from component validation
5022 :
5023 235659 : if (!state.dataSingleDuct->GetATMixerFlag) {
5024 235456 : return;
5025 : }
5026 203 : state.dataSingleDuct->GetATMixerFlag = false;
5027 :
5028 203 : auto &ipsc = state.dataIPShortCut;
5029 :
5030 203 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
5031 203 : cCurrentModuleObject = "AirTerminal:SingleDuct:Mixer";
5032 203 : state.dataSingleDuct->NumATMixers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
5033 203 : state.dataSingleDuct->SysATMixer.allocate(state.dataSingleDuct->NumATMixers);
5034 :
5035 : // make sure the input data is read in only once
5036 203 : if (state.dataZoneAirLoopEquipmentManager->GetAirDistUnitsFlag) {
5037 : // Need air distribution units first
5038 43 : ZoneAirLoopEquipmentManager::GetZoneAirLoopEquipment(state);
5039 43 : state.dataZoneAirLoopEquipmentManager->GetAirDistUnitsFlag = false;
5040 : }
5041 :
5042 262 : for (ATMixerNum = 1; ATMixerNum <= state.dataSingleDuct->NumATMixers; ++ATMixerNum) {
5043 118 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
5044 : cCurrentModuleObject,
5045 : ATMixerNum,
5046 59 : state.dataIPShortCut->cAlphaArgs,
5047 : NumAlphas,
5048 59 : state.dataIPShortCut->rNumericArgs,
5049 : NumNums,
5050 : IOStat,
5051 59 : state.dataIPShortCut->lNumericFieldBlanks,
5052 59 : state.dataIPShortCut->lAlphaFieldBlanks,
5053 59 : state.dataIPShortCut->cAlphaFieldNames,
5054 59 : state.dataIPShortCut->cNumericFieldNames);
5055 :
5056 59 : auto &atMixer = state.dataSingleDuct->SysATMixer(ATMixerNum);
5057 59 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
5058 59 : state.dataSingleDuct->SysATMixer(ATMixerNum).Name = state.dataIPShortCut->cAlphaArgs(1);
5059 :
5060 59 : atMixer.type = static_cast<HVAC::MixerType>(getEnumValue(HVAC::mixerTypeLocNamesUC, ipsc->cAlphaArgs(7)));
5061 :
5062 59 : if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:WATERTOAIRHEATPUMP") {
5063 15 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 1;
5064 44 : } else if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:FOURPIPEFANCOIL") {
5065 10 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 2;
5066 34 : } else if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:PACKAGEDTERMINALAIRCONDITIONER") {
5067 9 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 3;
5068 25 : } else if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:PACKAGEDTERMINALHEATPUMP") {
5069 5 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 4;
5070 20 : } else if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:VARIABLEREFRIGERANTFLOW") {
5071 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 5;
5072 20 : } else if (state.dataIPShortCut->cAlphaArgs(2) == "AIRLOOPHVAC:UNITARYSYSTEM") {
5073 5 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 6;
5074 15 : } else if (state.dataIPShortCut->cAlphaArgs(2) == "ZONEHVAC:UNITVENTILATOR") {
5075 5 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitType = 7;
5076 : }
5077 :
5078 59 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitName = state.dataIPShortCut->cAlphaArgs(3);
5079 :
5080 118 : ValidateComponent(
5081 59 : state, state.dataIPShortCut->cAlphaArgs(2), state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneHVACUnitName, errFlag, cCurrentModuleObject);
5082 :
5083 59 : state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode =
5084 59 : GetOnlySingleNode(state,
5085 59 : state.dataIPShortCut->cAlphaArgs(4),
5086 : ErrorsFound,
5087 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctMixer,
5088 59 : state.dataIPShortCut->cAlphaArgs(1),
5089 : DataLoopNode::NodeFluidType::Air,
5090 : DataLoopNode::ConnectionType::Outlet,
5091 : NodeInputManager::CompFluidStream::Primary,
5092 : ObjectIsNotParent,
5093 59 : state.dataIPShortCut->cAlphaFieldNames(4));
5094 :
5095 59 : state.dataSingleDuct->SysATMixer(ATMixerNum).PriInNode = GetOnlySingleNode(state,
5096 59 : state.dataIPShortCut->cAlphaArgs(5),
5097 : ErrorsFound,
5098 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctMixer,
5099 59 : state.dataIPShortCut->cAlphaArgs(1),
5100 : DataLoopNode::NodeFluidType::Air,
5101 : DataLoopNode::ConnectionType::Inlet,
5102 : NodeInputManager::CompFluidStream::Primary,
5103 : ObjectIsNotParent,
5104 59 : state.dataIPShortCut->cAlphaFieldNames(5));
5105 59 : state.dataSingleDuct->SysATMixer(ATMixerNum).SecInNode = GetOnlySingleNode(state,
5106 59 : state.dataIPShortCut->cAlphaArgs(6),
5107 : ErrorsFound,
5108 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctMixer,
5109 59 : state.dataIPShortCut->cAlphaArgs(1),
5110 : DataLoopNode::NodeFluidType::Air,
5111 : DataLoopNode::ConnectionType::Inlet,
5112 : NodeInputManager::CompFluidStream::Primary,
5113 : ObjectIsNotParent,
5114 59 : state.dataIPShortCut->cAlphaFieldNames(6));
5115 :
5116 59 : if (state.dataIPShortCut->lAlphaFieldBlanks(8)) {
5117 40 : state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser = true;
5118 : } else {
5119 19 : state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr =
5120 19 : Util::FindItemInList(state.dataIPShortCut->cAlphaArgs(8), state.dataSize->OARequirements);
5121 19 : if (state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr == 0) {
5122 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid data.", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
5123 0 : ShowContinueError(state,
5124 0 : format("..invalid {}=\"{}\".", state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8)));
5125 0 : ErrorsFound = true;
5126 : } else {
5127 19 : state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser = false;
5128 : }
5129 : }
5130 :
5131 59 : if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
5132 50 : state.dataSingleDuct->SysATMixer(ATMixerNum).OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
5133 : } else {
5134 9 : if (state.dataIPShortCut->cAlphaArgs(9) == "CURRENTOCCUPANCY") {
5135 9 : state.dataSingleDuct->SysATMixer(ATMixerNum).OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
5136 0 : } else if (state.dataIPShortCut->cAlphaArgs(9) == "DESIGNOCCUPANCY") {
5137 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::ByDesignLevel;
5138 : } else {
5139 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).OAPerPersonMode = DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel;
5140 0 : ShowWarningError(state, format("{}{}=\"{}\", invalid data.", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
5141 0 : ShowContinueError(state,
5142 0 : format("..invalid {}=\"{}\". The default input of CurrentOccupancy is assigned",
5143 0 : state.dataIPShortCut->cAlphaFieldNames(9),
5144 0 : state.dataIPShortCut->cAlphaArgs(9)));
5145 : }
5146 : }
5147 :
5148 : // Check for dupes in the three nodes.
5149 59 : if (state.dataSingleDuct->SysATMixer(ATMixerNum).SecInNode == state.dataSingleDuct->SysATMixer(ATMixerNum).PriInNode) {
5150 0 : ShowSevereError(state,
5151 0 : format("{} = {} {} = {} duplicates the {}.",
5152 : cCurrentModuleObject,
5153 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).Name,
5154 0 : state.dataIPShortCut->cAlphaArgs(5),
5155 0 : state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).PriInNode),
5156 0 : state.dataIPShortCut->cAlphaArgs(4)));
5157 0 : ErrorsFound = true;
5158 59 : } else if (state.dataSingleDuct->SysATMixer(ATMixerNum).SecInNode == state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode) {
5159 0 : ShowSevereError(state,
5160 0 : format("{} = {} {} = {} duplicates the {}.",
5161 : cCurrentModuleObject,
5162 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).Name,
5163 0 : state.dataIPShortCut->cAlphaArgs(6),
5164 0 : state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode),
5165 0 : state.dataIPShortCut->cAlphaArgs(4)));
5166 0 : ErrorsFound = true;
5167 : }
5168 :
5169 59 : if (state.dataSingleDuct->SysATMixer(ATMixerNum).PriInNode == state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode) {
5170 0 : ShowSevereError(state,
5171 0 : format("{} = {} {} = {} duplicates the {}.",
5172 : cCurrentModuleObject,
5173 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).Name,
5174 0 : state.dataIPShortCut->cAlphaArgs(6),
5175 0 : state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode),
5176 0 : state.dataIPShortCut->cAlphaArgs(5)));
5177 0 : ErrorsFound = true;
5178 : }
5179 :
5180 178 : for (int ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
5181 178 : if (state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
5182 59 : state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = state.dataSingleDuct->SysATMixer(ATMixerNum).PriInNode;
5183 59 : state.dataSingleDuct->SysATMixer(ATMixerNum).ADUNum = ADUNum;
5184 59 : break;
5185 : }
5186 : }
5187 : // one assumes if there isn't one assigned, it's an error?
5188 59 : if (state.dataSingleDuct->SysATMixer(ATMixerNum).ADUNum == 0) {
5189 0 : ShowSevereError(state,
5190 0 : format("{}No matching Air Distribution Unit, for System = [{},{}].",
5191 : RoutineName,
5192 : cCurrentModuleObject,
5193 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).Name));
5194 0 : ShowContinueError(
5195 : state,
5196 0 : format("...should have outlet node = {}", state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode)));
5197 0 : ErrorsFound = true;
5198 : } else {
5199 :
5200 59 : if (state.dataSingleDuct->SysATMixer(ATMixerNum).type == HVAC::MixerType::InletSide) {
5201 : // Air Terminal inlet node must be the same as a zone exhaust node
5202 35 : ZoneNodeNotFound = true;
5203 123 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
5204 122 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
5205 35 : continue;
5206 : }
5207 137 : for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumExhaustNodes; ++NodeNum) {
5208 84 : if (state.dataSingleDuct->SysATMixer(ATMixerNum).SecInNode ==
5209 84 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).ExhaustNode(NodeNum)) {
5210 34 : ZoneNodeNotFound = false;
5211 34 : state.dataDefineEquipment->AirDistUnit(state.dataSingleDuct->SysATMixer(ATMixerNum).ADUNum).ZoneEqNum = CtrlZone;
5212 34 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum = CtrlZone;
5213 : // Must wait until InitATMixer to fill other zone equip config data because ultimate zone inlet node is not known yet
5214 : // for inlet side mixers
5215 34 : if (!state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser) {
5216 10 : bool UseOccSchFlag = false;
5217 10 : bool UseMinOASchFlag = false;
5218 10 : state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate =
5219 10 : DataSizing::calcDesignSpecificationOutdoorAir(state,
5220 10 : state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr,
5221 10 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum,
5222 : UseOccSchFlag,
5223 : UseMinOASchFlag);
5224 : }
5225 34 : goto ControlledZoneLoop_exit;
5226 : }
5227 : }
5228 : }
5229 1 : ControlledZoneLoop_exit:;
5230 35 : if (ZoneNodeNotFound) {
5231 1 : bool ZoneNodeFoundAgain = false;
5232 4 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
5233 9 : for (int Num = 1; Num <= state.dataZoneEquip->ZoneEquipList(CtrlZone).NumOfEquipTypes; ++Num) {
5234 7 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), state.dataZoneEquip->ZoneEquipList(CtrlZone).EquipName(Num)) &&
5235 1 : Util::SameString(state.dataIPShortCut->cAlphaArgs(2),
5236 1 : state.dataZoneEquip->ZoneEquipList(CtrlZone).EquipTypeName(Num))) {
5237 1 : state.dataDefineEquipment->AirDistUnit(state.dataSingleDuct->SysATMixer(ATMixerNum).ADUNum).ZoneEqNum = CtrlZone;
5238 1 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum = CtrlZone;
5239 : // Must wait until InitATMixer to fill other zone equip config data because ultimate zone inlet node is not known yet
5240 : // for inlet side mixers
5241 1 : if (!state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser) {
5242 1 : bool UseOccSchFlag = false;
5243 1 : bool UseMinOASchFlag = false;
5244 1 : state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate =
5245 1 : DataSizing::calcDesignSpecificationOutdoorAir(state,
5246 1 : state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr,
5247 1 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum,
5248 : UseOccSchFlag,
5249 : UseMinOASchFlag);
5250 : }
5251 1 : ZoneNodeFoundAgain = true;
5252 1 : break;
5253 : }
5254 : }
5255 4 : if (ZoneNodeFoundAgain) {
5256 1 : break;
5257 : }
5258 : }
5259 1 : if (!ZoneNodeFoundAgain) {
5260 0 : ShowSevereError(state,
5261 0 : format("{} = \"{}\". Inlet Side Air Terminal Mixer air inlet node name must be the same as either a zone "
5262 : "exhaust node name or an induced air node in ZonePlenum.",
5263 : cCurrentModuleObject,
5264 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).Name));
5265 0 : ShowContinueError(state, "..Zone exhaust node name is specified in ZoneHVAC:EquipmentConnections object.");
5266 0 : ShowContinueError(state, "..Induced Air Outlet Node name is specified in AirLoopHVAC:ReturnPlenum object.");
5267 0 : ShowContinueError(state,
5268 0 : format("..Inlet Side CONNECTED Air Terminal Mixer inlet node name = {}",
5269 0 : state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).SecInNode)));
5270 0 : ErrorsFound = true;
5271 : }
5272 : }
5273 : }
5274 :
5275 59 : if (state.dataSingleDuct->SysATMixer(ATMixerNum).type == HVAC::MixerType::SupplySide) {
5276 24 : ZoneNodeNotFound = true;
5277 117 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
5278 117 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
5279 24 : continue;
5280 : }
5281 164 : for (NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++NodeNum) {
5282 95 : if (state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode ==
5283 95 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(NodeNum)) {
5284 24 : ZoneNodeNotFound = false;
5285 24 : state.dataDefineEquipment->AirDistUnit(state.dataSingleDuct->SysATMixer(ATMixerNum).ADUNum).ZoneEqNum = CtrlZone;
5286 24 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum = CtrlZone;
5287 : // Wait until InitATMixer to fill other zone equip config data
5288 :
5289 24 : if (!state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser) {
5290 8 : bool UseOccSchFlag = false;
5291 8 : bool UseMinOASchFlag = false;
5292 8 : state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate =
5293 8 : DataSizing::calcDesignSpecificationOutdoorAir(state,
5294 8 : state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr,
5295 8 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum,
5296 : UseOccSchFlag,
5297 : UseMinOASchFlag);
5298 : }
5299 24 : goto ControlZoneLoop_exit;
5300 : }
5301 : }
5302 : }
5303 0 : ControlZoneLoop_exit:;
5304 24 : if (ZoneNodeNotFound) {
5305 0 : ShowSevereError(
5306 : state,
5307 0 : format("{} = \"{}\". Supply Side Air Terminal Mixer air outlet node name must be the same as a zone inlet node name.",
5308 : cCurrentModuleObject,
5309 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).Name));
5310 0 : ShowContinueError(state, "..Zone inlet node name is specified in ZoneHVAC:EquipmentConnections object.");
5311 0 : ShowContinueError(state,
5312 0 : format("..Supply Side connected Air Terminal Mixer outlet node name = {}",
5313 0 : state.dataLoopNodes->NodeID(state.dataSingleDuct->SysATMixer(ATMixerNum).MixedAirOutNode)));
5314 0 : ErrorsFound = true;
5315 : }
5316 : }
5317 : }
5318 118 : TestCompSet(state,
5319 : cCurrentModuleObject,
5320 59 : state.dataSingleDuct->SysATMixer(ATMixerNum).Name,
5321 59 : state.dataIPShortCut->cAlphaArgs(5),
5322 59 : state.dataIPShortCut->cAlphaArgs(4),
5323 : "Air Nodes");
5324 :
5325 59 : if (state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr == 0) {
5326 40 : if (state.dataSize->ZoneSizingInput.allocated()) {
5327 240 : for (int SizingInputNum = 1; SizingInputNum <= state.dataSize->NumZoneSizingInput; ++SizingInputNum) {
5328 200 : if (state.dataSize->ZoneSizingInput(SizingInputNum).ZoneNum == state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum) {
5329 40 : if (state.dataSize->ZoneSizingInput(SizingInputNum).ZoneDesignSpecOAIndex == 0) {
5330 0 : ShowWarningError(
5331 0 : state, format("{}{}=\"{}\", invalid data.", RoutineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
5332 0 : ShowContinueError(state,
5333 0 : format("{} is blank in both the mixer and the Sizing:Zone object for the same zone.",
5334 0 : state.dataIPShortCut->cAlphaFieldNames(8)));
5335 0 : ShowContinueError(state, "The mixer outdoor airflow rate is set to zero.");
5336 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate = 0.0;
5337 : } else {
5338 40 : state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr =
5339 40 : state.dataSize->ZoneSizingInput(SizingInputNum).ZoneDesignSpecOAIndex;
5340 40 : state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate =
5341 40 : DataSizing::calcDesignSpecificationOutdoorAir(state,
5342 40 : state.dataSingleDuct->SysATMixer(ATMixerNum).OARequirementsPtr,
5343 40 : state.dataSingleDuct->SysATMixer(ATMixerNum).ZoneNum,
5344 : false,
5345 : false);
5346 40 : state.dataSingleDuct->SysATMixer(ATMixerNum).NoOAFlowInputFromUser = false;
5347 : }
5348 : }
5349 : }
5350 : } else {
5351 0 : ShowWarningError(state,
5352 0 : format("{}is blank and there is no Sizing:Zone for the same zone. The mixer outdoor airflow rate is set to zero.",
5353 0 : state.dataIPShortCut->cAlphaFieldNames(8)));
5354 0 : state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate = 0.0;
5355 : }
5356 : }
5357 59 : state.dataSingleDuct->SysATMixer(ATMixerNum).MassFlowRateMaxAvail =
5358 59 : state.dataSingleDuct->SysATMixer(ATMixerNum).DesignPrimaryAirVolRate * state.dataEnvrn->StdRhoAir;
5359 : }
5360 :
5361 203 : if (ErrorsFound) {
5362 0 : ShowFatalError(state, format("{}Errors found in input. Program terminates.", RoutineName));
5363 : }
5364 : }
5365 :
5366 1862187 : void AirTerminalMixerData::InitATMixer(EnergyPlusData &state, bool const FirstHVACIteration)
5367 : {
5368 : // Purpose: Initialize the AirTerminalMixers data structure with node data
5369 1862187 : if (this->OneTimeInitFlag) {
5370 : {
5371 59 : auto &thisADU(state.dataDefineEquipment->AirDistUnit(this->ADUNum));
5372 : {
5373 59 : auto &thisZoneEqConfig(state.dataZoneEquip->ZoneEquipConfig(thisADU.ZoneEqNum));
5374 118 : for (int SupAirIn = 1; SupAirIn <= thisZoneEqConfig.NumInletNodes; ++SupAirIn) {
5375 59 : if (this->ZoneInletNode == thisZoneEqConfig.InletNode(SupAirIn)) {
5376 59 : thisZoneEqConfig.AirDistUnitCool(SupAirIn).InNode = this->PriInNode;
5377 59 : thisZoneEqConfig.AirDistUnitCool(SupAirIn).OutNode = this->MixedAirOutNode;
5378 59 : thisZoneEqConfig.AirDistUnitHeat(SupAirIn).InNode = this->PriInNode;
5379 59 : thisZoneEqConfig.AirDistUnitHeat(SupAirIn).OutNode = this->MixedAirOutNode;
5380 59 : thisADU.TermUnitSizingNum = thisZoneEqConfig.AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
5381 59 : this->CtrlZoneInNodeIndex = SupAirIn;
5382 : {
5383 59 : auto &thisTermUnitSizingData(state.dataSize->TermUnitSizing(thisADU.TermUnitSizingNum));
5384 59 : thisTermUnitSizingData.ADUName = thisADU.Name;
5385 : // Fill TermUnitSizing with specs from DesignSpecification:AirTerminal:Sizing if there is one attached to this
5386 : // terminal unit
5387 59 : if (thisADU.AirTerminalSizingSpecIndex > 0) {
5388 : {
5389 0 : auto const &thisAirTermSizingSpec(state.dataSize->AirTerminalSizingSpec(thisADU.AirTerminalSizingSpecIndex));
5390 0 : thisTermUnitSizingData.SpecDesCoolSATRatio = thisAirTermSizingSpec.DesCoolSATRatio;
5391 0 : thisTermUnitSizingData.SpecDesHeatSATRatio = thisAirTermSizingSpec.DesHeatSATRatio;
5392 0 : thisTermUnitSizingData.SpecDesSensCoolingFrac = thisAirTermSizingSpec.DesSensCoolingFrac;
5393 0 : thisTermUnitSizingData.SpecDesSensHeatingFrac = thisAirTermSizingSpec.DesSensHeatingFrac;
5394 0 : thisTermUnitSizingData.SpecMinOAFrac = thisAirTermSizingSpec.MinOAFrac;
5395 : }
5396 : }
5397 : }
5398 : }
5399 : }
5400 : }
5401 : }
5402 59 : this->OneTimeInitFlag = false;
5403 : }
5404 :
5405 : // Keep trying until we find it, the airloopnum, that is
5406 1862187 : if (this->OneTimeInitFlag2) {
5407 270 : this->AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(state.dataDefineEquipment->AirDistUnit(this->ADUNum).ZoneEqNum)
5408 270 : .InletNodeAirLoopNum(this->CtrlZoneInNodeIndex);
5409 270 : state.dataDefineEquipment->AirDistUnit(this->ADUNum).AirLoopNum = this->AirLoopNum;
5410 270 : if (this->AirLoopNum > 0) {
5411 59 : this->OneTimeInitFlag2 = false;
5412 : }
5413 : }
5414 :
5415 : // Every iteration
5416 1862187 : Real64 mDotFromOARequirement(0.0);
5417 1862187 : Real64 vDotOAReq(0.0);
5418 1862187 : if (!this->NoOAFlowInputFromUser) {
5419 1862187 : Real64 airLoopOAFrac(0.0);
5420 1862187 : bool UseOccSchFlag = false;
5421 1862187 : if (this->OAPerPersonMode == DataZoneEquipment::PerPersonVentRateMode::DCVByCurrentLevel) {
5422 1862187 : UseOccSchFlag = true;
5423 : }
5424 1862187 : if (this->AirLoopNum > 0) {
5425 1861976 : airLoopOAFrac = state.dataAirLoop->AirLoopFlow(this->AirLoopNum).OAFrac;
5426 1861976 : if (airLoopOAFrac > 0.0) {
5427 1590720 : vDotOAReq = DataSizing::calcDesignSpecificationOutdoorAir(state, this->OARequirementsPtr, this->ZoneNum, UseOccSchFlag, true);
5428 1590720 : mDotFromOARequirement = vDotOAReq * state.dataEnvrn->StdRhoAir / airLoopOAFrac;
5429 : } else {
5430 271256 : mDotFromOARequirement = state.dataLoopNodes->Node(this->PriInNode).MassFlowRate;
5431 : }
5432 : }
5433 1862187 : if (FirstHVACIteration) {
5434 903307 : state.dataLoopNodes->Node(this->PriInNode).MassFlowRate = mDotFromOARequirement;
5435 903307 : state.dataLoopNodes->Node(this->PriInNode).MassFlowRateMaxAvail = this->MassFlowRateMaxAvail;
5436 903307 : state.dataLoopNodes->Node(this->PriInNode).MassFlowRateMinAvail = 0.0;
5437 : } else {
5438 958880 : state.dataLoopNodes->Node(this->PriInNode).MassFlowRate = mDotFromOARequirement;
5439 :
5440 958880 : state.dataLoopNodes->Node(this->PriInNode).MassFlowRate =
5441 958880 : min(state.dataLoopNodes->Node(this->PriInNode).MassFlowRate, state.dataLoopNodes->Node(this->PriInNode).MassFlowRateMaxAvail);
5442 958880 : state.dataLoopNodes->Node(this->PriInNode).MassFlowRate =
5443 958880 : max(state.dataLoopNodes->Node(this->PriInNode).MassFlowRate, state.dataLoopNodes->Node(this->PriInNode).MassFlowRateMinAvail);
5444 958880 : state.dataLoopNodes->Node(this->PriInNode).MassFlowRate =
5445 958880 : max(state.dataLoopNodes->Node(this->PriInNode).MassFlowRate, state.dataLoopNodes->Node(this->PriInNode).MassFlowRateMin);
5446 : }
5447 : }
5448 1862187 : if (this->type == HVAC::MixerType::InletSide) {
5449 1193352 : state.dataLoopNodes->Node(this->PriInNode).MassFlowRate =
5450 1193352 : min(state.dataLoopNodes->Node(this->PriInNode).MassFlowRate, state.dataLoopNodes->Node(this->MixedAirOutNode).MassFlowRate);
5451 : }
5452 1862187 : }
5453 :
5454 1862128 : void CalcATMixer(EnergyPlusData &state, int const SysNum)
5455 : {
5456 :
5457 : // SUBROUTINE INFORMATION:
5458 : // DATE WRITTEN March 2012
5459 :
5460 : // PURPOSE OF THIS SUBROUTINE
5461 : // Calculate the mixed air flow and conditions in the air terminal mixer
5462 :
5463 1862128 : auto &atMixer = state.dataSingleDuct->SysATMixer(SysNum);
5464 1862128 : auto &priInNode = state.dataLoopNodes->Node(atMixer.PriInNode);
5465 1862128 : auto &secInNode = state.dataLoopNodes->Node(atMixer.SecInNode);
5466 1862128 : auto &mixedAirOutNode = state.dataLoopNodes->Node(atMixer.MixedAirOutNode);
5467 :
5468 1862128 : Real64 MixedAirMassFlowRate =
5469 1862128 : (atMixer.type == HVAC::MixerType::SupplySide) ? secInNode.MassFlowRate + priInNode.MassFlowRate : mixedAirOutNode.MassFlowRate;
5470 :
5471 1862128 : if (atMixer.type == HVAC::MixerType::InletSide) {
5472 : // for inlet side mixer, the mixed air flow has been set, but we don't know the secondary flow
5473 1193317 : secInNode.MassFlowRate = max(MixedAirMassFlowRate - priInNode.MassFlowRate, 0.0);
5474 1193317 : if (std::abs(priInNode.MassFlowRate + secInNode.MassFlowRate - MixedAirMassFlowRate) > SmallMassFlow) {
5475 0 : ShowSevereError(state, format("CalcATMixer: Invalid mass flow rates in AirTerminal:SingleDuct:Mixer={}", atMixer.Name));
5476 0 : ShowContinueErrorTimeStamp(state,
5477 0 : format("Primary mass flow rate={:.6R}Secondary mass flow rate={:.6R}Mixed mass flow rate={:.6R}",
5478 0 : priInNode.MassFlowRate,
5479 0 : secInNode.MassFlowRate,
5480 : MixedAirMassFlowRate));
5481 0 : ShowFatalError(state, "Simulation terminates.");
5482 : }
5483 : }
5484 : // now calculate the mixed (outlet) conditions
5485 1862128 : if ((atMixer.MixedAirMassFlowRate = MixedAirMassFlowRate) > 0.0) {
5486 1730111 : Real64 MixedAirEnthalpy = (secInNode.MassFlowRate * secInNode.Enthalpy + priInNode.MassFlowRate * priInNode.Enthalpy) / MixedAirMassFlowRate;
5487 1730111 : Real64 MixedAirHumRat = (secInNode.MassFlowRate * secInNode.HumRat + priInNode.MassFlowRate * priInNode.HumRat) / MixedAirMassFlowRate;
5488 : // Mixed air temperature is calculated from the mixed air enthalpy and humidity ratio.
5489 1730111 : atMixer.MixedAirTemp = Psychrometrics::PsyTdbFnHW(MixedAirEnthalpy, MixedAirHumRat);
5490 1730111 : atMixer.MixedAirEnthalpy = MixedAirEnthalpy;
5491 1730111 : atMixer.MixedAirHumRat = MixedAirHumRat;
5492 : } else {
5493 132017 : atMixer.MixedAirEnthalpy = priInNode.Enthalpy;
5494 132017 : atMixer.MixedAirHumRat = priInNode.HumRat;
5495 132017 : atMixer.MixedAirTemp = priInNode.Temp;
5496 : }
5497 1862128 : }
5498 :
5499 1862128 : void UpdateATMixer(EnergyPlusData &state, int const SysNum)
5500 : {
5501 :
5502 : // SUBROUTINE INFORMATION:
5503 : // DATE WRITTEN March 2012
5504 :
5505 : // PURPOSE OF THIS SUBROUTINE
5506 : // Move the results of CalcATMixer to the affected nodes
5507 :
5508 : // Using/Aliasing
5509 : using namespace DataLoopNode;
5510 :
5511 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5512 1862128 : int PriInNode = state.dataSingleDuct->SysATMixer(SysNum).PriInNode;
5513 1862128 : int SecInNode = state.dataSingleDuct->SysATMixer(SysNum).SecInNode;
5514 1862128 : int MixedAirOutNode = state.dataSingleDuct->SysATMixer(SysNum).MixedAirOutNode;
5515 :
5516 : // mixed air data
5517 1862128 : state.dataLoopNodes->Node(MixedAirOutNode).Temp = state.dataSingleDuct->SysATMixer(SysNum).MixedAirTemp;
5518 1862128 : state.dataLoopNodes->Node(MixedAirOutNode).HumRat = state.dataSingleDuct->SysATMixer(SysNum).MixedAirHumRat;
5519 1862128 : state.dataLoopNodes->Node(MixedAirOutNode).Enthalpy = state.dataSingleDuct->SysATMixer(SysNum).MixedAirEnthalpy;
5520 1862128 : state.dataLoopNodes->Node(MixedAirOutNode).Press = state.dataSingleDuct->SysATMixer(SysNum).MixedAirPressure;
5521 1862128 : state.dataLoopNodes->Node(MixedAirOutNode).MassFlowRate = state.dataSingleDuct->SysATMixer(SysNum).MixedAirMassFlowRate;
5522 :
5523 1862128 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
5524 326026 : if (state.dataSingleDuct->SysATMixer(SysNum).MixedAirMassFlowRate <= HVAC::VerySmallMassFlow) {
5525 9396 : state.dataLoopNodes->Node(MixedAirOutNode).CO2 = state.dataLoopNodes->Node(PriInNode).CO2;
5526 : } else {
5527 316630 : state.dataLoopNodes->Node(MixedAirOutNode).CO2 =
5528 316630 : (state.dataLoopNodes->Node(SecInNode).MassFlowRate * state.dataLoopNodes->Node(SecInNode).CO2 +
5529 316630 : state.dataLoopNodes->Node(PriInNode).MassFlowRate * state.dataLoopNodes->Node(PriInNode).CO2) /
5530 316630 : state.dataLoopNodes->Node(MixedAirOutNode).MassFlowRate;
5531 : }
5532 : }
5533 :
5534 1862128 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
5535 0 : if (state.dataSingleDuct->SysATMixer(SysNum).MixedAirMassFlowRate <= HVAC::VerySmallMassFlow) {
5536 0 : state.dataLoopNodes->Node(MixedAirOutNode).GenContam = state.dataLoopNodes->Node(PriInNode).GenContam;
5537 : } else {
5538 0 : state.dataLoopNodes->Node(MixedAirOutNode).GenContam =
5539 0 : (state.dataLoopNodes->Node(SecInNode).MassFlowRate * state.dataLoopNodes->Node(SecInNode).GenContam +
5540 0 : state.dataLoopNodes->Node(PriInNode).MassFlowRate * state.dataLoopNodes->Node(PriInNode).GenContam) /
5541 0 : state.dataLoopNodes->Node(MixedAirOutNode).MassFlowRate;
5542 : }
5543 : }
5544 :
5545 : // update ADU flow data - because SimATMixer is called from the various zone equipment so the updates in SimZoneAirLoopEquipment won't work
5546 1862128 : int aduNum = state.dataSingleDuct->SysATMixer(SysNum).ADUNum;
5547 1862128 : state.dataDefineEquipment->AirDistUnit(aduNum).MassFlowRateTU = state.dataLoopNodes->Node(PriInNode).MassFlowRate;
5548 1862128 : state.dataDefineEquipment->AirDistUnit(aduNum).MassFlowRateZSup = state.dataLoopNodes->Node(PriInNode).MassFlowRate;
5549 1862128 : state.dataDefineEquipment->AirDistUnit(aduNum).MassFlowRateSup = state.dataLoopNodes->Node(PriInNode).MassFlowRate;
5550 1862128 : }
5551 :
5552 931 : void GetATMixer(EnergyPlusData &state,
5553 : std::string const &ZoneEquipName, // zone unit name name
5554 : std::string &ATMixerName, // air terminal mixer name
5555 : int &ATMixerNum, // air terminal mixer index
5556 : HVAC::MixerType &ATMixerType, // air teminal mixer type
5557 : int &ATMixerPriNode, // air terminal mixer primary air node number
5558 : int &ATMixerSecNode, // air terminal mixer secondary air node number
5559 : int &ATMixerOutNode, // air terminal mixer outlet air node number
5560 : int const ZoneEquipOutletNode // zone equipment outlet node (used with inlet side mixers)
5561 : )
5562 : {
5563 :
5564 : // SUBROUTINE INFORMATION:
5565 : // AUTHOR Fred Buhl
5566 : // DATE WRITTEN April 2012
5567 :
5568 : // PURPOSE OF THIS SUBROUTINE:
5569 : // This subroutine gets: 1) the index of the named AT Mixer in the SysATMixer data array
5570 : // 2) the node number of the primary air inlet node of the AT Mixer
5571 : // 3) set the AT Mixer ultimate zone inlet node
5572 :
5573 : int ATMixerIndex; // local air terminal mixer index
5574 :
5575 931 : if (state.dataSingleDuct->GetATMixerFlag) {
5576 193 : GetATMixers(state);
5577 193 : state.dataSingleDuct->GetATMixerFlag = false;
5578 : }
5579 :
5580 931 : if (state.dataSingleDuct->NumATMixers <= 0) {
5581 871 : ATMixerNum = 0;
5582 871 : ATMixerName = "";
5583 871 : ATMixerPriNode = 0;
5584 871 : ATMixerSecNode = 0;
5585 871 : ATMixerOutNode = 0;
5586 871 : ATMixerType = HVAC::MixerType::Invalid;
5587 871 : return;
5588 : }
5589 :
5590 60 : ATMixerIndex = Util::FindItemInList(ZoneEquipName, state.dataSingleDuct->SysATMixer, &AirTerminalMixerData::ZoneHVACUnitName);
5591 60 : if (ATMixerIndex > 0) {
5592 59 : ATMixerNum = ATMixerIndex;
5593 59 : ATMixerName = state.dataSingleDuct->SysATMixer(ATMixerIndex).Name;
5594 59 : ATMixerPriNode = state.dataSingleDuct->SysATMixer(ATMixerIndex).PriInNode;
5595 59 : ATMixerSecNode = state.dataSingleDuct->SysATMixer(ATMixerIndex).SecInNode;
5596 59 : ATMixerOutNode = state.dataSingleDuct->SysATMixer(ATMixerIndex).MixedAirOutNode;
5597 59 : ATMixerType = state.dataSingleDuct->SysATMixer(ATMixerIndex).type;
5598 59 : if (ATMixerType == HVAC::MixerType::InletSide) {
5599 35 : state.dataSingleDuct->SysATMixer(ATMixerIndex).ZoneInletNode = ZoneEquipOutletNode;
5600 : } else {
5601 24 : state.dataSingleDuct->SysATMixer(ATMixerIndex).ZoneInletNode = ATMixerOutNode;
5602 : }
5603 59 : state.dataSingleDuct->SysATMixer(ATMixerNum).InitATMixer(state, false);
5604 : } else {
5605 1 : ATMixerNum = 0;
5606 1 : ATMixerName = "";
5607 1 : ATMixerPriNode = 0;
5608 1 : ATMixerSecNode = 0;
5609 1 : ATMixerOutNode = 0;
5610 1 : ATMixerType = HVAC::MixerType::Invalid;
5611 : }
5612 : }
5613 :
5614 93 : void setATMixerSizingProperties(EnergyPlusData &state,
5615 : int const inletATMixerIndex, // index to ATMixer at inlet of zone equipment
5616 : int const controlledZoneNum, // controlled zone number
5617 : int const curZoneEqNum // current zone equipment being simulated
5618 : )
5619 : {
5620 :
5621 93 : if (inletATMixerIndex == 0) {
5622 37 : return; // protect this function from bad inputs
5623 : }
5624 93 : if (controlledZoneNum == 0) {
5625 0 : return;
5626 : }
5627 93 : if (curZoneEqNum == 0) {
5628 0 : return;
5629 : }
5630 93 : if (state.dataSingleDuct->SysATMixer(inletATMixerIndex).type == HVAC::MixerType::Invalid) {
5631 0 : return;
5632 : }
5633 :
5634 : // ATMixer properties only affect coil sizing when the mixer is on the inlet side of zone equipment
5635 93 : if (state.dataSingleDuct->SysATMixer(inletATMixerIndex).type == HVAC::MixerType::SupplySide) {
5636 : // check if user has selected No to account for DOAS system
5637 37 : if (state.dataSize->FinalZoneSizing.allocated() && state.dataSingleDuct->SysATMixer(inletATMixerIndex).printWarning) {
5638 24 : auto const &finalZoneSizing = state.dataSize->FinalZoneSizing(curZoneEqNum);
5639 24 : if (!finalZoneSizing.AccountForDOAS && finalZoneSizing.DOASControlStrategy != DOASControl::NeutralSup) {
5640 2 : ShowWarningError(state, format("AirTerminal:SingleDuct:Mixer: {}", state.dataSingleDuct->SysATMixer(inletATMixerIndex).Name));
5641 4 : ShowContinueError(
5642 : state,
5643 : " Supply side Air Terminal Mixer does not adjust zone equipment coil sizing and may result in inappropriately sized coils.");
5644 4 : ShowContinueError(
5645 : state,
5646 4 : format(" Set Account for Dedicated Outdoor Air System = Yes in Sizing:Zone object for zone = {}", finalZoneSizing.ZoneName));
5647 : }
5648 24 : state.dataSingleDuct->SysATMixer(inletATMixerIndex).printWarning = false;
5649 : }
5650 37 : return; // do nothing else if this is a supply side ATMixer
5651 : }
5652 : // check if user has selected Yes to account for DOAS system
5653 56 : if (state.dataSize->FinalZoneSizing.allocated() && state.dataSingleDuct->SysATMixer(inletATMixerIndex).printWarning) {
5654 56 : auto const &finalZoneSizing = state.dataSize->FinalZoneSizing(curZoneEqNum);
5655 56 : if (finalZoneSizing.AccountForDOAS && finalZoneSizing.DOASControlStrategy != DOASControl::NeutralSup) {
5656 0 : ShowWarningError(state, format("AirTerminal:SingleDuct:Mixer: {}", state.dataSingleDuct->SysATMixer(inletATMixerIndex).Name));
5657 0 : ShowContinueError(state, " Inlet side Air Terminal Mixer automatically adjusts zone equipment coil sizing.");
5658 0 : ShowContinueError(
5659 0 : state, format(" Set Account for Dedicated Outdoor Air System = No in Sizing:Zone object for zone = {}", finalZoneSizing.ZoneName));
5660 0 : state.dataSingleDuct->SysATMixer(inletATMixerIndex).printWarning = false;
5661 : }
5662 : }
5663 :
5664 : // proceed to set ATMixer properties used for sizing coils
5665 :
5666 : int airLoopIndex = // find air loop associated with ATMixer
5667 56 : state.dataZoneEquip->ZoneEquipConfig(controlledZoneNum)
5668 56 : .InletNodeAirLoopNum(state.dataSingleDuct->SysATMixer(inletATMixerIndex).CtrlZoneInNodeIndex);
5669 :
5670 : // must be a system sizing run or calculations are not possible
5671 56 : bool SizingDesRunThisAirSys = false; // Sizing:System object found flag
5672 56 : CheckThisAirSystemForSizing(state, airLoopIndex, SizingDesRunThisAirSys); // check for Sizing:System object
5673 :
5674 56 : if (SizingDesRunThisAirSys) {
5675 56 : auto &finalSysSizing = state.dataSize->FinalSysSizing(airLoopIndex);
5676 56 : auto &zoneEqSizing = state.dataSize->ZoneEqSizing(curZoneEqNum);
5677 :
5678 : // set ATMixer outlet air flow rate in ZoneEqSizing array for ATMixer. If this value > 0, then the Sizer will know an ATMixer exists
5679 56 : zoneEqSizing.ATMixerVolFlow = state.dataSingleDuct->SysATMixer(inletATMixerIndex).DesignPrimaryAirVolRate;
5680 :
5681 : // If air loop has heating coil use SA conditions, else if OA sys has coils then use precool conditions, else use OA conditions
5682 56 : if (state.dataAirSystemsData->PrimaryAirSystems(airLoopIndex).CentralHeatCoilExists) {
5683 : // if central heating coil exists, ATMixer outlet is assumed to be at supply air conditions described in sizing input
5684 5 : zoneEqSizing.ATMixerHeatPriDryBulb = finalSysSizing.HeatSupTemp;
5685 5 : zoneEqSizing.ATMixerHeatPriHumRat = finalSysSizing.HeatSupHumRat;
5686 51 : } else if (state.dataAirSystemsData->PrimaryAirSystems(airLoopIndex).NumOAHeatCoils > 0) {
5687 : // if no central heating coil exists and an outdoor air coil does exist, then ATMixer outlet is mixture of preheat and return
5688 0 : if (finalSysSizing.DesMainVolFlow == 0.0) { // protect divide by 0
5689 : // doesn't matter, just pick a condition
5690 0 : zoneEqSizing.ATMixerHeatPriDryBulb = finalSysSizing.PreheatTemp;
5691 0 : zoneEqSizing.ATMixerHeatPriHumRat = finalSysSizing.PreheatHumRat;
5692 : } else {
5693 : // mix preheat condition with return air condition based on OA frac. OA frac should nearly always be 1.
5694 : // OA frac is based on air loop fraction, not ATMixer flow fraction since air loop can serve multiple ATMixers
5695 0 : Real64 OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesMainVolFlow;
5696 0 : OutAirFrac = min(1.0, max(0.0, OutAirFrac));
5697 :
5698 : // calculate humrat based on simple mixing
5699 0 : Real64 CoilInHumRatForSizing = OutAirFrac * finalSysSizing.PreheatHumRat + (1 - OutAirFrac) * finalSysSizing.HeatRetHumRat;
5700 :
5701 : // calculate enthalpy based on simple mixing
5702 : Real64 CoilInEnthalpyForSizing =
5703 0 : OutAirFrac * Psychrometrics::PsyHFnTdbW(finalSysSizing.PreheatTemp, finalSysSizing.PreheatHumRat) +
5704 0 : (1 - OutAirFrac) * Psychrometrics::PsyHFnTdbW(finalSysSizing.HeatRetTemp, finalSysSizing.HeatRetHumRat);
5705 :
5706 : // back calculate temperature based on humrat and enthalpy state points
5707 0 : Real64 CoilInTempForSizing = Psychrometrics::PsyTdbFnHW(CoilInEnthalpyForSizing, CoilInHumRatForSizing);
5708 :
5709 0 : zoneEqSizing.ATMixerHeatPriDryBulb = CoilInTempForSizing;
5710 0 : zoneEqSizing.ATMixerHeatPriHumRat = CoilInHumRatForSizing;
5711 : }
5712 : } else {
5713 : // else no coils exist in air loop so mix OA condition with return air condition
5714 51 : if (finalSysSizing.DesMainVolFlow == 0.0) { // protect divide by 0
5715 : // doesn't matter, just pick a condition
5716 0 : zoneEqSizing.ATMixerHeatPriDryBulb = finalSysSizing.HeatOutTemp;
5717 0 : zoneEqSizing.ATMixerHeatPriHumRat = finalSysSizing.HeatOutHumRat;
5718 : } else {
5719 : // OA frac is based on air loop fraction, not ATMixer flow fraction since air loop can serve multiple ATMixers
5720 51 : Real64 OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesMainVolFlow;
5721 51 : OutAirFrac = min(1.0, max(0.0, OutAirFrac));
5722 :
5723 : // calculate humrat based on simple mixing
5724 51 : Real64 CoilInHumRatForSizing = OutAirFrac * finalSysSizing.HeatOutHumRat + (1 - OutAirFrac) * finalSysSizing.HeatRetHumRat;
5725 :
5726 : // calculate enthalpy based on simple mixing
5727 : Real64 CoilInEnthalpyForSizing =
5728 51 : OutAirFrac * Psychrometrics::PsyHFnTdbW(finalSysSizing.HeatOutTemp, finalSysSizing.HeatOutHumRat) +
5729 51 : (1 - OutAirFrac) * Psychrometrics::PsyHFnTdbW(finalSysSizing.HeatRetTemp, finalSysSizing.HeatRetHumRat);
5730 :
5731 : // back calculate temperature based on humrat and enthalpy state points
5732 51 : Real64 CoilInTempForSizing = Psychrometrics::PsyTdbFnHW(CoilInEnthalpyForSizing, CoilInHumRatForSizing);
5733 :
5734 51 : zoneEqSizing.ATMixerHeatPriDryBulb = CoilInTempForSizing;
5735 51 : zoneEqSizing.ATMixerHeatPriHumRat = CoilInHumRatForSizing;
5736 : }
5737 : }
5738 :
5739 : // If air loop has cooling coil use SA conditions, else if OA sys has coils then use precool conditions, else use OA conditions
5740 56 : if (state.dataAirSystemsData->PrimaryAirSystems(airLoopIndex).CentralCoolCoilExists) {
5741 : // if central cooling coil exists, ATMixer outlet is assumed to be at supply air conditions described in sizing input
5742 5 : zoneEqSizing.ATMixerCoolPriDryBulb = finalSysSizing.CoolSupTemp;
5743 5 : zoneEqSizing.ATMixerCoolPriHumRat = finalSysSizing.CoolSupHumRat;
5744 51 : } else if (state.dataAirSystemsData->PrimaryAirSystems(airLoopIndex).NumOACoolCoils > 0) {
5745 : // if no central cooling coil exists and an outdoor air coil does exist, then ATMixer outlet is mixture of precool and return
5746 0 : if (finalSysSizing.DesMainVolFlow == 0.0) { // protect divide by 0
5747 : // doesn't matter, just pick a condition
5748 0 : zoneEqSizing.ATMixerCoolPriDryBulb = finalSysSizing.PrecoolTemp;
5749 0 : zoneEqSizing.ATMixerCoolPriHumRat = finalSysSizing.PrecoolHumRat;
5750 : } else {
5751 : // mix precool condition with return air condition based on OA frac. OA frac should nearly always be 1.
5752 : // OA frac is based on air loop fraction, not ATMixer flow fraction since air loop can serve multiple ATMixers
5753 0 : Real64 OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesMainVolFlow;
5754 0 : OutAirFrac = min(1.0, max(0.0, OutAirFrac));
5755 :
5756 : // calculate humrat based on simple mixing
5757 0 : Real64 CoilInHumRatForSizing = OutAirFrac * finalSysSizing.PrecoolHumRat + (1 - OutAirFrac) * finalSysSizing.RetHumRatAtCoolPeak;
5758 :
5759 : // calculate enthalpy based on simple mixing
5760 : Real64 CoilInEnthalpyForSizing =
5761 0 : OutAirFrac * Psychrometrics::PsyHFnTdbW(finalSysSizing.PrecoolTemp, finalSysSizing.PrecoolHumRat) +
5762 0 : (1 - OutAirFrac) * Psychrometrics::PsyHFnTdbW(finalSysSizing.RetTempAtCoolPeak, finalSysSizing.RetHumRatAtCoolPeak);
5763 :
5764 : // back calculate temperature based on humrat and enthalpy state points
5765 0 : Real64 CoilInTempForSizing = Psychrometrics::PsyTdbFnHW(CoilInEnthalpyForSizing, CoilInHumRatForSizing);
5766 :
5767 0 : zoneEqSizing.ATMixerCoolPriDryBulb = CoilInTempForSizing;
5768 0 : zoneEqSizing.ATMixerCoolPriHumRat = CoilInHumRatForSizing;
5769 : }
5770 : } else {
5771 : // else no coils exist in air loop so mix OA condition with return air condition
5772 51 : if (finalSysSizing.DesMainVolFlow == 0.0) { // protect divide by 0
5773 : // doesn't matter, just pick a condition
5774 0 : zoneEqSizing.ATMixerCoolPriDryBulb = finalSysSizing.OutTempAtCoolPeak;
5775 0 : zoneEqSizing.ATMixerCoolPriHumRat = finalSysSizing.OutHumRatAtCoolPeak;
5776 : } else {
5777 : // OA frac is based on air loop fraction, not ATMixer flow fraction since air loop can serve multiple ATMixers
5778 51 : Real64 OutAirFrac = finalSysSizing.DesOutAirVolFlow / finalSysSizing.DesMainVolFlow;
5779 51 : OutAirFrac = min(1.0, max(0.0, OutAirFrac));
5780 :
5781 : // calculate humrat based on simple mixing
5782 51 : Real64 CoilInHumRatForSizing =
5783 51 : OutAirFrac * finalSysSizing.OutHumRatAtCoolPeak + (1 - OutAirFrac) * finalSysSizing.RetHumRatAtCoolPeak;
5784 :
5785 : // calculate enthalpy based on simple mixing
5786 : Real64 CoilInEnthalpyForSizing =
5787 51 : OutAirFrac * Psychrometrics::PsyHFnTdbW(finalSysSizing.OutTempAtCoolPeak, finalSysSizing.OutHumRatAtCoolPeak) +
5788 51 : (1 - OutAirFrac) * Psychrometrics::PsyHFnTdbW(finalSysSizing.RetTempAtCoolPeak, finalSysSizing.RetHumRatAtCoolPeak);
5789 :
5790 : // back calculate temperature based on humrat and enthalpy state points
5791 51 : Real64 CoilInTempForSizing = Psychrometrics::PsyTdbFnHW(CoilInEnthalpyForSizing, CoilInHumRatForSizing);
5792 :
5793 51 : zoneEqSizing.ATMixerCoolPriDryBulb = CoilInTempForSizing;
5794 51 : zoneEqSizing.ATMixerCoolPriHumRat = CoilInHumRatForSizing;
5795 : }
5796 : }
5797 :
5798 : } else {
5799 : // warn user that system sizing is needed to size coils when AT Mixer is used ?
5800 : // if there were a message here then this function should only be called when SizingDesRunThisZone is true
5801 : }
5802 : }
5803 :
5804 37322114 : void SingleDuctAirTerminal::CalcOutdoorAirVolumeFlowRate(EnergyPlusData &state)
5805 : {
5806 : // calculates zone outdoor air volume flow rate using the supply air flow rate and OA fraction
5807 37322114 : if (this->AirLoopNum > 0) {
5808 37312860 : this->OutdoorAirFlowRate =
5809 37312860 : (this->sd_airterminalOutlet.AirMassFlowRate / state.dataEnvrn->StdRhoAir) * state.dataAirLoop->AirLoopFlow(this->AirLoopNum).OAFrac;
5810 : } else {
5811 9254 : this->OutdoorAirFlowRate = 0.0;
5812 : }
5813 37322114 : }
5814 :
5815 3597 : void SingleDuctAirTerminal::reportTerminalUnit(EnergyPlusData &state)
5816 : {
5817 : // populate the predefined equipment summary report related to air terminals
5818 3597 : auto &orp = state.dataOutRptPredefined;
5819 3597 : auto &adu = state.dataDefineEquipment->AirDistUnit(this->ADUNum);
5820 3597 : if (!state.dataSize->TermUnitFinalZoneSizing.empty()) {
5821 3082 : auto &sizing = state.dataSize->TermUnitFinalZoneSizing(adu.TermUnitSizingNum);
5822 3082 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlow, adu.Name, sizing.DesCoolVolFlowMin);
5823 3082 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinOutdoorFlow, adu.Name, sizing.MinOA);
5824 3082 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSupCoolingSP, adu.Name, sizing.CoolDesTemp);
5825 3082 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSupHeatingSP, adu.Name, sizing.HeatDesTemp);
5826 3082 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatingCap, adu.Name, sizing.DesHeatLoad);
5827 3082 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolingCap, adu.Name, sizing.DesCoolLoad);
5828 : }
5829 3597 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermTypeInp, adu.Name, this->sysType);
5830 3597 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermPrimFlow, adu.Name, this->MaxAirVolFlowRate);
5831 3597 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSecdFlow, adu.Name, "n/a");
5832 3597 : if (this->zoneMinAirFracSched != nullptr) {
5833 163 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlowSch, adu.Name, this->zoneMinAirFracSched->Name);
5834 : } else {
5835 3434 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlowSch, adu.Name, "n/a");
5836 : }
5837 3597 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMaxFlowReh, adu.Name, this->MaxAirVolFlowRateDuringReheat);
5838 3597 : std::string schName = "n/a";
5839 3597 : if (this->OARequirementsPtr > 0) {
5840 422 : auto const *minOASched = state.dataSize->OARequirements(this->OARequirementsPtr).oaFlowFracSched;
5841 422 : if (minOASched != nullptr) {
5842 422 : schName = minOASched->Name;
5843 : }
5844 : }
5845 3597 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinOAflowSch, adu.Name, schName);
5846 3597 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatCoilType, adu.Name, this->ReheatComp);
5847 3597 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolCoilType, adu.Name, "n/a");
5848 3597 : if (this->fanType != HVAC::FanType::Invalid) {
5849 8 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanType, adu.Name, HVAC::fanTypeNames[(int)this->fanType]);
5850 : } else {
5851 3589 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanType, adu.Name, "n/a");
5852 : }
5853 3597 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanName, adu.Name, this->FanName);
5854 3597 : }
5855 :
5856 : // End of Reporting subroutines for the Sys Module
5857 : // *****************************************************************************
5858 :
5859 : } // namespace EnergyPlus::SingleDuct
|