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