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