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 : // ObjexxFCL Headers
49 : #include <ObjexxFCL/Array.functions.hh>
50 : #include <ObjexxFCL/Fmath.hh>
51 :
52 : // EnergyPlus Headers
53 : #include <EnergyPlus/Autosizing/Base.hh>
54 : #include <EnergyPlus/BranchNodeConnections.hh>
55 : #include <EnergyPlus/Data/EnergyPlusData.hh>
56 : #include <EnergyPlus/DataContaminantBalance.hh>
57 : #include <EnergyPlus/DataDefineEquip.hh>
58 : #include <EnergyPlus/DataEnvironment.hh>
59 : #include <EnergyPlus/DataHVACGlobals.hh>
60 : #include <EnergyPlus/DataHeatBalance.hh>
61 : #include <EnergyPlus/DataLoopNode.hh>
62 : #include <EnergyPlus/DataSizing.hh>
63 : #include <EnergyPlus/DataZoneEquipment.hh>
64 : #include <EnergyPlus/General.hh>
65 : #include <EnergyPlus/GeneralRoutines.hh>
66 : #include <EnergyPlus/GlobalNames.hh>
67 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
68 : #include <EnergyPlus/NodeInputManager.hh>
69 : #include <EnergyPlus/Psychrometrics.hh>
70 : #include <EnergyPlus/ScheduleManager.hh>
71 : #include <EnergyPlus/UnitarySystem.hh>
72 : #include <EnergyPlus/UtilityRoutines.hh>
73 : #include <EnergyPlus/ZoneEquipmentManager.hh>
74 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
75 :
76 : namespace EnergyPlus::DataZoneEquipment {
77 :
78 : // MODULE INFORMATION
79 : // AUTHOR: Russ Taylor
80 : // DATE WRITTEN: June 1998
81 :
82 : // PURPOSE OF THIS MODULE:
83 : // This module contains variable declarations for zone equipment configuration data
84 :
85 : Array1D_string const cValidSysAvailManagerCompTypes(NumValidSysAvailZoneComponents,
86 : {"ZoneHVAC:FourPipeFanCoil",
87 : "ZoneHVAC:PackagedTerminalHeatPump",
88 : "ZoneHVAC:PackagedTerminalAirConditioner",
89 : "ZoneHVAC:WaterToAirHeatPump",
90 : "ZoneHVAC:WindowAirConditioner",
91 : "ZoneHVAC:UnitHeater",
92 : "ZoneHVAC:UnitVentilator",
93 : "ZoneHVAC:EnergyRecoveryVentilator",
94 : "ZoneHVAC:VentilatedSlab",
95 : "ZoneHVAC:OutdoorAirUnit",
96 : "ZoneHVAC:TerminalUnit:VariableRefrigerantFlow",
97 : "ZoneHVAC:IdealLoadsAirSystem",
98 : "ZoneHVAC:EvaporativeCoolerUnit",
99 : "ZoneHVAC:HybridUnitaryHVAC"});
100 :
101 : constexpr std::array<std::string_view, static_cast<int>(ZoneEquipType::Num)> zoneEquipTypeNamesUC = {
102 : "DUMMY", // DUMMY,
103 :
104 : "ZONEHVAC:FOURPIPEFANCOIL", // FanCoilFourPipe
105 : "ZONEHVAC:PACKAGEDTERMINALHEATPUMP", // PackagedTerminalHeatPump
106 : "ZONEHVAC:PACKAGEDTERMINALAIRCONDITIONER", // PackagedTerminalAirConditioner
107 : "ZONEHVAC:WATERTOAIRHEATPUMP", // PackagedTerminalHeatPumpWaterToAir
108 : "ZONEHVAC:WINDOWAIRCONDITIONER", // WindowAirConditioner
109 : "ZONEHVAC:UNITHEATER", // UnitHeater
110 : "ZONEHVAC:UNITVENTILATOR", // UnitVentilator
111 : "ZONEHVAC:ENERGYRECOVERYVENTILATOR", // EnergyRecoveryVentilator
112 : "ZONEHVAC:VENTILATEDSLAB", // VentilatedSlab
113 : "ZONEHVAC:OUTDOORAIRUNIT", // OutdoorAirUnit
114 : "ZONEHVAC:TERMINALUNIT:VARIABLEREFRIGERANTFLOW", // VariableRefrigerantFlowTerminal
115 : "ZONEHVAC:IDEALLOADSAIRSYSTEM", // IdealLoadsAirSystem
116 : "ZONEHVAC:EVAPORATIVECOOLERUNIT", // EvaporativeCooler
117 : "ZONEHVAC:HYBRIDUNITARYHVAC", // HybridEvaporativeCooler,
118 :
119 : // last zone equipment type to use zone availability manager. The above list must not change or
120 : // NumValidSysAvailZoneComponents must also change.
121 :
122 : "ZONEHVAC:AIRDISTRIBUTIONUNIT", // AirDistributionUnit
123 : "ZONEHVAC:BASEBOARD:CONVECTIVE:WATER", // BaseboardWaterConvective
124 : "ZONEHVAC:BASEBOARD:CONVECTIVE:ELECTRIC", // BaseboardElectricConvective
125 : "ZONEHVAC:BASEBOARD:RADIANTCONVECTIVE:STEAM", // BaseboardSteam
126 : "ZONEHVAC:BASEBOARD:RADIANTCONVECTIVE:WATER", // BaseboardWater
127 : "ZONEHVAC:BASEBOARD:RADIANTCONVECTIVE:ELECTRIC", // BaseboardElectric
128 : "ZONEHVAC:HIGHTEMPERATURERADIANT", // HighTempRadiant
129 : "ZONEHVAC:LOWTEMPERATURERADIANT:CONSTANTFLOW", // LowTempRadiantConstFlow
130 : "ZONEHVAC:LOWTEMPERATURERADIANT:VARIABLEFLOW", // LowTempRadiantVarFlow
131 : "ZONEHVAC:LOWTEMPERATURERADIANT:ELECTRIC", // LowTempRadiantElectric
132 : "FAN:ZONEEXHAUST", // ExhaustFan
133 : "HEATEXCHANGER:AIRTOAIR:FLATPLATE", // HeatExchanger
134 : "WATERHEATER:HEATPUMP:PUMPEDCONDENSER", // HeatPumpWaterHeaterPumpedCondenser
135 : "WATERHEATER:HEATPUMP:WRAPPEDCONDENSER", // HeatPumpWaterHeaterWrappedCondenser
136 : "ZONEHVAC:DEHUMIDIFIER:DX", // DXDehumidifier
137 : "ZONEHVAC:REFRIGERATIONCHILLERSET", // RefrigerationAirChillerSet
138 : "ZONEHVAC:FORCEDAIR:USERDEFINED", // UserDefinedVACForcedAir
139 : "ZONEHVAC:COOLINGPANEL:RADIANTCONVECTIVE:WATER", // CoolingPanel
140 : "AIRLOOPHVAC:UNITARYSYSTEM", // UnitarySystem
141 : "AIRTERMINAL:DUALDUCT:CONSTANTVOLUME", // AirTerminalDualDuctConstantVolume
142 : "AIRTERMINAL:DUALDUCT:VAV", // AirTerminalDualDuctVAV
143 : "AIRTERMINAL:SINGLEDUCT:CONSTANTVOLUME:REHEAT", // AirTerminalSingleDuctConstantVolumeReheat
144 : "AIRTERMINAL:SINGLEDUCT:CONSTANTVOLUME:NOREHEAT", // AirTerminalSingleDuctConstantVolumeNoReheat
145 : "AIRTERMINAL:SINGLEDUCT:VAV:REHEAT", // AirTerminalSingleDuctVAVReheat
146 : "AIRTERMINAL:SINGLEDUCT:VAV:NOREHEAT", // AirTerminalSingleDuctVAVNoReheat
147 : "AIRTERMINAL:SINGLEDUCT:SERIESPIU:REHEAT", // AirTerminalSingleDuctSeriesPIUReheat
148 : "AIRTERMINAL:SINGLEDUCT:PARALLELPIU:REHEAT", // AirTerminalSingleDuctParallelPIUReheat
149 : "AIRTERMINAL:SINGLEDUCT:CONSTANTVOLUME:FOURPIPEINDUCTION", // AirTerminalSingleDuctCAVFourPipeInduction
150 : "AIRTERMINAL:SINGLEDUCT:VAV:REHEAT:VARIABLESPEEDFAN", // AirTerminalSingleDuctVAVReheatVariableSpeedFan
151 : "AIRTERMINAL:SINGLEDUCT:VAV:HEATANDCOOL:REHEAT", // AirTerminalSingleDuctVAVHeatAndCoolReheat
152 : "AIRTERMINAL:SINGLEDUCT:VAV:HEATANDCOOL:NOREHEAT", // AirTerminalSingleDuctVAVHeatAndCoolNoReheat
153 : "AIRTERMINAL:SINGLEDUCT:CONSTANTVOLUME:COOLEDBEAM", // AirTerminalSingleDuctConstantVolumeCooledBeam
154 : "AIRTERMINAL:DUALDUCT:VAV:OUTDOORAIR", // AirTerminalDualDuctVAVOutdoorAir
155 : "AIRLOOPHVACRETURNAIR" // AirLoopHVACReturnAir
156 : };
157 :
158 : static constexpr std::array<std::string_view, static_cast<int>(LoadDist::Num)> LoadDistNamesUC = {
159 : "SEQUENTIALLOAD", "UNIFORMLOAD", "UNIFORMPLR", "SEQUENTIALUNIFORMPLR"};
160 :
161 : static constexpr std::array<std::string_view, static_cast<int>(ZoneEquipTstatControl::Num)> zoneEquipTstatControlNamesUC = {
162 : "SINGLESPACE", "MAXIMUM", "IDEAL"};
163 :
164 : static constexpr std::array<std::string_view, static_cast<int>(SpaceEquipSizingBasis::Num)> spaceEquipSizingBasisNamesUC = {
165 : "DESIGNCOOLINGLOAD", "DESIGNHEATINGLOAD", "FLOORAREA", "VOLUME", "PERIMETERLENGTH"};
166 :
167 360 : void GetZoneEquipmentData(EnergyPlusData &state)
168 : {
169 :
170 : // SUBROUTINE INFORMATION:
171 : // AUTHOR Russ Taylor
172 : // DATE WRITTEN June 1997
173 : // MODIFIED Aug 2003, FCW: set ZoneEquipConfig number for each zone
174 :
175 : // PURPOSE OF THIS SUBROUTINE:
176 : // Get all the system related equipment which may be attached to
177 : // a zone
178 :
179 : // Using/Aliasing
180 : using NodeInputManager::CheckUniqueNodeNames;
181 : using NodeInputManager::CheckUniqueNodeNumbers;
182 : using NodeInputManager::EndUniqueNodeCheck;
183 : using NodeInputManager::GetNodeNums;
184 : using NodeInputManager::GetOnlySingleNode;
185 : using NodeInputManager::InitUniqueNodeCheck;
186 : using namespace DataLoopNode;
187 :
188 : // SUBROUTINE PARAMETER DEFINITIONS:
189 : static constexpr std::string_view RoutineName("GetZoneEquipmentData: "); // include trailing blank space
190 :
191 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
192 : int NumAlphas;
193 : int NumNums;
194 : int IOStat;
195 360 : Array1D_string AlphArray;
196 360 : Array1D<Real64> NumArray;
197 : int MaxAlphas;
198 : int MaxNums;
199 : int NumParams;
200 360 : Array1D_int NodeNums;
201 : bool IsNotOK; // Flag to verify nam
202 360 : std::string CurrentModuleObject; // Object type for getting and error messages
203 360 : Array1D_string cAlphaFields; // Alpha field names
204 360 : Array1D_string cNumericFields; // Numeric field names
205 360 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
206 360 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
207 :
208 : struct EquipListAudit
209 : {
210 : // Members
211 : std::string ObjectType;
212 : std::string ObjectName;
213 : int OnListNum;
214 :
215 : // Default Constructor
216 358 : EquipListAudit() : OnListNum(0)
217 : {
218 358 : }
219 : };
220 : // Object Data
221 360 : Array1D<EquipListAudit> ZoneEquipListAcct;
222 :
223 : // Look in the input file for zones with air loop and zone equipment attached
224 :
225 360 : int numControlledZones = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "ZoneHVAC:EquipmentConnections");
226 360 : int numControlledSpaces = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SpaceHVAC:EquipmentConnections");
227 360 : state.dataZoneEquip->NumOfZoneEquipLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(
228 : state, "ZoneHVAC:EquipmentList"); // Look for lists of equipment data - there should
229 : // be as many of these as there are controlled zones
230 360 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "NodeList", NumParams, NumAlphas, NumNums);
231 360 : NodeNums.dimension(NumParams, 0);
232 360 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "ZoneHVAC:EquipmentList", NumParams, NumAlphas, NumNums);
233 360 : MaxAlphas = NumAlphas;
234 360 : MaxNums = NumNums;
235 360 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "ZoneHVAC:EquipmentConnections", NumParams, NumAlphas, NumNums);
236 360 : MaxAlphas = max(MaxAlphas, NumAlphas);
237 360 : MaxNums = max(MaxNums, NumNums);
238 360 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "SpaceHVAC:EquipmentConnections", NumParams, NumAlphas, NumNums);
239 360 : MaxAlphas = max(MaxAlphas, NumAlphas);
240 360 : MaxNums = max(MaxNums, NumNums);
241 360 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "AirLoopHVAC:SupplyPath", NumParams, NumAlphas, NumNums);
242 360 : MaxAlphas = max(MaxAlphas, NumAlphas);
243 360 : MaxNums = max(MaxNums, NumNums);
244 360 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "AirLoopHVAC:ReturnPath", NumParams, NumAlphas, NumNums);
245 360 : MaxAlphas = max(MaxAlphas, NumAlphas);
246 360 : MaxNums = max(MaxNums, NumNums);
247 360 : AlphArray.allocate(MaxAlphas);
248 360 : NumArray.dimension(MaxNums, 0.0);
249 360 : cAlphaFields.allocate(MaxAlphas);
250 360 : cNumericFields.allocate(MaxNums);
251 360 : lAlphaBlanks.dimension(MaxAlphas, true);
252 360 : lNumericBlanks.dimension(MaxNums, true);
253 :
254 360 : if (!allocated(state.dataZoneEquip->SupplyAirPath)) {
255 : // Look for and read in the air supply path
256 : // component (splitters) information for each zone
257 360 : state.dataZoneEquip->NumSupplyAirPaths = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirLoopHVAC:SupplyPath");
258 360 : state.dataZoneEquip->SupplyAirPath.allocate(state.dataZoneEquip->NumSupplyAirPaths);
259 : }
260 :
261 360 : if (!allocated(state.dataZoneEquip->ReturnAirPath)) {
262 : // Look for and read in the air return path
263 : // component (mixers & plenums) information for each zone
264 360 : state.dataZoneEquip->NumReturnAirPaths = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirLoopHVAC:ReturnPath");
265 360 : state.dataZoneEquip->ReturnAirPath.allocate(state.dataZoneEquip->NumReturnAirPaths);
266 : }
267 :
268 360 : state.dataZoneEquip->ZoneEquipConfig.allocate(state.dataGlobal->NumOfZones); // Allocate the array containing the configuration data for each zone
269 360 : if (state.dataHeatBal->doSpaceHeatBalanceSizing || state.dataHeatBal->doSpaceHeatBalanceSimulation) {
270 16 : state.dataZoneEquip->spaceEquipConfig.allocate(
271 8 : state.dataGlobal->numSpaces); // Allocate the array containing the configuration data for each space
272 : }
273 360 : state.dataZoneEquip->ZoneEquipList.allocate(state.dataGlobal->NumOfZones);
274 360 : state.dataZoneEquip->ZoneEquipAvail.dimension(state.dataGlobal->NumOfZones, Avail::Status::NoAction);
275 360 : state.dataZoneEquip->UniqueZoneEquipListNames.reserve(state.dataGlobal->NumOfZones);
276 :
277 360 : if (state.dataZoneEquip->NumOfZoneEquipLists != numControlledZones) {
278 0 : ShowSevereError(state,
279 0 : format("{}Number of Zone Equipment lists [{}] not equal Number of Controlled Zones [{}]",
280 : RoutineName,
281 0 : state.dataZoneEquip->NumOfZoneEquipLists,
282 : numControlledZones));
283 0 : ShowContinueError(state, "..Each Controlled Zone [ZoneHVAC:EquipmentConnections] must have a corresponding (unique) ZoneHVAC:EquipmentList");
284 0 : ShowFatalError(state, "GetZoneEquipment: Incorrect number of zone equipment lists");
285 : }
286 :
287 360 : if (numControlledZones > state.dataGlobal->NumOfZones) {
288 0 : ShowSevereError(state,
289 0 : format("{}Number of Controlled Zone objects [{}] greater than Number of Zones [{}]",
290 : RoutineName,
291 : numControlledZones,
292 0 : state.dataGlobal->NumOfZones));
293 0 : ShowFatalError(state, format("{}Too many ZoneHVAC:EquipmentConnections objects.", RoutineName));
294 : }
295 :
296 360 : InitUniqueNodeCheck(state, "ZoneHVAC:EquipmentConnections");
297 :
298 360 : int overallEquipCount = 0;
299 360 : int locTermUnitSizingCounter = 0; // will increment for every zone inlet node
300 :
301 : // auto &Zone(state.dataHeatBal->Zone);
302 :
303 662 : for (int controlledZoneLoop = 1; controlledZoneLoop <= numControlledZones; ++controlledZoneLoop) {
304 302 : CurrentModuleObject = "ZoneHVAC:EquipmentConnections";
305 302 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
306 : CurrentModuleObject,
307 : controlledZoneLoop,
308 : AlphArray,
309 : NumAlphas,
310 : NumArray,
311 : NumNums,
312 : IOStat,
313 : lNumericBlanks,
314 : lAlphaBlanks,
315 : cAlphaFields,
316 : cNumericFields); // Get Equipment | data for one zone
317 :
318 302 : int zoneNum = Util::FindItemInList(AlphArray(1), state.dataHeatBal->Zone);
319 302 : std::string_view zsString = "Zone";
320 :
321 302 : if (zoneNum == 0) {
322 0 : ShowSevereError(state, format("{}{}: {}=\"{}\"", RoutineName, CurrentModuleObject, cAlphaFields(1), AlphArray(1)));
323 0 : ShowContinueError(state,
324 0 : format("..Requested Controlled {} not among {}s, remaining items for this object not processed.", zsString, zsString));
325 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
326 0 : continue;
327 : }
328 302 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
329 : // Is this a duplicate for the same zone?
330 302 : if (thisZone.IsControlled) {
331 0 : ShowSevereError(state, format("{}{}: {}=\"{}\"", RoutineName, CurrentModuleObject, cAlphaFields(1), AlphArray(1)));
332 0 : ShowContinueError(state,
333 0 : format("..Duplicate Controlled {} entered, only one {} per {} is allowed.", zsString, CurrentModuleObject, zsString));
334 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
335 0 : continue;
336 : }
337 302 : thisZone.IsControlled = true;
338 302 : bool isSpace = false;
339 302 : auto &thisZoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(zoneNum);
340 302 : processZoneEquipmentInput(state,
341 : CurrentModuleObject,
342 : zoneNum,
343 : isSpace,
344 : locTermUnitSizingCounter,
345 : overallEquipCount,
346 : thisZoneEquipConfig,
347 : AlphArray,
348 : cAlphaFields,
349 : lAlphaBlanks,
350 : NodeNums);
351 302 : thisZone.SystemZoneNodeNumber = thisZoneEquipConfig.ZoneNode;
352 : } // end loop over controlled zones
353 360 : for (int controlledSpaceLoop = 1; controlledSpaceLoop <= numControlledSpaces; ++controlledSpaceLoop) {
354 0 : CurrentModuleObject = "SpaceHVAC:EquipmentConnections";
355 0 : if (!state.dataHeatBal->doSpaceHeatBalanceSimulation) {
356 0 : ShowWarningError(
357 : state,
358 0 : format("{} requires \"Do Space Heat Balance for Simulation = Yes\" in ZoneAirHeatBalanceAlgorithm. {} objects will be ignored.",
359 : CurrentModuleObject,
360 : CurrentModuleObject));
361 0 : break;
362 : }
363 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
364 : CurrentModuleObject,
365 : controlledSpaceLoop,
366 : AlphArray,
367 : NumAlphas,
368 : NumArray,
369 : NumNums,
370 : IOStat,
371 : lNumericBlanks,
372 : lAlphaBlanks,
373 : cAlphaFields,
374 : cNumericFields); // Get Equipment | data for one zone
375 :
376 0 : int spaceNum = Util::FindItemInList(AlphArray(1), state.dataHeatBal->space);
377 0 : std::string_view zsString = "Space";
378 :
379 0 : if (spaceNum == 0) {
380 0 : ShowSevereError(state, format("{}{}: {}=\"{}\"", RoutineName, CurrentModuleObject, cAlphaFields(1), AlphArray(1)));
381 0 : ShowContinueError(state,
382 0 : format("..Requested Controlled {} not among {}s, remaining items for this object not processed.", zsString, zsString));
383 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
384 0 : continue;
385 : }
386 0 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
387 0 : int zoneNum = thisSpace.zoneNum;
388 0 : if (!state.dataHeatBal->Zone(zoneNum).IsControlled) {
389 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, CurrentModuleObject, thisSpace.Name));
390 0 : ShowContinueError(state,
391 0 : format("..Zone Name={} is not a controlled zone. A ZoneHVAC:EquipmentConnections object is required for this zone.",
392 0 : state.dataHeatBal->Zone(zoneNum).Name));
393 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
394 0 : continue;
395 : }
396 : // Is this a duplicate for the same space?
397 0 : if (thisSpace.IsControlled) {
398 0 : ShowSevereError(state, format("{}{}: {}=\"{}\"", RoutineName, CurrentModuleObject, cAlphaFields(1), AlphArray(1)));
399 0 : ShowContinueError(state,
400 0 : format("..Duplicate Controlled {} entered, only one {} per {} is allowed.", zsString, CurrentModuleObject, zsString));
401 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
402 0 : continue;
403 : }
404 0 : thisSpace.IsControlled = true;
405 0 : bool isSpace = true;
406 0 : auto &thisSpaceEquipConfig = state.dataZoneEquip->spaceEquipConfig(spaceNum);
407 0 : processZoneEquipmentInput(state,
408 : CurrentModuleObject,
409 : spaceNum,
410 : isSpace,
411 : locTermUnitSizingCounter,
412 : overallEquipCount,
413 : thisSpaceEquipConfig,
414 : AlphArray,
415 : cAlphaFields,
416 : lAlphaBlanks,
417 : NodeNums);
418 0 : thisSpace.SystemZoneNodeNumber = thisSpaceEquipConfig.ZoneNode;
419 : } // end loop over controlled spaces
420 :
421 360 : if (state.dataHeatBal->doSpaceHeatBalanceSizing || state.dataHeatBal->doSpaceHeatBalanceSimulation) {
422 : // Auto-assign the system node name for spaces in controlled zones that do not have a SpaceHVAC:EquipmentConnections input
423 17 : for (auto &thisZone : state.dataHeatBal->Zone) {
424 9 : if (!thisZone.IsControlled) {
425 2 : continue;
426 : }
427 7 : int spaceCount = 0;
428 28 : for (int spaceNum : thisZone.spaceIndexes) {
429 21 : ++spaceCount;
430 21 : if (state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber == 0) {
431 21 : std::string spaceNodeName = format("{}-Space {}", state.dataLoopNodes->NodeID(thisZone.SystemZoneNodeNumber), spaceCount);
432 21 : int spaceNodeNum = GetOnlySingleNode(state,
433 : spaceNodeName,
434 21 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound,
435 : DataLoopNode::ConnectionObjectType::ZoneHVACEquipmentConnections,
436 21 : AlphArray(1),
437 : DataLoopNode::NodeFluidType::Air,
438 : DataLoopNode::ConnectionType::ZoneNode,
439 : NodeInputManager::CompFluidStream::Primary,
440 : DataLoopNode::ObjectIsNotParent);
441 21 : state.dataHeatBal->space(spaceNum).SystemZoneNodeNumber = spaceNodeNum;
442 21 : }
443 7 : }
444 8 : }
445 : }
446 : // Allocate TermUnitSizing array and set zone number
447 360 : if (locTermUnitSizingCounter > 0) {
448 224 : state.dataSize->NumAirTerminalUnits = locTermUnitSizingCounter;
449 224 : state.dataSize->TermUnitSizing.allocate(state.dataSize->NumAirTerminalUnits);
450 536 : for (int loopZoneNum = 1; loopZoneNum <= state.dataGlobal->NumOfZones; ++loopZoneNum) {
451 : {
452 312 : auto &thisZoneEqConfig = state.dataZoneEquip->ZoneEquipConfig(loopZoneNum);
453 633 : for (int loopNodeNum = 1; loopNodeNum <= thisZoneEqConfig.NumInletNodes; ++loopNodeNum) {
454 321 : state.dataSize->TermUnitSizing(thisZoneEqConfig.AirDistUnitCool(loopNodeNum).TermUnitSizingIndex).CtrlZoneNum = loopZoneNum;
455 : }
456 : }
457 : }
458 : }
459 360 : if (state.dataZoneEquip->GetZoneEquipmentDataErrorsFound) {
460 0 : ShowWarningError(state, format("{}{}, duplicate items NOT CHECKED due to previous errors.", RoutineName, CurrentModuleObject));
461 0 : overallEquipCount = 0;
462 : }
463 360 : if (overallEquipCount > 0) {
464 235 : ZoneEquipListAcct.allocate(overallEquipCount);
465 235 : overallEquipCount = 0;
466 536 : for (int Loop1 = 1; Loop1 <= numControlledZones; ++Loop1) {
467 646 : for (int Loop2 = 1; Loop2 <= state.dataZoneEquip->ZoneEquipList(Loop1).NumOfEquipTypes; ++Loop2) {
468 345 : ++overallEquipCount;
469 345 : ZoneEquipListAcct(overallEquipCount).ObjectType = state.dataZoneEquip->ZoneEquipList(Loop1).EquipType(Loop2);
470 345 : ZoneEquipListAcct(overallEquipCount).ObjectName = state.dataZoneEquip->ZoneEquipList(Loop1).EquipName(Loop2);
471 345 : ZoneEquipListAcct(overallEquipCount).OnListNum = Loop1;
472 : }
473 : }
474 : // Now check for uniqueness
475 580 : for (int Loop1 = 1; Loop1 <= overallEquipCount; ++Loop1) {
476 548 : for (int Loop2 = Loop1 + 1; Loop2 <= overallEquipCount; ++Loop2) {
477 327 : if (ZoneEquipListAcct(Loop1).ObjectType != ZoneEquipListAcct(Loop2).ObjectType ||
478 124 : ZoneEquipListAcct(Loop1).ObjectName != ZoneEquipListAcct(Loop2).ObjectName) {
479 203 : continue;
480 : }
481 : // Duplicated -- not allowed
482 0 : ShowSevereError(state, format("{}{}, duplicate items in ZoneHVAC:EquipmentList.", RoutineName, CurrentModuleObject));
483 0 : ShowContinueError(state,
484 0 : format("Equipment: Type={}, Name={}", ZoneEquipListAcct(Loop1).ObjectType, ZoneEquipListAcct(Loop1).ObjectName));
485 0 : ShowContinueError(state,
486 0 : format("Found on List=\"{}\".", state.dataZoneEquip->ZoneEquipList(ZoneEquipListAcct(Loop1).OnListNum).Name));
487 0 : ShowContinueError(
488 : state,
489 0 : format("Equipment Duplicated on List=\"{}\".", state.dataZoneEquip->ZoneEquipList(ZoneEquipListAcct(Loop2).OnListNum).Name));
490 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
491 : }
492 : }
493 235 : ZoneEquipListAcct.deallocate();
494 : }
495 :
496 : // map ZoneEquipConfig%EquipListIndex to ZoneEquipList%Name
497 :
498 853 : for (int ControlledZoneLoop = 1; ControlledZoneLoop <= state.dataGlobal->NumOfZones; ++ControlledZoneLoop) {
499 493 : state.dataZoneEquip->GetZoneEquipmentDataFound = Util::FindItemInList(
500 493 : state.dataZoneEquip->ZoneEquipList(ControlledZoneLoop).Name, state.dataZoneEquip->ZoneEquipConfig, &EquipConfiguration::EquipListName);
501 493 : if (state.dataZoneEquip->GetZoneEquipmentDataFound > 0) {
502 493 : state.dataZoneEquip->ZoneEquipConfig(state.dataZoneEquip->GetZoneEquipmentDataFound).EquipListIndex = ControlledZoneLoop;
503 : }
504 : } // end loop over controlled zones
505 :
506 360 : EndUniqueNodeCheck(state, "ZoneHVAC:EquipmentConnections");
507 :
508 360 : auto &ip = state.dataInputProcessing->inputProcessor;
509 :
510 360 : CurrentModuleObject = "SpaceHVAC:ZoneEquipmentSplitter";
511 360 : auto instances = ip->epJSON.find(CurrentModuleObject);
512 360 : if (instances != ip->epJSON.end()) {
513 0 : if (!state.dataHeatBal->doSpaceHeatBalanceSimulation) {
514 0 : ShowWarningError(
515 : state,
516 0 : format("{} requires \"Do Space Heat Balance for Simulation = Yes\" in ZoneAirHeatBalanceAlgorithm. {} objects will be ignored.",
517 : CurrentModuleObject,
518 : CurrentModuleObject));
519 : } else {
520 0 : auto const &objectSchemaProps = ip->getObjectSchemaProps(state, CurrentModuleObject);
521 0 : auto &instancesValue = instances.value();
522 0 : int numZoneEqSplitters = instancesValue.size();
523 0 : state.dataZoneEquip->zoneEquipSplitter.resize(numZoneEqSplitters);
524 0 : int zeqSplitterNum = -1;
525 0 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
526 0 : ++zeqSplitterNum;
527 0 : auto const &objectFields = instance.value();
528 0 : auto &thisZeqSplitter = state.dataZoneEquip->zoneEquipSplitter[zeqSplitterNum];
529 0 : thisZeqSplitter.Name = Util::makeUPPER(instance.key());
530 0 : thisZeqSplitter.spaceEquipType = DataLoopNode::ConnectionObjectType::SpaceHVACZoneEquipmentSplitter;
531 0 : ip->markObjectAsUsed(CurrentModuleObject, instance.key());
532 :
533 0 : std::string zoneName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_name");
534 0 : int zoneNum = Util::FindItemInList(zoneName, state.dataHeatBal->Zone);
535 0 : if (zoneNum == 0) {
536 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, CurrentModuleObject, thisZeqSplitter.Name));
537 0 : ShowContinueError(state, format("..Zone Name={} not found, remaining items for this object not processed.", zoneName));
538 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
539 0 : continue;
540 : }
541 0 : if (!state.dataHeatBal->Zone(zoneNum).IsControlled) {
542 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, CurrentModuleObject, thisZeqSplitter.Name));
543 0 : ShowContinueError(
544 : state,
545 0 : format("..Zone Name={} is not a controlled zone. A ZoneHVAC:EquipmentConnections object is required for this zone.",
546 : zoneName));
547 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
548 0 : continue;
549 : }
550 :
551 0 : processZoneEquipSplitterInput(state, CurrentModuleObject, zeqSplitterNum, zoneNum, objectSchemaProps, objectFields, thisZeqSplitter);
552 0 : } // end loop over zone equipment splitters
553 : }
554 : }
555 :
556 360 : CurrentModuleObject = "SpaceHVAC:ZoneEquipmentMixer";
557 360 : instances = ip->epJSON.find(CurrentModuleObject);
558 360 : if (instances != ip->epJSON.end()) {
559 0 : if (!state.dataHeatBal->doSpaceHeatBalanceSimulation) {
560 0 : ShowWarningError(
561 : state,
562 0 : format("{} requires \"Do Space Heat Balance for Simulation = Yes\" in ZoneAirHeatBalanceAlgorithm. {} objects will be ignored.",
563 : CurrentModuleObject,
564 : CurrentModuleObject));
565 : } else {
566 0 : auto const &objectSchemaProps = ip->getObjectSchemaProps(state, CurrentModuleObject);
567 0 : auto &instancesValue = instances.value();
568 0 : int numZoneEqMixers = instancesValue.size();
569 0 : state.dataZoneEquip->zoneEquipMixer.resize(numZoneEqMixers);
570 0 : int zeqMixerNum = -1;
571 0 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
572 0 : ++zeqMixerNum;
573 0 : auto const &objectFields = instance.value();
574 0 : auto &thisZeqMixer = state.dataZoneEquip->zoneEquipMixer[zeqMixerNum];
575 0 : thisZeqMixer.Name = Util::makeUPPER(instance.key());
576 0 : thisZeqMixer.spaceEquipType = DataLoopNode::ConnectionObjectType::SpaceHVACZoneEquipmentMixer;
577 0 : ip->markObjectAsUsed(CurrentModuleObject, instance.key());
578 :
579 0 : std::string zoneName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_name");
580 0 : int zoneNum = Util::FindItemInList(zoneName, state.dataHeatBal->Zone);
581 0 : if (zoneNum == 0) {
582 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, CurrentModuleObject, thisZeqMixer.Name));
583 0 : ShowContinueError(state, format("..Zone Name={} not found, remaining items for this object not processed.", zoneName));
584 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
585 0 : continue;
586 : }
587 0 : if (!state.dataHeatBal->Zone(zoneNum).IsControlled) {
588 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, CurrentModuleObject, thisZeqMixer.Name));
589 0 : ShowContinueError(
590 : state,
591 0 : format("..Zone Name={} is not a controlled zone. A ZoneHVAC:EquipmentConnections object is required for this zone.",
592 : zoneName));
593 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
594 0 : continue;
595 : }
596 :
597 0 : processZoneEquipMixerInput(state, CurrentModuleObject, zoneNum, objectSchemaProps, objectFields, thisZeqMixer);
598 0 : } // end loop over zone equipment mixers
599 : }
600 : }
601 :
602 360 : CurrentModuleObject = "SpaceHVAC:ZoneReturnMixer";
603 360 : instances = ip->epJSON.find(CurrentModuleObject);
604 360 : if (instances != ip->epJSON.end()) {
605 0 : if (!state.dataHeatBal->doSpaceHeatBalanceSimulation) {
606 0 : ShowWarningError(
607 : state,
608 0 : format("{} requires \"Do Space Heat Balance for Simulation = Yes\" in ZoneAirHeatBalanceAlgorithm. {} objects will be ignored.",
609 : CurrentModuleObject,
610 : CurrentModuleObject));
611 : } else {
612 0 : auto const &objectSchemaProps = ip->getObjectSchemaProps(state, CurrentModuleObject);
613 0 : auto &instancesValue = instances.value();
614 0 : int numZoneRetMixers = instancesValue.size();
615 0 : state.dataZoneEquip->zoneReturnMixer.resize(numZoneRetMixers);
616 0 : int zeqRetNum = -1;
617 0 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
618 0 : ++zeqRetNum;
619 0 : auto const &objectFields = instance.value();
620 0 : auto &thisZretMixer = state.dataZoneEquip->zoneReturnMixer[zeqRetNum];
621 0 : thisZretMixer.Name = Util::makeUPPER(instance.key());
622 0 : thisZretMixer.spaceEquipType = DataLoopNode::ConnectionObjectType::SpaceHVACZoneReturnMixer;
623 0 : ip->markObjectAsUsed(CurrentModuleObject, instance.key());
624 :
625 0 : std::string zoneName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_name");
626 0 : int zoneNum = Util::FindItemInList(zoneName, state.dataHeatBal->Zone);
627 0 : if (zoneNum == 0) {
628 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, CurrentModuleObject, thisZretMixer.Name));
629 0 : ShowContinueError(state, format("..Zone Name={} not found, remaining items for this object not processed.", zoneName));
630 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
631 0 : continue;
632 : }
633 0 : if (!state.dataHeatBal->Zone(zoneNum).IsControlled) {
634 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, CurrentModuleObject, thisZretMixer.Name));
635 0 : ShowContinueError(
636 : state,
637 0 : format("..Zone Name={} is not a controlled zone. A ZoneHVAC:EquipmentConnections object is required for this zone.",
638 : zoneName));
639 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
640 0 : continue;
641 : }
642 :
643 0 : processZoneReturnMixerInput(state, CurrentModuleObject, zoneNum, objectSchemaProps, objectFields, zeqRetNum);
644 0 : } // end loop over zone return mixers
645 : }
646 : }
647 :
648 360 : CurrentModuleObject = "AirLoopHVAC:SupplyPath";
649 424 : for (int PathNum = 1; PathNum <= state.dataZoneEquip->NumSupplyAirPaths; ++PathNum) {
650 :
651 64 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
652 : CurrentModuleObject,
653 : PathNum,
654 : AlphArray,
655 : NumAlphas,
656 : NumArray,
657 : NumNums,
658 : IOStat,
659 : lNumericBlanks,
660 : lAlphaBlanks,
661 : cAlphaFields,
662 : cNumericFields); // data for one zone
663 64 : state.dataZoneEquip->SupplyAirPath(PathNum).Name = AlphArray(1);
664 64 : state.dataZoneEquip->SupplyAirPath(PathNum).NumOfComponents = nint((double(NumAlphas) - 2.0) / 2.0);
665 :
666 128 : state.dataZoneEquip->SupplyAirPath(PathNum).InletNodeNum = GetOnlySingleNode(state,
667 64 : AlphArray(2),
668 64 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound,
669 : DataLoopNode::ConnectionObjectType::AirLoopHVACSupplyPath,
670 64 : AlphArray(1),
671 : DataLoopNode::NodeFluidType::Air,
672 : DataLoopNode::ConnectionType::Inlet,
673 : NodeInputManager::CompFluidStream::Primary,
674 : ObjectIsParent);
675 :
676 64 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentType.allocate(state.dataZoneEquip->SupplyAirPath(PathNum).NumOfComponents);
677 64 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentTypeEnum.allocate(state.dataZoneEquip->SupplyAirPath(PathNum).NumOfComponents);
678 64 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentTypeEnum = DataZoneEquipment::AirLoopHVACZone::Invalid;
679 64 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentName.allocate(state.dataZoneEquip->SupplyAirPath(PathNum).NumOfComponents);
680 64 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentIndex.allocate(state.dataZoneEquip->SupplyAirPath(PathNum).NumOfComponents);
681 64 : state.dataZoneEquip->SupplyAirPath(PathNum).SplitterIndex.allocate(state.dataZoneEquip->SupplyAirPath(PathNum).NumOfComponents);
682 64 : state.dataZoneEquip->SupplyAirPath(PathNum).PlenumIndex.allocate(state.dataZoneEquip->SupplyAirPath(PathNum).NumOfComponents);
683 :
684 64 : int Counter = 3;
685 :
686 129 : for (int CompNum = 1; CompNum <= state.dataZoneEquip->SupplyAirPath(PathNum).NumOfComponents; ++CompNum) {
687 :
688 65 : if ((AlphArray(Counter) == "AIRLOOPHVAC:ZONESPLITTER") || (AlphArray(Counter) == "AIRLOOPHVAC:SUPPLYPLENUM")) {
689 :
690 65 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentType(CompNum) = AlphArray(Counter);
691 65 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentName(CompNum) = AlphArray(Counter + 1);
692 130 : ValidateComponent(state,
693 65 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentType(CompNum),
694 65 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentName(CompNum),
695 : IsNotOK,
696 : CurrentModuleObject);
697 65 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentIndex(CompNum) = 0;
698 65 : state.dataZoneEquip->SupplyAirPath(PathNum).SplitterIndex(CompNum) = 0;
699 65 : state.dataZoneEquip->SupplyAirPath(PathNum).PlenumIndex(CompNum) = 0;
700 65 : state.dataZoneEquip->SupplyAirPath(PathNum).ComponentTypeEnum(CompNum) =
701 130 : (AirLoopHVACZone)getEnumValue(AirLoopHVACTypeNamesUC, AlphArray(Counter));
702 : } else {
703 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, cAlphaFields(1), state.dataZoneEquip->SupplyAirPath(PathNum).Name));
704 0 : ShowContinueError(state, format("Unhandled component type =\"{}\".", AlphArray(Counter)));
705 0 : ShowContinueError(state, R"(Must be "AirLoopHVAC:ZoneSplitter" or "AirLoopHVAC:SupplyPlenum")");
706 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
707 : }
708 :
709 65 : Counter += 2;
710 : }
711 :
712 64 : state.dataZoneEquip->SupplyAirPath(PathNum).NumOutletNodes = 0;
713 64 : state.dataZoneEquip->SupplyAirPath(PathNum).NumNodes = 0;
714 :
715 : } // end loop over supply air paths
716 :
717 360 : CurrentModuleObject = "AirLoopHVAC:ReturnPath";
718 424 : for (int PathNum = 1; PathNum <= state.dataZoneEquip->NumReturnAirPaths; ++PathNum) {
719 :
720 64 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
721 : CurrentModuleObject,
722 : PathNum,
723 : AlphArray,
724 : NumAlphas,
725 : NumArray,
726 : NumNums,
727 : IOStat,
728 : lNumericBlanks,
729 : lAlphaBlanks,
730 : cAlphaFields,
731 : cNumericFields); // data for one zone
732 64 : state.dataZoneEquip->ReturnAirPath(PathNum).Name = AlphArray(1);
733 64 : state.dataZoneEquip->ReturnAirPath(PathNum).NumOfComponents = nint((double(NumAlphas) - 2.0) / 2.0);
734 :
735 128 : state.dataZoneEquip->ReturnAirPath(PathNum).OutletNodeNum = GetOnlySingleNode(state,
736 64 : AlphArray(2),
737 64 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound,
738 : DataLoopNode::ConnectionObjectType::AirLoopHVACReturnPath,
739 64 : AlphArray(1),
740 : DataLoopNode::NodeFluidType::Air,
741 : DataLoopNode::ConnectionType::Outlet,
742 : NodeInputManager::CompFluidStream::Primary,
743 : ObjectIsParent);
744 :
745 64 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentType.allocate(state.dataZoneEquip->ReturnAirPath(PathNum).NumOfComponents);
746 64 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentTypeEnum.allocate(state.dataZoneEquip->ReturnAirPath(PathNum).NumOfComponents);
747 64 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentTypeEnum = DataZoneEquipment::AirLoopHVACZone::Invalid;
748 64 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentName.allocate(state.dataZoneEquip->ReturnAirPath(PathNum).NumOfComponents);
749 64 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentIndex.allocate(state.dataZoneEquip->ReturnAirPath(PathNum).NumOfComponents);
750 :
751 64 : int Counter = 3;
752 :
753 129 : for (int CompNum = 1; CompNum <= state.dataZoneEquip->ReturnAirPath(PathNum).NumOfComponents; ++CompNum) {
754 :
755 65 : if ((AlphArray(Counter) == "AIRLOOPHVAC:ZONEMIXER") || (AlphArray(Counter) == "AIRLOOPHVAC:RETURNPLENUM")) {
756 :
757 65 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentType(CompNum) = AlphArray(Counter);
758 65 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentName(CompNum) = AlphArray(Counter + 1);
759 65 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentIndex(CompNum) = 0;
760 130 : ValidateComponent(state,
761 65 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentType(CompNum),
762 65 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentName(CompNum),
763 : IsNotOK,
764 : CurrentModuleObject);
765 65 : if (IsNotOK) {
766 0 : ShowContinueError(state, format("In {} = {}", CurrentModuleObject, state.dataZoneEquip->ReturnAirPath(PathNum).Name));
767 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
768 : }
769 65 : state.dataZoneEquip->ReturnAirPath(PathNum).ComponentTypeEnum(CompNum) =
770 130 : static_cast<AirLoopHVACZone>(getEnumValue(AirLoopHVACTypeNamesUC, AlphArray(Counter)));
771 : } else {
772 0 : ShowSevereError(state, format("{}{}=\"{}\"", RoutineName, cAlphaFields(1), state.dataZoneEquip->ReturnAirPath(PathNum).Name));
773 0 : ShowContinueError(state, format("Unhandled component type =\"{}\".", AlphArray(Counter)));
774 0 : ShowContinueError(state, R"(Must be "AirLoopHVAC:ZoneMixer" or "AirLoopHVAC:ReturnPlenum")");
775 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
776 : }
777 :
778 65 : Counter += 2;
779 : }
780 :
781 : } // end loop over return air paths
782 :
783 360 : AlphArray.deallocate();
784 360 : NumArray.deallocate();
785 360 : cAlphaFields.deallocate();
786 360 : cNumericFields.deallocate();
787 360 : lAlphaBlanks.deallocate();
788 360 : lNumericBlanks.deallocate();
789 :
790 360 : if (state.dataZoneEquip->GetZoneEquipmentDataErrorsFound) {
791 0 : ShowFatalError(state, format("{}Errors found in getting Zone Equipment input.", RoutineName));
792 : }
793 360 : }
794 :
795 302 : void processZoneEquipmentInput(EnergyPlusData &state,
796 : std::string_view zoneEqModuleObject,
797 : int const zoneOrSpaceNum,
798 : bool const isSpace,
799 : int &locTermUnitSizingCounter,
800 : int &overallEquipCount,
801 : DataZoneEquipment::EquipConfiguration &thisEquipConfig,
802 : Array1D_string &AlphArray,
803 : Array1D_string &cAlphaFields, // Alpha field names
804 : Array1D_bool &lAlphaBlanks, // Logical array, alpha field input BLANK = .TRUE.
805 : Array1D_int &NodeNums)
806 : {
807 : static constexpr std::string_view RoutineName("processZoneEquipmentInput: "); // include trailing blank space
808 : static constexpr std::string_view routineName = "processZoneEquipmentInput";
809 :
810 302 : int spaceFieldShift = 0;
811 302 : if (isSpace) {
812 0 : spaceFieldShift = -1;
813 : }
814 :
815 302 : ErrorObjectHeader eoh{routineName, zoneEqModuleObject, AlphArray(1)};
816 :
817 302 : thisEquipConfig.IsControlled = true;
818 302 : thisEquipConfig.ZoneName = AlphArray(1); // for x-referencing with the geometry data
819 :
820 302 : bool IsNotOK = false;
821 604 : GlobalNames::IntraObjUniquenessCheck(
822 302 : state, AlphArray(2), zoneEqModuleObject, cAlphaFields(2), state.dataZoneEquip->UniqueZoneEquipListNames, IsNotOK);
823 302 : if (IsNotOK) {
824 0 : ShowContinueError(state, format("..another Controlled Zone has been assigned that {}.", cAlphaFields(2)));
825 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
826 : }
827 302 : thisEquipConfig.EquipListName = AlphArray(2); // the name of the list containing all the zone eq.
828 302 : std::string const InletNodeListName = AlphArray(3 + spaceFieldShift);
829 302 : std::string const ExhaustNodeListName = AlphArray(4 + spaceFieldShift);
830 302 : thisEquipConfig.ZoneNode = GetOnlySingleNode(state,
831 302 : AlphArray(5 + spaceFieldShift),
832 302 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound,
833 : DataLoopNode::ConnectionObjectType::ZoneHVACEquipmentConnections,
834 302 : AlphArray(1),
835 : DataLoopNode::NodeFluidType::Air,
836 : DataLoopNode::ConnectionType::ZoneNode,
837 : NodeInputManager::CompFluidStream::Primary,
838 : DataLoopNode::ObjectIsNotParent); // all zone air state variables are
839 302 : if (thisEquipConfig.ZoneNode == 0) {
840 0 : ShowSevereError(state, format("{}{}: {}=\"{}\", invalid", RoutineName, zoneEqModuleObject, cAlphaFields(1), AlphArray(1)));
841 0 : ShowContinueError(state, format("{} must be present.", cAlphaFields(5 + spaceFieldShift)));
842 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
843 : } else {
844 302 : bool UniqueNodeError = false;
845 302 : NodeInputManager::CheckUniqueNodeNames(
846 302 : state, cAlphaFields(5 + spaceFieldShift), UniqueNodeError, AlphArray(5 + spaceFieldShift), AlphArray(1));
847 302 : if (UniqueNodeError) {
848 : // ShowContinueError(state, format("Occurs for {} = {}", trim( cAlphaFields( 1 ) ), trim( AlphArray( 1 ) )));
849 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
850 : }
851 : }
852 :
853 302 : std::string ReturnNodeListName = AlphArray(6 + spaceFieldShift);
854 302 : if (lAlphaBlanks(7)) {
855 302 : thisEquipConfig.returnFlowFracSched = Sched::GetScheduleAlwaysOn(state); // Not an availability sched, but defaults to constant-1.0
856 0 : } else if ((thisEquipConfig.returnFlowFracSched = Sched::GetSchedule(state, AlphArray(7 + spaceFieldShift))) == nullptr) {
857 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(7), AlphArray(7));
858 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
859 : }
860 302 : std::string ReturnFlowBasisNodeListName = AlphArray(8 + spaceFieldShift);
861 :
862 : // Read in the equipment type, name and sequence information
863 : // for each equipment list
864 :
865 302 : if (!isSpace) {
866 302 : std::string CurrentModuleObject = "ZoneHVAC:EquipmentList";
867 302 : auto &ip = state.dataInputProcessing->inputProcessor;
868 :
869 302 : int ZoneEquipListNum = ip->getObjectItemNum(state, CurrentModuleObject, thisEquipConfig.EquipListName);
870 :
871 302 : if (ZoneEquipListNum <= 0) {
872 0 : ShowSevereError(state, format("{}{} not found = {}", RoutineName, CurrentModuleObject, thisEquipConfig.EquipListName));
873 0 : ShowContinueError(state, format("In ZoneHVAC:EquipmentConnections object, for Zone = {}", thisEquipConfig.ZoneName));
874 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
875 : } else {
876 302 : auto const &epListFields = ip->getJSONObjectItem(state, CurrentModuleObject, thisEquipConfig.EquipListName);
877 :
878 302 : auto const &objectSchemaProps = ip->getObjectSchemaProps(state, CurrentModuleObject);
879 :
880 302 : EquipList &thisZoneEquipList = state.dataZoneEquip->ZoneEquipList(zoneOrSpaceNum);
881 :
882 302 : thisZoneEquipList.Name = thisEquipConfig.EquipListName;
883 :
884 604 : std::string loadDistName = ip->getAlphaFieldValue(epListFields, objectSchemaProps, "load_distribution_scheme");
885 302 : thisZoneEquipList.LoadDistScheme =
886 302 : static_cast<DataZoneEquipment::LoadDist>(getEnumValue(DataZoneEquipment::LoadDistNamesUC, Util::makeUPPER(loadDistName)));
887 302 : if (thisZoneEquipList.LoadDistScheme == DataZoneEquipment::LoadDist::Invalid) {
888 0 : ShowSevereError(state, format("{}{} = \"{}, Invalid choice\".", RoutineName, CurrentModuleObject, thisZoneEquipList.Name));
889 0 : ShowContinueError(state, format("...load_distribution_scheme=\"{}\".", loadDistName));
890 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
891 : }
892 :
893 302 : auto extensibles = epListFields.find("equipment");
894 302 : if (extensibles != epListFields.end()) {
895 301 : auto &extensiblesArray = extensibles.value();
896 301 : thisZoneEquipList.NumOfEquipTypes = static_cast<int>(extensiblesArray.size());
897 :
898 : // Increment overall count of equipment
899 301 : overallEquipCount += thisZoneEquipList.NumOfEquipTypes;
900 :
901 301 : thisZoneEquipList.EquipTypeName.allocate(thisZoneEquipList.NumOfEquipTypes);
902 301 : thisZoneEquipList.EquipType.allocate(thisZoneEquipList.NumOfEquipTypes);
903 301 : thisZoneEquipList.compPointer.resize(thisZoneEquipList.NumOfEquipTypes + 1);
904 301 : thisZoneEquipList.EquipName.allocate(thisZoneEquipList.NumOfEquipTypes);
905 301 : thisZoneEquipList.EquipIndex.allocate(thisZoneEquipList.NumOfEquipTypes);
906 301 : thisZoneEquipList.zoneEquipSplitterIndex.allocate(thisZoneEquipList.NumOfEquipTypes);
907 301 : thisZoneEquipList.EquipData.allocate(thisZoneEquipList.NumOfEquipTypes);
908 301 : thisZoneEquipList.CoolingPriority.allocate(thisZoneEquipList.NumOfEquipTypes);
909 301 : thisZoneEquipList.HeatingPriority.allocate(thisZoneEquipList.NumOfEquipTypes);
910 301 : thisZoneEquipList.CoolingCapacity.allocate(thisZoneEquipList.NumOfEquipTypes);
911 301 : thisZoneEquipList.HeatingCapacity.allocate(thisZoneEquipList.NumOfEquipTypes);
912 301 : thisZoneEquipList.sequentialCoolingFractionScheds.allocate(thisZoneEquipList.NumOfEquipTypes);
913 301 : thisZoneEquipList.sequentialHeatingFractionScheds.allocate(thisZoneEquipList.NumOfEquipTypes);
914 659 : for (int eqNum = 1; eqNum <= thisZoneEquipList.NumOfEquipTypes; ++eqNum) {
915 358 : thisZoneEquipList.EquipTypeName(eqNum) = "";
916 358 : thisZoneEquipList.EquipType(eqNum) = DataZoneEquipment::ZoneEquipType::Invalid;
917 358 : thisZoneEquipList.EquipName(eqNum) = "";
918 358 : thisZoneEquipList.EquipIndex(eqNum) = 0;
919 358 : thisZoneEquipList.zoneEquipSplitterIndex(eqNum) = -1;
920 358 : thisZoneEquipList.compPointer[eqNum] = nullptr;
921 358 : thisZoneEquipList.CoolingPriority(eqNum) = 0;
922 358 : thisZoneEquipList.HeatingPriority(eqNum) = 0;
923 358 : thisZoneEquipList.CoolingCapacity(eqNum) = 0;
924 358 : thisZoneEquipList.HeatingCapacity(eqNum) = 0;
925 358 : thisZoneEquipList.sequentialCoolingFractionScheds(eqNum) = nullptr;
926 358 : thisZoneEquipList.sequentialHeatingFractionScheds(eqNum) = nullptr;
927 : }
928 :
929 301 : auto const &extensionSchemaProps = objectSchemaProps["equipment"]["items"]["properties"];
930 :
931 301 : int ZoneEquipTypeNum = 0;
932 659 : for (auto &extensibleInstance : extensiblesArray) {
933 358 : ++ZoneEquipTypeNum;
934 :
935 358 : thisZoneEquipList.EquipTypeName(ZoneEquipTypeNum) =
936 1074 : ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "zone_equipment_object_type");
937 358 : thisZoneEquipList.EquipName(ZoneEquipTypeNum) =
938 1074 : ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "zone_equipment_name");
939 :
940 716 : ValidateComponent(state,
941 358 : thisZoneEquipList.EquipTypeName(ZoneEquipTypeNum),
942 358 : thisZoneEquipList.EquipName(ZoneEquipTypeNum),
943 : IsNotOK,
944 : CurrentModuleObject);
945 358 : if (IsNotOK) {
946 0 : ShowContinueError(state, format("In {}={}", CurrentModuleObject, thisZoneEquipList.Name));
947 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
948 : }
949 :
950 : // If not present, this return 0
951 716 : thisZoneEquipList.CoolingPriority(ZoneEquipTypeNum) =
952 716 : ip->getIntFieldValue(extensibleInstance, extensionSchemaProps, "zone_equipment_cooling_sequence");
953 :
954 716 : if ((thisZoneEquipList.CoolingPriority(ZoneEquipTypeNum) < 0) ||
955 358 : (thisZoneEquipList.CoolingPriority(ZoneEquipTypeNum) > thisZoneEquipList.NumOfEquipTypes)) {
956 0 : ShowSevereError(state, format("{}{} = \"{}\".", RoutineName, CurrentModuleObject, thisZoneEquipList.Name));
957 0 : ShowContinueError(
958 0 : state, format("invalid zone_equipment_cooling_sequence=[{}].", thisZoneEquipList.CoolingPriority(ZoneEquipTypeNum)));
959 0 : ShowContinueError(state, "equipment sequence must be > 0 and <= number of equipments in the list.");
960 0 : if (thisZoneEquipList.CoolingPriority(ZoneEquipTypeNum) > 0) {
961 0 : ShowContinueError(state, format("only {} in the list.", thisZoneEquipList.NumOfEquipTypes));
962 : }
963 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
964 : }
965 :
966 716 : thisZoneEquipList.HeatingPriority(ZoneEquipTypeNum) =
967 716 : ip->getIntFieldValue(extensibleInstance, extensionSchemaProps, "zone_equipment_heating_or_no_load_sequence");
968 716 : if ((thisZoneEquipList.HeatingPriority(ZoneEquipTypeNum) < 0) ||
969 358 : (thisZoneEquipList.HeatingPriority(ZoneEquipTypeNum) > thisZoneEquipList.NumOfEquipTypes)) {
970 0 : ShowSevereError(state, format("{}{} = \"{}\".", RoutineName, CurrentModuleObject, thisZoneEquipList.Name));
971 0 : ShowContinueError(
972 0 : state, format("invalid zone_equipment_heating_sequence=[{}].", thisZoneEquipList.HeatingPriority(ZoneEquipTypeNum)));
973 0 : ShowContinueError(state, "equipment sequence must be > 0 and <= number of equipments in the list.");
974 0 : if (thisZoneEquipList.HeatingPriority(ZoneEquipTypeNum) > 0) {
975 0 : ShowContinueError(state, format("only {} in the list.", thisZoneEquipList.NumOfEquipTypes));
976 : }
977 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
978 : }
979 :
980 : std::string coolingSchName =
981 716 : ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "zone_equipment_sequential_cooling_fraction_schedule_name");
982 358 : if (coolingSchName.empty()) {
983 356 : thisZoneEquipList.sequentialCoolingFractionScheds(ZoneEquipTypeNum) =
984 356 : Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but defaults to constant-1.0
985 : } else {
986 2 : thisZoneEquipList.sequentialCoolingFractionScheds(ZoneEquipTypeNum) = Sched::GetSchedule(state, coolingSchName);
987 2 : if (thisZoneEquipList.sequentialCoolingFractionScheds(ZoneEquipTypeNum) == nullptr) {
988 0 : ShowSevereItemNotFound(state, eoh, "zone_equipment_sequential_cooling_fraction_schedule_name", coolingSchName);
989 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
990 : }
991 : }
992 :
993 : std::string heatingSchName =
994 716 : ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "zone_equipment_sequential_heating_fraction_schedule_name");
995 358 : if (heatingSchName.empty()) {
996 356 : thisZoneEquipList.sequentialHeatingFractionScheds(ZoneEquipTypeNum) =
997 356 : Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but defaults to constant-1.0
998 : } else {
999 2 : thisZoneEquipList.sequentialHeatingFractionScheds(ZoneEquipTypeNum) = Sched::GetSchedule(state, heatingSchName);
1000 2 : if (thisZoneEquipList.sequentialHeatingFractionScheds(ZoneEquipTypeNum) == nullptr) {
1001 0 : ShowSevereItemNotFound(state, eoh, "zone_equipment_sequential_heating_fraction_schedule_name", coolingSchName);
1002 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1003 : }
1004 : }
1005 :
1006 : // do this here for initial prototype, but later will call all the equipment in a separate function to see who is on - maybe
1007 358 : if (thisZoneEquipList.HeatingPriority(ZoneEquipTypeNum) > 0) {
1008 358 : ++thisZoneEquipList.NumAvailHeatEquip;
1009 : }
1010 358 : if (thisZoneEquipList.CoolingPriority(ZoneEquipTypeNum) > 0) {
1011 355 : ++thisZoneEquipList.NumAvailCoolEquip;
1012 : }
1013 :
1014 716 : thisZoneEquipList.EquipType(ZoneEquipTypeNum) = static_cast<ZoneEquipType>(
1015 358 : getEnumValue(zoneEquipTypeNamesUC, Util::makeUPPER(thisZoneEquipList.EquipTypeName(ZoneEquipTypeNum))));
1016 :
1017 358 : if (thisZoneEquipList.EquipType(ZoneEquipTypeNum) == ZoneEquipType::UnitarySystem ||
1018 336 : thisZoneEquipList.EquipType(ZoneEquipTypeNum) == ZoneEquipType::PackagedTerminalAirConditioner ||
1019 1014 : thisZoneEquipList.EquipType(ZoneEquipTypeNum) == ZoneEquipType::PackagedTerminalHeatPump ||
1020 320 : thisZoneEquipList.EquipType(ZoneEquipTypeNum) == ZoneEquipType::PackagedTerminalHeatPumpWaterToAir) {
1021 : // loop index accesses correct pointer to equipment on this equipment list
1022 : // EquipIndex is used to access specific equipment for a single class of equipment (e.g., PTAC 1, 2 and 3)
1023 40 : thisZoneEquipList.compPointer[ZoneEquipTypeNum] = UnitarySystems::UnitarySys::factory(
1024 40 : state, HVAC::UnitarySysType::Unitary_AnyCoilType, thisZoneEquipList.EquipName(ZoneEquipTypeNum), true, 0);
1025 40 : thisZoneEquipList.EquipIndex(ZoneEquipTypeNum) = thisZoneEquipList.compPointer[ZoneEquipTypeNum]->getEquipIndex();
1026 : }
1027 :
1028 358 : if (thisZoneEquipList.EquipType(ZoneEquipTypeNum) == ZoneEquipType::Invalid) {
1029 0 : ShowSevereError(state, format("{}{} = {}", RoutineName, CurrentModuleObject, thisZoneEquipList.Name));
1030 0 : ShowContinueError(state, format("..Invalid Equipment Type = {}", thisZoneEquipList.EquipType(ZoneEquipTypeNum)));
1031 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1032 : }
1033 659 : }
1034 : } // End parsing all extensible Zone Equipment info
1035 :
1036 : // Check for multiple assignments
1037 660 : for (int ZoneEquipTypeNum = 1; ZoneEquipTypeNum <= thisZoneEquipList.NumOfEquipTypes; ++ZoneEquipTypeNum) {
1038 358 : if (count_eq(thisZoneEquipList.CoolingPriority, ZoneEquipTypeNum) > 1) {
1039 0 : ShowSevereError(state, format("{}{} = {}", RoutineName, CurrentModuleObject, thisZoneEquipList.Name));
1040 0 : ShowContinueError(state,
1041 0 : format("...multiple assignments for Zone Equipment Cooling Sequence={}, must be 1-1 correspondence between "
1042 : "sequence assignments and number of equipments.",
1043 : ZoneEquipTypeNum));
1044 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1045 358 : } else if (count_eq(thisZoneEquipList.CoolingPriority, ZoneEquipTypeNum) == 0) {
1046 3 : ShowWarningError(state, format("{}{} = {}", RoutineName, CurrentModuleObject, thisZoneEquipList.Name));
1047 6 : ShowContinueError(state,
1048 6 : format("...zero assigned to Zone Equipment Cooling Sequence={}, apparent gap in sequence assignments in "
1049 : "this equipment list.",
1050 : ZoneEquipTypeNum));
1051 : }
1052 358 : if (count_eq(thisZoneEquipList.HeatingPriority, ZoneEquipTypeNum) > 1) {
1053 0 : ShowSevereError(state, format("{}{} = {}", RoutineName, CurrentModuleObject, thisZoneEquipList.Name));
1054 0 : ShowContinueError(state,
1055 0 : format("...multiple assignments for Zone Equipment Heating or No-Load Sequence={}, must be 1-1 "
1056 : "correspondence between sequence assignments and number of equipments.",
1057 : ZoneEquipTypeNum));
1058 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1059 358 : } else if (count_eq(thisZoneEquipList.HeatingPriority, ZoneEquipTypeNum) == 0) {
1060 0 : ShowWarningError(state, format("{}{} = {}", RoutineName, CurrentModuleObject, thisZoneEquipList.Name));
1061 0 : ShowContinueError(state,
1062 0 : format("...zero assigned to Zone Equipment Heating or No-Load Sequence={}, apparent gap in sequence "
1063 : "assignments in this equipment list.",
1064 : ZoneEquipTypeNum));
1065 : }
1066 : }
1067 302 : } // End ZoneHVAC:EquipmentList
1068 302 : }
1069 302 : bool NodeListError = false;
1070 302 : int NumNodes = 0;
1071 604 : GetNodeNums(state,
1072 : InletNodeListName,
1073 : NumNodes,
1074 : NodeNums,
1075 : NodeListError,
1076 : DataLoopNode::NodeFluidType::Air,
1077 : (isSpace ? DataLoopNode::ConnectionObjectType::SpaceHVACEquipmentConnections
1078 : : DataLoopNode::ConnectionObjectType::ZoneHVACEquipmentConnections),
1079 302 : thisEquipConfig.ZoneName,
1080 : DataLoopNode::ConnectionType::ZoneInlet,
1081 : NodeInputManager::CompFluidStream::Primary,
1082 : DataLoopNode::ObjectIsNotParent);
1083 :
1084 302 : if (!NodeListError) {
1085 302 : thisEquipConfig.NumInletNodes = NumNodes;
1086 :
1087 302 : thisEquipConfig.InletNode.allocate(NumNodes);
1088 302 : thisEquipConfig.InletNodeAirLoopNum.allocate(NumNodes);
1089 302 : thisEquipConfig.InletNodeADUNum.allocate(NumNodes);
1090 302 : thisEquipConfig.AirDistUnitCool.allocate(NumNodes);
1091 302 : thisEquipConfig.AirDistUnitHeat.allocate(NumNodes);
1092 :
1093 623 : for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
1094 321 : thisEquipConfig.InletNode(NodeNum) = NodeNums(NodeNum);
1095 321 : bool UniqueNodeError = false;
1096 642 : NodeInputManager::CheckUniqueNodeNumbers(state, "Zone Air Inlet Nodes", UniqueNodeError, NodeNums(NodeNum), thisEquipConfig.ZoneName);
1097 321 : if (UniqueNodeError) {
1098 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1099 : }
1100 321 : thisEquipConfig.InletNodeAirLoopNum(NodeNum) = 0;
1101 321 : thisEquipConfig.InletNodeADUNum(NodeNum) = 0;
1102 321 : thisEquipConfig.AirDistUnitCool(NodeNum).InNode = 0;
1103 321 : thisEquipConfig.AirDistUnitHeat(NodeNum).InNode = 0;
1104 321 : thisEquipConfig.AirDistUnitCool(NodeNum).OutNode = 0;
1105 321 : thisEquipConfig.AirDistUnitHeat(NodeNum).OutNode = 0;
1106 321 : if (!isSpace) {
1107 321 : ++locTermUnitSizingCounter;
1108 321 : thisEquipConfig.AirDistUnitCool(NodeNum).TermUnitSizingIndex = locTermUnitSizingCounter;
1109 321 : thisEquipConfig.AirDistUnitHeat(NodeNum).TermUnitSizingIndex = locTermUnitSizingCounter;
1110 : }
1111 : }
1112 : } else {
1113 0 : ShowContinueError(
1114 : state,
1115 0 : format("Invalid Zone Air Inlet Node or NodeList Name in ZoneHVAC:EquipmentConnections object, for Zone = {}", thisEquipConfig.ZoneName));
1116 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1117 : }
1118 :
1119 302 : NodeListError = false;
1120 604 : GetNodeNums(state,
1121 : ExhaustNodeListName,
1122 : NumNodes,
1123 : NodeNums,
1124 : NodeListError,
1125 : DataLoopNode::NodeFluidType::Air,
1126 : (isSpace ? DataLoopNode::ConnectionObjectType::SpaceHVACEquipmentConnections
1127 : : DataLoopNode::ConnectionObjectType::ZoneHVACEquipmentConnections),
1128 302 : thisEquipConfig.ZoneName,
1129 : DataLoopNode::ConnectionType::ZoneExhaust,
1130 : NodeInputManager::CompFluidStream::Primary,
1131 : DataLoopNode::ObjectIsNotParent);
1132 :
1133 302 : if (!NodeListError) {
1134 302 : thisEquipConfig.NumExhaustNodes = NumNodes;
1135 :
1136 302 : thisEquipConfig.ExhaustNode.allocate(NumNodes);
1137 :
1138 504 : for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
1139 202 : thisEquipConfig.ExhaustNode(NodeNum) = NodeNums(NodeNum);
1140 202 : bool UniqueNodeError = false;
1141 404 : NodeInputManager::CheckUniqueNodeNumbers(state, "Zone Air Exhaust Nodes", UniqueNodeError, NodeNums(NodeNum), thisEquipConfig.ZoneName);
1142 202 : if (UniqueNodeError) {
1143 : // ShowContinueError(state, format("Occurs for Zone = {}", trim( AlphArray( 1 ) )));
1144 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1145 : }
1146 : }
1147 : } else {
1148 0 : ShowContinueError(
1149 : state,
1150 0 : format("Invalid Zone Air Exhaust Node or NodeList Name in ZoneHVAC:EquipmentConnections object, for Zone={}", thisEquipConfig.ZoneName));
1151 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1152 : }
1153 :
1154 302 : NodeListError = false;
1155 604 : GetNodeNums(state,
1156 : ReturnNodeListName,
1157 : NumNodes,
1158 : NodeNums,
1159 : NodeListError,
1160 : DataLoopNode::NodeFluidType::Air,
1161 : (isSpace ? DataLoopNode::ConnectionObjectType::SpaceHVACEquipmentConnections
1162 : : DataLoopNode::ConnectionObjectType::ZoneHVACEquipmentConnections),
1163 302 : thisEquipConfig.ZoneName,
1164 : DataLoopNode::ConnectionType::ZoneReturn,
1165 : NodeInputManager::CompFluidStream::Primary,
1166 : DataLoopNode::ObjectIsNotParent);
1167 :
1168 302 : if (!NodeListError) {
1169 302 : thisEquipConfig.NumReturnNodes = NumNodes;
1170 :
1171 302 : thisEquipConfig.ReturnNode.allocate(NumNodes);
1172 302 : thisEquipConfig.returnNodeSpaceMixerIndex.allocate(NumNodes);
1173 602 : for (int &mixIndex : thisEquipConfig.returnNodeSpaceMixerIndex) {
1174 300 : mixIndex = -1;
1175 : }
1176 302 : thisEquipConfig.ReturnNodeAirLoopNum.allocate(NumNodes);
1177 302 : thisEquipConfig.ReturnNodeRetPathNum.allocate(NumNodes);
1178 302 : thisEquipConfig.ReturnNodeRetPathCompNum.allocate(NumNodes);
1179 302 : thisEquipConfig.ReturnNodeInletNum.allocate(NumNodes);
1180 302 : thisEquipConfig.FixedReturnFlow.allocate(NumNodes);
1181 302 : thisEquipConfig.ReturnNodePlenumNum.allocate(NumNodes);
1182 302 : thisEquipConfig.ReturnNodeExhaustNodeNum.allocate(NumNodes);
1183 302 : thisEquipConfig.SharedExhaustNode.allocate(NumNodes);
1184 302 : thisEquipConfig.ReturnNode = 0; // initialize to zero here
1185 302 : thisEquipConfig.ReturnNodeAirLoopNum = 0; // initialize to zero here
1186 302 : thisEquipConfig.ReturnNodeInletNum = 0; // initialize to zero here
1187 302 : thisEquipConfig.ReturnNodeRetPathNum = 0;
1188 302 : thisEquipConfig.ReturnNodeRetPathCompNum = 0;
1189 302 : thisEquipConfig.FixedReturnFlow = false; // initialize to false here
1190 302 : thisEquipConfig.ReturnNodePlenumNum = 0; // initialize to zero here
1191 302 : thisEquipConfig.ReturnNodeExhaustNodeNum = 0; // initialize to zero here
1192 302 : thisEquipConfig.SharedExhaustNode = LightReturnExhaustConfig::NoExhast; // initialize to zero here
1193 :
1194 602 : for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
1195 300 : thisEquipConfig.ReturnNode(NodeNum) = NodeNums(NodeNum);
1196 300 : bool UniqueNodeError = false;
1197 600 : NodeInputManager::CheckUniqueNodeNumbers(state, "Zone Return Air Nodes", UniqueNodeError, NodeNums(NodeNum), thisEquipConfig.ZoneName);
1198 300 : if (UniqueNodeError) {
1199 : // ShowContinueError(state, format("Occurs for Zone = {}", trim( AlphArray( 1 ) )));
1200 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1201 : }
1202 : }
1203 : } else {
1204 0 : ShowContinueError(
1205 : state,
1206 0 : format("Invalid Zone Return Air Node or NodeList Name in ZoneHVAC:EquipmentConnections object, for Zone={}", thisEquipConfig.ZoneName));
1207 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1208 : }
1209 :
1210 302 : NodeListError = false;
1211 604 : GetNodeNums(state,
1212 : ReturnFlowBasisNodeListName,
1213 : NumNodes,
1214 : NodeNums,
1215 : NodeListError,
1216 : DataLoopNode::NodeFluidType::Air,
1217 : (isSpace ? DataLoopNode::ConnectionObjectType::SpaceHVACEquipmentConnections
1218 : : DataLoopNode::ConnectionObjectType::ZoneHVACEquipmentConnections),
1219 302 : thisEquipConfig.ZoneName,
1220 : DataLoopNode::ConnectionType::Sensor,
1221 : NodeInputManager::CompFluidStream::Primary,
1222 : DataLoopNode::ObjectIsNotParent);
1223 :
1224 302 : if (!NodeListError) {
1225 302 : thisEquipConfig.NumReturnFlowBasisNodes = NumNodes;
1226 :
1227 302 : thisEquipConfig.ReturnFlowBasisNode.allocate(NumNodes);
1228 :
1229 305 : for (int NodeNum = 1; NodeNum <= NumNodes; ++NodeNum) {
1230 3 : thisEquipConfig.ReturnFlowBasisNode(NodeNum) = NodeNums(NodeNum);
1231 : }
1232 : } else {
1233 0 : ShowContinueError(
1234 : state,
1235 0 : format("Invalid Zone Return Air Node 1 Flow Rate Basis Node or NodeList Name in ZoneHVAC:EquipmentConnections object, for Zone={}",
1236 0 : thisEquipConfig.ZoneName));
1237 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1238 : }
1239 302 : }
1240 :
1241 0 : void processZoneEquipSplitterInput(EnergyPlusData &state,
1242 : std::string_view zeqSplitterModuleObject,
1243 : int const zeqSplitterNum,
1244 : int const zoneNum,
1245 : InputProcessor::json const objectSchemaProps,
1246 : InputProcessor::json const objectFields,
1247 : DataZoneEquipment::ZoneEquipmentSplitter &thisZeqSplitter)
1248 :
1249 : {
1250 : static constexpr std::string_view RoutineName("processZoneEquipSplitterInput: "); // include trailing blank space
1251 0 : auto &ip = state.dataInputProcessing->inputProcessor;
1252 0 : std::string const zeqTypeName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_equipment_object_type");
1253 0 : thisZeqSplitter.zoneEquipType = DataZoneEquipment::ZoneEquipType(getEnumValue(zoneEquipTypeNamesUC, zeqTypeName));
1254 0 : if (thisZeqSplitter.zoneEquipType == ZoneEquipType::Invalid) {
1255 0 : ShowSevereError(state, format("{}{} = {}", RoutineName, zeqSplitterModuleObject, thisZeqSplitter.Name));
1256 0 : ShowContinueError(state, format("..Invalid Equipment Type = {}", zeqTypeName));
1257 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1258 : }
1259 :
1260 0 : thisZeqSplitter.zoneEquipName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_equipment_name");
1261 :
1262 : // Search zone equipment list for matching equip type and name
1263 0 : bool found = false;
1264 0 : auto &thisZoneEqList = state.dataZoneEquip->ZoneEquipList(state.dataZoneEquip->ZoneEquipConfig(zoneNum).EquipListIndex);
1265 0 : for (int eqCount = 1; eqCount <= thisZoneEqList.NumOfEquipTypes; ++eqCount) {
1266 0 : if (thisZeqSplitter.zoneEquipType == thisZoneEqList.EquipType(eqCount)) {
1267 0 : if (thisZeqSplitter.zoneEquipName == thisZoneEqList.EquipName(eqCount)) {
1268 0 : found = true;
1269 : // Set index in zone equipment list pointing to this SpaceHVAC:ZoneEquipmentSplitter
1270 0 : thisZoneEqList.zoneEquipSplitterIndex = zeqSplitterNum;
1271 : // SpaceHVAC TODO: Outletnodes aren't know yet - need to set this in a later init
1272 : // thisZeqSplitter.zoneEquipOutletNodeNum = thisZoneEqList.EquipData(eqCount).OutletNodeNums(1);
1273 0 : break;
1274 : }
1275 : }
1276 : }
1277 0 : if (!found) {
1278 0 : ShowSevereError(state, format("{}{} = {}", RoutineName, zeqSplitterModuleObject, thisZeqSplitter.Name));
1279 0 : ShowContinueError(
1280 0 : state, format(".. Zone Equipment Object Type={} and Zone Equipment Name={} not found", zeqTypeName, thisZeqSplitter.zoneEquipName));
1281 0 : ShowContinueError(state, format(".. in ZoneHVAC:EquipmentList={}", thisZoneEqList.Name));
1282 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1283 0 : return;
1284 : }
1285 :
1286 0 : bool objectIsParent = true;
1287 0 : thisZeqSplitter.zoneEquipOutletNodeNum =
1288 0 : GetOnlySingleNode(state,
1289 0 : ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_equipment_outlet_node_name"),
1290 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound,
1291 : thisZeqSplitter.spaceEquipType,
1292 0 : thisZeqSplitter.Name,
1293 : DataLoopNode::NodeFluidType::Air,
1294 : DataLoopNode::ConnectionType::Inlet,
1295 : NodeInputManager::CompFluidStream::Primary,
1296 : objectIsParent);
1297 :
1298 0 : thisZeqSplitter.tstatControl = DataZoneEquipment::ZoneEquipTstatControl(
1299 0 : getEnumValue(zoneEquipTstatControlNamesUC, ip->getAlphaFieldValue(objectFields, objectSchemaProps, "thermostat_control_method")));
1300 0 : if (thisZeqSplitter.tstatControl == DataZoneEquipment::ZoneEquipTstatControl::SingleSpace) {
1301 0 : std::string spaceName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "control_space_name");
1302 0 : thisZeqSplitter.controlSpaceIndex = Util::FindItemInList(spaceName, state.dataHeatBal->space);
1303 0 : if (thisZeqSplitter.controlSpaceIndex == 0) {
1304 0 : ShowSevereError(state, format("{}{}={}", RoutineName, zeqSplitterModuleObject, thisZeqSplitter.Name));
1305 0 : ShowContinueError(state, format("Space Name={} not found.", spaceName));
1306 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1307 : }
1308 0 : }
1309 0 : thisZeqSplitter.spaceSizingBasis = DataZoneEquipment::SpaceEquipSizingBasis(
1310 0 : getEnumValue(spaceEquipSizingBasisNamesUC, ip->getAlphaFieldValue(objectFields, objectSchemaProps, "space_fraction_method")));
1311 :
1312 0 : auto extensibles = objectFields.find("spaces");
1313 0 : auto const &extensionSchemaProps = objectSchemaProps["spaces"]["items"]["properties"];
1314 0 : if (extensibles != objectFields.end()) {
1315 0 : auto &extensiblesArray = extensibles.value();
1316 0 : int const numSpaces = extensiblesArray.size();
1317 0 : thisZeqSplitter.spaces.resize(numSpaces);
1318 0 : int spaceCount = -1;
1319 0 : for (auto &extensibleInstance : extensiblesArray) {
1320 0 : ++spaceCount;
1321 0 : auto &thisZeqSpace = thisZeqSplitter.spaces[spaceCount];
1322 0 : std::string const spaceName = ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "space_name");
1323 0 : thisZeqSpace.spaceIndex = Util::FindItemInList(spaceName, state.dataHeatBal->space);
1324 0 : if (thisZeqSpace.spaceIndex == 0) {
1325 0 : ShowSevereError(state, format("{}{}={}", RoutineName, zeqSplitterModuleObject, thisZeqSplitter.Name));
1326 0 : ShowContinueError(state, format("Space Name={} not found.", spaceName));
1327 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1328 : } else {
1329 0 : thisZeqSpace.fraction = ip->getRealFieldValue(extensibleInstance, extensionSchemaProps, "space_fraction");
1330 0 : thisZeqSpace.spaceNodeNum =
1331 0 : GetOnlySingleNode(state,
1332 0 : ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "space_supply_node_name"),
1333 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound,
1334 : thisZeqSplitter.spaceEquipType,
1335 0 : thisZeqSplitter.Name,
1336 : DataLoopNode::NodeFluidType::Air,
1337 : DataLoopNode::ConnectionType::Outlet,
1338 : NodeInputManager::CompFluidStream::Primary,
1339 : objectIsParent);
1340 0 : if (thisZeqSplitter.controlSpaceIndex == thisZeqSpace.spaceIndex) {
1341 0 : thisZeqSplitter.controlSpaceNumber = spaceCount;
1342 : }
1343 : }
1344 0 : }
1345 : }
1346 0 : }
1347 :
1348 0 : void processZoneEquipMixerInput(EnergyPlusData &state,
1349 : std::string_view zeqMixerModuleObject,
1350 : int const zoneNum,
1351 : InputProcessor::json const objectSchemaProps,
1352 : InputProcessor::json const objectFields,
1353 : DataZoneEquipment::ZoneEquipmentMixer &thisZeqMixer)
1354 :
1355 : {
1356 : static constexpr std::string_view RoutineName("processZoneEquipMixerInput: "); // include trailing blank space
1357 0 : auto &ip = state.dataInputProcessing->inputProcessor;
1358 0 : bool objectIsParent = true;
1359 0 : thisZeqMixer.outletNodeNum = GetOnlySingleNode(state,
1360 0 : ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_equipment_inlet_node_name"),
1361 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound,
1362 : thisZeqMixer.spaceEquipType,
1363 0 : thisZeqMixer.Name,
1364 : DataLoopNode::NodeFluidType::Air,
1365 : DataLoopNode::ConnectionType::Outlet,
1366 : NodeInputManager::CompFluidStream::Primary,
1367 : objectIsParent);
1368 : // Check zone exhaust nodes
1369 0 : bool found = false;
1370 0 : auto &thisZoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(zoneNum);
1371 0 : for (int exhNodeNum : thisZoneEquipConfig.ExhaustNode) {
1372 0 : if (thisZeqMixer.outletNodeNum == exhNodeNum) {
1373 0 : found = true;
1374 0 : break;
1375 : }
1376 : }
1377 0 : if (!found) {
1378 0 : ShowSevereError(state, format("{}{}={}", RoutineName, zeqMixerModuleObject, thisZeqMixer.Name));
1379 0 : ShowContinueError(state,
1380 0 : format("Zone Equipment Inlet Node Name={} is not an exhaust node for ZoneHVAC:EquipmentConnections={}.",
1381 0 : state.dataLoopNodes->NodeID(thisZeqMixer.outletNodeNum),
1382 0 : thisZoneEquipConfig.ZoneName));
1383 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1384 : }
1385 :
1386 0 : thisZeqMixer.spaceSizingBasis = DataZoneEquipment::SpaceEquipSizingBasis(
1387 0 : getEnumValue(spaceEquipSizingBasisNamesUC, ip->getAlphaFieldValue(objectFields, objectSchemaProps, "space_fraction_method")));
1388 :
1389 0 : auto extensibles = objectFields.find("spaces");
1390 0 : auto const &extensionSchemaProps = objectSchemaProps["spaces"]["items"]["properties"];
1391 0 : if (extensibles != objectFields.end()) {
1392 0 : auto &extensiblesArray = extensibles.value();
1393 0 : int const numSpaces = extensiblesArray.size();
1394 0 : thisZeqMixer.spaces.resize(numSpaces);
1395 0 : int spaceCount = -1;
1396 0 : for (auto &extensibleInstance : extensiblesArray) {
1397 0 : ++spaceCount;
1398 0 : auto &thisZeqSpace = thisZeqMixer.spaces[spaceCount];
1399 0 : std::string const spaceName = ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "space_name");
1400 0 : thisZeqSpace.spaceIndex = Util::FindItemInList(spaceName, state.dataHeatBal->space);
1401 0 : if (thisZeqSpace.spaceIndex == 0) {
1402 0 : ShowSevereError(state, format("{}{}={}", RoutineName, zeqMixerModuleObject, thisZeqMixer.Name));
1403 0 : ShowContinueError(state, format("Space Name={} not found.", spaceName));
1404 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1405 : } else {
1406 0 : thisZeqSpace.fraction = ip->getRealFieldValue(extensibleInstance, extensionSchemaProps, "space_fraction");
1407 0 : thisZeqSpace.spaceNodeNum = GetOnlySingleNode(state,
1408 0 : ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "space_node_name"),
1409 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound,
1410 : thisZeqMixer.spaceEquipType,
1411 0 : thisZeqMixer.Name,
1412 : DataLoopNode::NodeFluidType::Air,
1413 : DataLoopNode::ConnectionType::Inlet,
1414 : NodeInputManager::CompFluidStream::Primary,
1415 : objectIsParent);
1416 : // Check space exhaust nodes
1417 0 : found = false;
1418 0 : auto &thisSpaceEquipConfig = state.dataZoneEquip->spaceEquipConfig(thisZeqSpace.spaceIndex);
1419 0 : for (int exhNodeNum : thisSpaceEquipConfig.ExhaustNode) {
1420 0 : if (thisZeqSpace.spaceNodeNum == exhNodeNum) {
1421 0 : found = true;
1422 0 : break;
1423 : }
1424 : }
1425 0 : if (!found) {
1426 0 : ShowSevereError(state, format("{}{}={}", RoutineName, zeqMixerModuleObject, thisZeqMixer.Name));
1427 0 : ShowContinueError(state,
1428 0 : format("Space Node Name={} is not an exhaust node for SpaceHVAC:EquipmentConnections={}.",
1429 0 : state.dataLoopNodes->NodeID(thisZeqSpace.spaceNodeNum),
1430 0 : thisSpaceEquipConfig.ZoneName));
1431 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1432 : }
1433 : }
1434 0 : }
1435 : }
1436 0 : }
1437 :
1438 0 : void processZoneReturnMixerInput(EnergyPlusData &state,
1439 : std::string_view zeqMixerModuleObject,
1440 : int const zoneNum,
1441 : InputProcessor::json const objectSchemaProps,
1442 : InputProcessor::json const objectFields,
1443 : int mixerIndex)
1444 :
1445 : {
1446 : static constexpr std::string_view RoutineName("processZoneReturnMixerInput: "); // include trailing blank space
1447 0 : auto &ip = state.dataInputProcessing->inputProcessor;
1448 0 : bool objectIsParent = true;
1449 0 : auto &thisZretMixer = state.dataZoneEquip->zoneReturnMixer[mixerIndex];
1450 0 : thisZretMixer.outletNodeNum = GetOnlySingleNode(state,
1451 0 : ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_return_air_node_name"),
1452 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound,
1453 : thisZretMixer.spaceEquipType,
1454 0 : thisZretMixer.Name,
1455 : DataLoopNode::NodeFluidType::Air,
1456 : DataLoopNode::ConnectionType::Outlet,
1457 : NodeInputManager::CompFluidStream::Primary,
1458 : objectIsParent);
1459 : // Check zone return nodes
1460 0 : bool found = false;
1461 0 : auto &thisZoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(zoneNum);
1462 0 : int nodeCounter = 0;
1463 0 : for (int retNodeNum : thisZoneEquipConfig.ReturnNode) {
1464 0 : ++nodeCounter;
1465 0 : if (thisZretMixer.outletNodeNum == retNodeNum) {
1466 0 : found = true;
1467 : // Zone return node is fed by a space return mixer
1468 0 : thisZoneEquipConfig.returnNodeSpaceMixerIndex(nodeCounter) = mixerIndex;
1469 0 : break;
1470 : }
1471 : }
1472 0 : if (!found) {
1473 0 : ShowSevereError(state, format("{}{}={}", RoutineName, zeqMixerModuleObject, thisZretMixer.Name));
1474 0 : ShowContinueError(state,
1475 0 : format("Zone Equipment Return Air Node Name={} is not a return air node for ZoneHVAC:EquipmentConnections={}.",
1476 0 : state.dataLoopNodes->NodeID(thisZretMixer.outletNodeNum),
1477 0 : thisZoneEquipConfig.ZoneName));
1478 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1479 : }
1480 :
1481 0 : auto extensibles = objectFields.find("spaces");
1482 0 : auto const &extensionSchemaProps = objectSchemaProps["spaces"]["items"]["properties"];
1483 0 : if (extensibles != objectFields.end()) {
1484 0 : auto &extensiblesArray = extensibles.value();
1485 0 : int const numSpaces = extensiblesArray.size();
1486 0 : thisZretMixer.spaces.resize(numSpaces);
1487 0 : int spaceCount = -1;
1488 0 : for (auto &extensibleInstance : extensiblesArray) {
1489 0 : ++spaceCount;
1490 0 : auto &thisZeqSpace = thisZretMixer.spaces[spaceCount];
1491 0 : std::string const spaceName = ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "space_name");
1492 0 : thisZeqSpace.spaceIndex = Util::FindItemInList(spaceName, state.dataHeatBal->space);
1493 0 : if (thisZeqSpace.spaceIndex == 0) {
1494 0 : ShowSevereError(state, format("{}{}={}", RoutineName, zeqMixerModuleObject, thisZretMixer.Name));
1495 0 : ShowContinueError(state, format("Space Name={} not found.", spaceName));
1496 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1497 : } else {
1498 0 : thisZeqSpace.spaceNodeNum =
1499 0 : GetOnlySingleNode(state,
1500 0 : ip->getAlphaFieldValue(extensibleInstance, extensionSchemaProps, "space_return_air_node_name"),
1501 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound,
1502 : thisZretMixer.spaceEquipType,
1503 0 : thisZretMixer.Name,
1504 : DataLoopNode::NodeFluidType::Air,
1505 : DataLoopNode::ConnectionType::Inlet,
1506 : NodeInputManager::CompFluidStream::Primary,
1507 : objectIsParent);
1508 : // Check space return nodes
1509 0 : found = false;
1510 0 : auto &thisSpaceEquipConfig = state.dataZoneEquip->spaceEquipConfig(thisZeqSpace.spaceIndex);
1511 0 : for (int retNodeNum : thisSpaceEquipConfig.ReturnNode) {
1512 0 : if (thisZeqSpace.spaceNodeNum == retNodeNum) {
1513 0 : found = true;
1514 0 : break;
1515 : }
1516 : }
1517 0 : if (!found) {
1518 0 : ShowSevereError(state, format("{}{}={}", RoutineName, zeqMixerModuleObject, thisZretMixer.Name));
1519 0 : ShowContinueError(state,
1520 0 : format("Space Return Air Node Name={} is not a return air node for SpaceHVAC:EquipmentConnections={}.",
1521 0 : state.dataLoopNodes->NodeID(thisZeqSpace.spaceNodeNum),
1522 0 : thisSpaceEquipConfig.ZoneName));
1523 0 : state.dataZoneEquip->GetZoneEquipmentDataErrorsFound = true;
1524 : }
1525 : }
1526 0 : }
1527 : }
1528 0 : }
1529 :
1530 80 : bool CheckZoneEquipmentList(EnergyPlusData &state,
1531 : std::string_view const ComponentType, // Type of component
1532 : std::string_view const ComponentName, // Name of component
1533 : ObjexxFCL::Optional_int CtrlZoneNum)
1534 : {
1535 :
1536 : // FUNCTION INFORMATION:
1537 : // AUTHOR Linda Lawrie
1538 : // DATE WRITTEN May 2007
1539 : // MODIFIED na
1540 : // RE-ENGINEERED na
1541 :
1542 : // PURPOSE OF THIS FUNCTION:
1543 : // Provides a way to check if a component name is listed on a zone equipment list.
1544 :
1545 : // Return value
1546 : bool IsOnList; // True if item is on a list, false if not.
1547 :
1548 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1549 : int Loop;
1550 : int ListLoop;
1551 : int CtrlZoneNumLocal;
1552 :
1553 80 : CtrlZoneNumLocal = 0;
1554 80 : IsOnList = false;
1555 145 : for (Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) { // NumOfZoneEquipLists
1556 145 : if (state.dataZoneEquip->ZoneEquipList(Loop).Name.empty()) {
1557 26 : continue; // dimensioned by NumOfZones. Only valid ones have names.
1558 : }
1559 188 : for (ListLoop = 1; ListLoop <= state.dataZoneEquip->ZoneEquipList(Loop).NumOfEquipTypes; ++ListLoop) {
1560 :
1561 149 : if (!Util::SameString(state.dataZoneEquip->ZoneEquipList(Loop).EquipTypeName(ListLoop), ComponentType)) {
1562 30 : continue;
1563 : }
1564 119 : if (ComponentName == "*") {
1565 0 : IsOnList = true;
1566 0 : CtrlZoneNumLocal = Loop;
1567 0 : goto EquipList_exit;
1568 : }
1569 119 : if (!Util::SameString(state.dataZoneEquip->ZoneEquipList(Loop).EquipName(ListLoop), ComponentName)) {
1570 39 : continue;
1571 : }
1572 80 : IsOnList = true;
1573 80 : CtrlZoneNumLocal = Loop;
1574 80 : goto EquipList_exit;
1575 : }
1576 : }
1577 0 : EquipList_exit:;
1578 80 : if (present(CtrlZoneNum)) {
1579 0 : CtrlZoneNum = CtrlZoneNumLocal;
1580 : }
1581 80 : return IsOnList;
1582 : }
1583 :
1584 14 : int GetControlledZoneIndex(EnergyPlusData &state, std::string const &ZoneName) // Zone name to match into Controlled Zone structure
1585 : {
1586 :
1587 : // FUNCTION INFORMATION:
1588 : // AUTHOR Linda Lawrie
1589 : // DATE WRITTEN March 2008
1590 :
1591 : // PURPOSE OF THIS FUNCTION:
1592 : // This function returns the index into the Controlled Zone Equipment structure
1593 : // of the indicated zone.
1594 :
1595 14 : return Util::FindItemInList(ZoneName, state.dataZoneEquip->ZoneEquipConfig, &EquipConfiguration::ZoneName);
1596 : }
1597 :
1598 0 : int FindControlledZoneIndexFromSystemNodeNumberForZone(EnergyPlusData &state,
1599 : int const TrialZoneNodeNum) // Node number to match into Controlled Zone structure
1600 : {
1601 :
1602 : // FUNCTION INFORMATION:
1603 : // AUTHOR Brent Griffith
1604 : // DATE WRITTEN August 2013
1605 :
1606 : // PURPOSE OF THIS FUNCTION:
1607 : // This function returns the zone number for the indicated
1608 : // zone node num. Returns 0 if did not find zone node in any Zone
1609 :
1610 0 : int ControlledZoneIndex = 0; // Index into Controlled Zone structure
1611 :
1612 0 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1613 0 : if (state.dataZoneEquip->ZoneEquipConfig(ZoneNum).IsControlled) {
1614 0 : if (TrialZoneNodeNum == state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ZoneNode) {
1615 : // found it.
1616 0 : ControlledZoneIndex = ZoneNum;
1617 0 : break;
1618 : }
1619 : }
1620 : }
1621 :
1622 0 : return ControlledZoneIndex;
1623 : }
1624 :
1625 11 : int GetSystemNodeNumberForZone(EnergyPlusData &state, int const zoneNum)
1626 : {
1627 :
1628 : // FUNCTION INFORMATION:
1629 : // AUTHOR Linda Lawrie
1630 : // DATE WRITTEN March 2008
1631 :
1632 : // PURPOSE OF THIS FUNCTION:
1633 : // This function returns the system node number for the indicated
1634 : // zone. Returns 0 if the Zone is not a controlled zone.
1635 :
1636 11 : int SystemZoneNodeNumber = 0; // System node number for controlled zone
1637 :
1638 11 : if (zoneNum > 0) {
1639 10 : if (state.dataZoneEquip->ZoneEquipConfig(zoneNum).IsControlled) {
1640 10 : SystemZoneNodeNumber = state.dataZoneEquip->ZoneEquipConfig(zoneNum).ZoneNode;
1641 : }
1642 : }
1643 :
1644 11 : return SystemZoneNodeNumber;
1645 : }
1646 :
1647 0 : int GetReturnAirNodeForZone(EnergyPlusData &state,
1648 : int const zoneNum,
1649 : std::string const &NodeName, // Return air node name to match (may be blank)
1650 : std::string const &calledFromDescription // String identifying the calling function and object
1651 : )
1652 : {
1653 :
1654 : // FUNCTION INFORMATION:
1655 : // AUTHOR Linda Lawrie
1656 : // DATE WRITTEN March 2008
1657 : // MODIFIED Feb 2017 expanded for multiple return nodes in a zone
1658 :
1659 : // PURPOSE OF THIS FUNCTION:
1660 : // This function returns the return air node number for the indicated
1661 : // zone and node name. If NodeName is blank, return the first return node number,
1662 : // otherwise return the node number of the matching return node name.
1663 : // Returns 0 if the Zone is not a controlled zone or the node name does not match.
1664 :
1665 : // Return value
1666 0 : int ReturnAirNodeNumber = 0; // Return Air node number for controlled zone
1667 :
1668 0 : ReturnAirNodeNumber = 0; // default is not found
1669 0 : if (zoneNum > 0) {
1670 : {
1671 0 : auto const &thisZoneEquip(state.dataZoneEquip->ZoneEquipConfig(zoneNum));
1672 0 : if (thisZoneEquip.IsControlled) {
1673 0 : if (NodeName.empty()) {
1674 : // If NodeName is blank, return first return node number, but warn if there are multiple return nodes for this zone
1675 0 : ReturnAirNodeNumber = thisZoneEquip.ReturnNode(1);
1676 0 : if (thisZoneEquip.NumReturnNodes > 1) {
1677 0 : ShowWarningError(state,
1678 0 : format("GetReturnAirNodeForZone: {}, request for zone return node is ambiguous.", calledFromDescription));
1679 0 : ShowContinueError(state,
1680 0 : format("Zone={} has {} return nodes. First return node will be used.",
1681 0 : thisZoneEquip.ZoneName,
1682 0 : thisZoneEquip.NumReturnNodes));
1683 : }
1684 : } else {
1685 0 : for (int nodeCount = 1; nodeCount <= thisZoneEquip.NumReturnNodes; ++nodeCount) {
1686 0 : int curNodeNum = thisZoneEquip.ReturnNode(nodeCount);
1687 0 : if (NodeName == state.dataLoopNodes->NodeID(curNodeNum)) {
1688 0 : ReturnAirNodeNumber = curNodeNum;
1689 : }
1690 : }
1691 : }
1692 : }
1693 : }
1694 : }
1695 :
1696 0 : return ReturnAirNodeNumber;
1697 : }
1698 :
1699 74 : int GetReturnNumForZone(EnergyPlusData &state,
1700 : int const zoneNum,
1701 : std::string const &NodeName // Return air node name to match (may be blank)
1702 : )
1703 : {
1704 :
1705 : // PURPOSE OF THIS FUNCTION:
1706 : // This function returns the zone return number (not the node number) for the indicated
1707 : // zone and node name. If NodeName is blank, return 1 (the first return node)
1708 : // otherwise return the index of the matching return node name.
1709 : // Returns 0 if the Zone is not a controlled zone or the node name does not match.
1710 :
1711 : // Return value
1712 74 : int ReturnIndex = 0; // Return number for the given zone (not the node number)
1713 :
1714 74 : if (zoneNum > 0) {
1715 74 : if (state.dataZoneEquip->ZoneEquipConfig(zoneNum).IsControlled) {
1716 60 : if (NodeName.empty()) {
1717 : // If NodeName is blank, return first return node number
1718 58 : ReturnIndex = 1;
1719 : } else {
1720 4 : for (int nodeCount = 1; nodeCount <= state.dataZoneEquip->ZoneEquipConfig(zoneNum).NumReturnNodes; ++nodeCount) {
1721 2 : int curNodeNum = state.dataZoneEquip->ZoneEquipConfig(zoneNum).ReturnNode(nodeCount);
1722 2 : if (NodeName == state.dataLoopNodes->NodeID(curNodeNum)) {
1723 2 : ReturnIndex = nodeCount;
1724 : }
1725 : }
1726 : }
1727 : }
1728 : }
1729 :
1730 74 : return ReturnIndex;
1731 : }
1732 :
1733 2 : bool VerifyLightsExhaustNodeForZone(EnergyPlusData &state, int const ZoneNum, int const ZoneExhaustNodeNum)
1734 : {
1735 2 : bool exhaustNodeError = true;
1736 :
1737 2 : for (int ExhaustNum = 1; ExhaustNum <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumExhaustNodes; ++ExhaustNum) {
1738 2 : if (ZoneExhaustNodeNum == state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ExhaustNode(ExhaustNum)) {
1739 2 : exhaustNodeError = false;
1740 2 : break;
1741 : }
1742 : }
1743 :
1744 2 : return exhaustNodeError;
1745 : }
1746 :
1747 16 : void EquipList::getPrioritiesForInletNode(EnergyPlusData &state,
1748 : int const inletNodeNum, // Zone inlet node number to match
1749 : int &coolingPriority, // Cooling priority num for matching equipment
1750 : int &heatingPriority // Heating priority num for matching equipment
1751 : )
1752 : {
1753 16 : bool equipFound = false;
1754 24 : for (int equipNum = 1; equipNum <= this->NumOfEquipTypes; ++equipNum) {
1755 24 : if (this->EquipType(equipNum) == DataZoneEquipment::ZoneEquipType::AirDistributionUnit) {
1756 22 : if (inletNodeNum == state.dataDefineEquipment->AirDistUnit(this->EquipIndex(equipNum)).OutletNodeNum) {
1757 16 : equipFound = true;
1758 : }
1759 : }
1760 24 : if (equipFound) {
1761 16 : coolingPriority = this->CoolingPriority(equipNum);
1762 16 : heatingPriority = this->HeatingPriority(equipNum);
1763 16 : break;
1764 : }
1765 : }
1766 : // Set MinAirLoopIterationsAfterFirst for equipment that uses sequenced loads, based on zone equip load distribution scheme
1767 16 : int minIterations = state.dataHVACGlobal->MinAirLoopIterationsAfterFirst;
1768 16 : if (this->LoadDistScheme == DataZoneEquipment::LoadDist::Sequential) {
1769 : // Sequential needs one extra iterations up to the highest airterminal unit equipment number
1770 12 : minIterations = max(coolingPriority, heatingPriority, minIterations);
1771 4 : } else if (this->LoadDistScheme == DataZoneEquipment::LoadDist::Uniform) {
1772 : // Uniform needs one extra iteration which is the default
1773 4 : } else if (this->LoadDistScheme == DataZoneEquipment::LoadDist::UniformPLR) {
1774 : // UniformPLR needs two extra iterations, regardless of unit equipment number
1775 2 : minIterations = max(2, minIterations);
1776 2 : } else if (this->LoadDistScheme == DataZoneEquipment::LoadDist::SequentialUniformPLR) {
1777 : // SequentialUniformPLR needs one extra iterations up to the highest airterminal unit equipment number plus one more
1778 2 : minIterations = max((coolingPriority + 1), (heatingPriority + 1), minIterations);
1779 : }
1780 16 : state.dataHVACGlobal->MinAirLoopIterationsAfterFirst = minIterations;
1781 16 : }
1782 :
1783 325806 : Real64 EquipList::SequentialHeatingFraction([[maybe_unused]] EnergyPlusData &state, const int equipNum)
1784 : {
1785 325806 : return sequentialHeatingFractionScheds(equipNum)->getCurrentVal();
1786 : }
1787 :
1788 320727 : Real64 EquipList::SequentialCoolingFraction([[maybe_unused]] EnergyPlusData &state, const int equipNum)
1789 : {
1790 320727 : return sequentialCoolingFractionScheds(equipNum)->getCurrentVal();
1791 : }
1792 :
1793 48 : int GetZoneEquipControlledZoneNum(EnergyPlusData &state, DataZoneEquipment::ZoneEquipType const zoneEquipType, std::string const &EquipmentName)
1794 : {
1795 : static constexpr std::string_view RoutineName("GetZoneEquipControlledZoneNum: ");
1796 48 : int ControlZoneNum = 0;
1797 :
1798 73 : for (int CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
1799 72 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
1800 5 : continue;
1801 : }
1802 112 : for (int Num = 1; Num <= state.dataZoneEquip->ZoneEquipList(CtrlZone).NumOfEquipTypes; ++Num) {
1803 159 : if (zoneEquipType == state.dataZoneEquip->ZoneEquipList(CtrlZone).EquipType(Num) &&
1804 67 : Util::SameString(EquipmentName, state.dataZoneEquip->ZoneEquipList(CtrlZone).EquipName(Num))) {
1805 47 : return ControlZoneNum = CtrlZone;
1806 : }
1807 : }
1808 : }
1809 1 : ShowSevereError(state,
1810 1 : fmt::format("{}{}=\"{}\" is not on any ZoneHVAC:Equipmentlist. It will not be simulated.",
1811 : RoutineName,
1812 1 : zoneEquipTypeNamesUC[(int)zoneEquipType],
1813 : EquipmentName));
1814 1 : return ControlZoneNum;
1815 : }
1816 :
1817 2 : void CheckSharedExhaust(EnergyPlusData &state)
1818 : {
1819 2 : int ExhastNodeNum = 0;
1820 14 : for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
1821 12 : if (state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumReturnNodes < 2) {
1822 12 : continue;
1823 : }
1824 0 : for (int nodeCount = 1; nodeCount <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumReturnNodes; ++nodeCount) {
1825 0 : if (state.dataZoneEquip->ZoneEquipConfig(ZoneNum).SharedExhaustNode(nodeCount) == LightReturnExhaustConfig::Shared) {
1826 0 : continue;
1827 : }
1828 0 : ExhastNodeNum = state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ReturnNodeExhaustNodeNum(nodeCount);
1829 0 : if (ExhastNodeNum > 0) {
1830 0 : state.dataZoneEquip->ZoneEquipConfig(ZoneNum).SharedExhaustNode(nodeCount) = LightReturnExhaustConfig::Single;
1831 0 : for (int nodeCount1 = nodeCount + 1; nodeCount1 <= state.dataZoneEquip->ZoneEquipConfig(ZoneNum).NumReturnNodes; ++nodeCount1) {
1832 0 : if (ExhastNodeNum == state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ReturnNodeExhaustNodeNum(nodeCount1)) {
1833 0 : state.dataZoneEquip->ZoneEquipConfig(ZoneNum).SharedExhaustNode(nodeCount) = LightReturnExhaustConfig::Multi;
1834 0 : state.dataZoneEquip->ZoneEquipConfig(ZoneNum).SharedExhaustNode(nodeCount1) = LightReturnExhaustConfig::Shared;
1835 : }
1836 : }
1837 : }
1838 : }
1839 : }
1840 2 : }
1841 :
1842 277049 : void EquipConfiguration::setTotalInletFlows(EnergyPlusData &state)
1843 : {
1844 277049 : this->TotInletAirMassFlowRate = 0.0;
1845 277049 : Real64 TotInletAirMassFlowRateMax = 0.0;
1846 277049 : Real64 TotInletAirMassFlowRateMaxAvail = 0.0;
1847 277049 : Real64 TotInletAirMassFlowRateMin = 0.0;
1848 277049 : Real64 TotInletAirMassFlowRateMinAvail = 0.0;
1849 591812 : for (int NodeNum = 1; NodeNum <= this->NumInletNodes; ++NodeNum) {
1850 : {
1851 314763 : auto const &thisNode(state.dataLoopNodes->Node(this->InletNode(NodeNum)));
1852 314763 : this->TotInletAirMassFlowRate += thisNode.MassFlowRate;
1853 314763 : TotInletAirMassFlowRateMax += thisNode.MassFlowRateMax;
1854 314763 : TotInletAirMassFlowRateMaxAvail += thisNode.MassFlowRateMaxAvail;
1855 314763 : TotInletAirMassFlowRateMin += thisNode.MassFlowRateMin;
1856 314763 : TotInletAirMassFlowRateMinAvail += thisNode.MassFlowRateMinAvail;
1857 : }
1858 : }
1859 277049 : auto &zoneSpaceNode = state.dataLoopNodes->Node(this->ZoneNode);
1860 277049 : zoneSpaceNode.MassFlowRate = this->TotInletAirMassFlowRate;
1861 277049 : zoneSpaceNode.MassFlowRateMax = TotInletAirMassFlowRateMax;
1862 277049 : zoneSpaceNode.MassFlowRateMaxAvail = TotInletAirMassFlowRateMaxAvail;
1863 277049 : zoneSpaceNode.MassFlowRateMin = TotInletAirMassFlowRateMin;
1864 277049 : zoneSpaceNode.MassFlowRateMinAvail = TotInletAirMassFlowRateMinAvail;
1865 277049 : }
1866 :
1867 44508 : void scaleInletFlows(EnergyPlusData &state, int const zoneNodeNum, int const spaceNodeNum, Real64 const frac)
1868 : {
1869 44508 : assert(zoneNodeNum > 0);
1870 44508 : assert(spaceNodeNum > 0);
1871 44508 : auto const &zoneNode = state.dataLoopNodes->Node(zoneNodeNum);
1872 44508 : auto &spaceNode = state.dataLoopNodes->Node(spaceNodeNum);
1873 44508 : spaceNode.MassFlowRate = zoneNode.MassFlowRate * frac;
1874 44508 : spaceNode.MassFlowRateMax = zoneNode.MassFlowRateMax * frac;
1875 44508 : spaceNode.MassFlowRateMaxAvail = zoneNode.MassFlowRateMaxAvail * frac;
1876 44508 : spaceNode.MassFlowRateMin = zoneNode.MassFlowRateMin * frac;
1877 44508 : spaceNode.MassFlowRateMinAvail = zoneNode.MassFlowRateMinAvail * frac;
1878 44508 : }
1879 :
1880 0 : void ZoneEquipmentSplitterMixer::size(EnergyPlusData &state)
1881 : {
1882 : bool anyAutoSize =
1883 0 : std::any_of(spaces.begin(), spaces.end(), [](ZoneEquipSplitterMixerSpace const &s) { return s.fraction == DataSizing::AutoSize; });
1884 0 : if (!anyAutoSize) {
1885 0 : return;
1886 : }
1887 :
1888 0 : if (!state.dataHeatBal->doSpaceHeatBalanceSizing && (this->spaceSizingBasis == DataZoneEquipment::SpaceEquipSizingBasis::DesignCoolingLoad ||
1889 0 : (this->spaceSizingBasis == DataZoneEquipment::SpaceEquipSizingBasis::DesignHeatingLoad))) {
1890 0 : ShowSevereError(state,
1891 0 : format("ZoneEquipmentSplitterMixer::size: {} is unknown for {}={}. Unable to autosize Space Fractions.",
1892 0 : DataZoneEquipment::spaceEquipSizingBasisNamesUC[(int)this->spaceSizingBasis],
1893 0 : BranchNodeConnections::ConnectionObjectTypeNames[(int)this->spaceEquipType],
1894 0 : this->Name));
1895 0 : ShowFatalError(state,
1896 : "Set \"Do Space Heat Balance for Sizing\" to Yes in ZoneAirHeatBalanceAlgorithm or choose a different Space Fraction Method.");
1897 0 : return;
1898 : }
1899 :
1900 : // Calculate total of space fraction basis value across all spaces for this splitter or mixer
1901 : // including spaces which are not autosized here.
1902 0 : Real64 spacesTotal = 0.0;
1903 0 : switch (this->spaceSizingBasis) {
1904 0 : case DataZoneEquipment::SpaceEquipSizingBasis::DesignCoolingLoad:
1905 0 : for (auto &thisSpace : this->spaces) {
1906 0 : spacesTotal += state.dataSize->FinalSpaceSizing(thisSpace.spaceIndex).DesCoolLoad;
1907 0 : }
1908 0 : break;
1909 0 : case DataZoneEquipment::SpaceEquipSizingBasis::DesignHeatingLoad:
1910 0 : for (auto &thisSpace : this->spaces) {
1911 0 : spacesTotal += state.dataSize->FinalSpaceSizing(thisSpace.spaceIndex).DesHeatLoad;
1912 0 : }
1913 0 : break;
1914 0 : case DataZoneEquipment::SpaceEquipSizingBasis::FloorArea:
1915 0 : for (auto &thisSpace : this->spaces) {
1916 0 : spacesTotal += state.dataHeatBal->space(thisSpace.spaceIndex).FloorArea;
1917 0 : }
1918 0 : break;
1919 0 : case DataZoneEquipment::SpaceEquipSizingBasis::Volume:
1920 0 : for (auto &thisSpace : this->spaces) {
1921 0 : spacesTotal += state.dataHeatBal->space(thisSpace.spaceIndex).Volume;
1922 0 : }
1923 0 : break;
1924 0 : case DataZoneEquipment::SpaceEquipSizingBasis::PerimeterLength:
1925 0 : for (auto &thisSpace : this->spaces) {
1926 0 : spacesTotal += state.dataHeatBal->space(thisSpace.spaceIndex).extPerimeter;
1927 0 : }
1928 0 : break;
1929 0 : default:
1930 : // If method is not set, then return
1931 0 : return;
1932 : break;
1933 : }
1934 :
1935 0 : if (spacesTotal < 0.00001) {
1936 0 : ShowSevereError(state,
1937 0 : format("ZoneEquipmentSplitterMixer::size: Total {} is zero for {}={}. Unable to autosize Space Fractions.",
1938 0 : DataZoneEquipment::spaceEquipSizingBasisNamesUC[(int)this->spaceSizingBasis],
1939 0 : BranchNodeConnections::ConnectionObjectTypeNames[(int)this->spaceEquipType],
1940 0 : this->Name));
1941 0 : Real64 spaceFrac = 1.0 / (int)this->spaces.size();
1942 0 : ShowContinueError(state, format("Setting space fractions to 1/number of spaces = {}.", spaceFrac));
1943 0 : for (auto &thisSpace : this->spaces) {
1944 0 : thisSpace.fraction = spaceFrac;
1945 0 : }
1946 : } else {
1947 : // Calculate space fractions
1948 0 : for (auto &thisSpace : this->spaces) {
1949 0 : if (thisSpace.fraction == DataSizing::AutoSize) {
1950 0 : switch (this->spaceSizingBasis) {
1951 0 : case DataZoneEquipment::SpaceEquipSizingBasis::DesignCoolingLoad:
1952 0 : thisSpace.fraction = state.dataSize->FinalSpaceSizing(thisSpace.spaceIndex).DesCoolLoad / spacesTotal;
1953 0 : break;
1954 0 : case DataZoneEquipment::SpaceEquipSizingBasis::DesignHeatingLoad:
1955 0 : thisSpace.fraction = state.dataSize->FinalSpaceSizing(thisSpace.spaceIndex).DesHeatLoad / spacesTotal;
1956 0 : break;
1957 0 : case DataZoneEquipment::SpaceEquipSizingBasis::FloorArea:
1958 0 : thisSpace.fraction = state.dataHeatBal->space(thisSpace.spaceIndex).FloorArea / spacesTotal;
1959 0 : break;
1960 0 : case DataZoneEquipment::SpaceEquipSizingBasis::Volume:
1961 0 : thisSpace.fraction = state.dataHeatBal->space(thisSpace.spaceIndex).Volume / spacesTotal;
1962 0 : break;
1963 0 : case DataZoneEquipment::SpaceEquipSizingBasis::PerimeterLength:
1964 0 : thisSpace.fraction = state.dataHeatBal->space(thisSpace.spaceIndex).extPerimeter / spacesTotal;
1965 0 : break;
1966 0 : default:
1967 0 : break;
1968 : }
1969 : }
1970 0 : }
1971 : }
1972 : // Report sizing results
1973 0 : int spaceCounter = 0;
1974 0 : for (auto &thisSpace : this->spaces) {
1975 0 : ++spaceCounter;
1976 0 : BaseSizer::reportSizerOutput(state,
1977 0 : BranchNodeConnections::ConnectionObjectTypeNames[(int)this->spaceEquipType],
1978 : this->Name,
1979 0 : format("Space {} Fraction", spaceCounter),
1980 : thisSpace.fraction);
1981 0 : }
1982 : }
1983 :
1984 2 : void ZoneMixer::setOutletConditions(EnergyPlusData &state)
1985 : {
1986 2 : if (this->outletNodeNum == 0) {
1987 0 : return;
1988 : }
1989 :
1990 2 : Real64 sumEnthalpy = 0.0;
1991 2 : Real64 sumHumRat = 0.0;
1992 2 : Real64 sumCO2 = 0.0;
1993 2 : Real64 sumGenContam = 0.0;
1994 2 : Real64 sumPressure = 0.0;
1995 2 : Real64 sumFractions = 0.0;
1996 2 : auto &outletNode = state.dataLoopNodes->Node(this->outletNodeNum);
1997 8 : for (auto &mixerSpace : this->spaces) {
1998 6 : auto const &spaceOutletNode = state.dataLoopNodes->Node(mixerSpace.spaceNodeNum);
1999 6 : sumEnthalpy += spaceOutletNode.Enthalpy * mixerSpace.fraction;
2000 6 : sumHumRat += spaceOutletNode.HumRat * mixerSpace.fraction;
2001 6 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2002 6 : sumCO2 += spaceOutletNode.CO2 * mixerSpace.fraction;
2003 : }
2004 6 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2005 6 : sumGenContam += spaceOutletNode.GenContam * mixerSpace.fraction;
2006 : }
2007 6 : sumPressure += spaceOutletNode.Press * mixerSpace.fraction;
2008 6 : sumFractions += mixerSpace.fraction;
2009 2 : }
2010 :
2011 : // For SpaceHVAC:ZoneReturnMixer, the fractions are dynamic and could be zero if there is no flow
2012 2 : if (sumFractions > 0) {
2013 2 : outletNode.Enthalpy = sumEnthalpy / sumFractions;
2014 2 : outletNode.HumRat = sumHumRat / sumFractions;
2015 2 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2016 2 : outletNode.CO2 = sumCO2 / sumFractions;
2017 : }
2018 2 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2019 2 : outletNode.GenContam = sumGenContam / sumFractions;
2020 : }
2021 2 : outletNode.Press = sumPressure / sumFractions;
2022 :
2023 : // Use Enthalpy and humidity ratio to get outlet temperature from psych chart
2024 2 : outletNode.Temp = Psychrometrics::PsyTdbFnHW(outletNode.Enthalpy, outletNode.HumRat);
2025 : }
2026 : }
2027 :
2028 1 : void ZoneReturnMixer::setInletConditions(EnergyPlusData &state)
2029 : {
2030 4 : for (auto &mixerSpace : this->spaces) {
2031 3 : auto &spaceOutletNode = state.dataLoopNodes->Node(mixerSpace.spaceNodeNum);
2032 3 : int spaceZoneNodeNum = state.dataZoneEquip->spaceEquipConfig(mixerSpace.spaceIndex).ZoneNode;
2033 3 : auto const &spaceNode = state.dataLoopNodes->Node(spaceZoneNodeNum);
2034 3 : spaceOutletNode.Temp = spaceNode.Temp;
2035 3 : spaceOutletNode.HumRat = spaceNode.HumRat;
2036 3 : spaceOutletNode.Enthalpy = spaceNode.Enthalpy;
2037 3 : spaceOutletNode.Press = spaceNode.Press;
2038 3 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2039 3 : spaceOutletNode.CO2 = spaceNode.CO2;
2040 : }
2041 3 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2042 3 : spaceOutletNode.GenContam = spaceNode.GenContam;
2043 : }
2044 1 : }
2045 1 : }
2046 1 : void ZoneEquipmentMixer::setInletFlows(EnergyPlusData &state)
2047 : {
2048 1 : if (this->outletNodeNum == 0) {
2049 0 : return;
2050 : }
2051 :
2052 1 : auto &equipInletNode = state.dataLoopNodes->Node(this->outletNodeNum);
2053 4 : for (auto &mixerSpace : this->spaces) {
2054 3 : auto &spaceOutletNode = state.dataLoopNodes->Node(mixerSpace.spaceNodeNum);
2055 3 : spaceOutletNode.MassFlowRate = equipInletNode.MassFlowRate * mixerSpace.fraction;
2056 3 : spaceOutletNode.MassFlowRateMaxAvail = equipInletNode.MassFlowRateMaxAvail * mixerSpace.fraction;
2057 3 : spaceOutletNode.MassFlowRateMinAvail = equipInletNode.MassFlowRateMinAvail * mixerSpace.fraction;
2058 1 : }
2059 : }
2060 :
2061 2 : void ZoneReturnMixer::setInletFlows(EnergyPlusData &state)
2062 : {
2063 2 : if (this->outletNodeNum == 0) {
2064 0 : return;
2065 : }
2066 2 : auto &outletNode = state.dataLoopNodes->Node(this->outletNodeNum);
2067 :
2068 2 : Real64 sumMixerInletMassFlow = 0;
2069 8 : for (auto const &mixerSpace : this->spaces) {
2070 : // calc return flows for spaces feeding this mixer
2071 6 : auto &spaceEquipConfig = state.dataZoneEquip->spaceEquipConfig(mixerSpace.spaceIndex);
2072 6 : Real64 outletMassFlowRate = outletNode.MassFlowRate; // calcReturnFlows might adjust this parameter value, so make a copy here
2073 6 : Real64 spaceReturnFlow = 0.0;
2074 6 : spaceEquipConfig.calcReturnFlows(state, outletMassFlowRate, spaceReturnFlow);
2075 6 : sumMixerInletMassFlow += spaceReturnFlow;
2076 2 : }
2077 :
2078 8 : for (auto &mixerSpace : this->spaces) {
2079 6 : auto &spaceOutletNode = state.dataLoopNodes->Node(mixerSpace.spaceNodeNum);
2080 : // For return mixer, fraction is calculated every time step, not a user input
2081 6 : if (sumMixerInletMassFlow > 0.0) {
2082 6 : mixerSpace.fraction = spaceOutletNode.MassFlowRate / sumMixerInletMassFlow;
2083 : } else {
2084 0 : mixerSpace.fraction = 0.0;
2085 : }
2086 6 : spaceOutletNode.MassFlowRate = outletNode.MassFlowRate * mixerSpace.fraction;
2087 6 : spaceOutletNode.MassFlowRateMaxAvail = outletNode.MassFlowRateMaxAvail * mixerSpace.fraction;
2088 6 : spaceOutletNode.MassFlowRateMinAvail = outletNode.MassFlowRateMinAvail * mixerSpace.fraction;
2089 2 : }
2090 : }
2091 :
2092 3 : void ZoneEquipmentSplitter::adjustLoads(EnergyPlusData &state, int zoneNum, int equipTypeNum)
2093 : {
2094 3 : auto &thisZoneEnergyDemand = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum);
2095 3 : auto &thisZoneMoistureDemand = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(zoneNum);
2096 :
2097 3 : auto &zoneTstatSetpt = state.dataHeatBalFanSys->zoneTstatSetpts(zoneNum);
2098 :
2099 3 : Real64 sensibleRatio = 1.0;
2100 3 : Real64 latentRatio = 1.0;
2101 3 : switch (this->tstatControl) {
2102 1 : case DataZoneEquipment::ZoneEquipTstatControl::Ideal: {
2103 1 : return;
2104 : } break; // Do nothing
2105 :
2106 1 : case DataZoneEquipment::ZoneEquipTstatControl::SingleSpace: {
2107 1 : Real64 controlSpaceFrac = this->spaces[this->controlSpaceNumber].fraction;
2108 1 : if (controlSpaceFrac > 0.0) {
2109 1 : if (thisZoneEnergyDemand.RemainingOutputRequired != 0.0) {
2110 1 : sensibleRatio = (state.dataZoneEnergyDemand->spaceSysEnergyDemand(this->controlSpaceIndex).RemainingOutputRequired /
2111 1 : thisZoneEnergyDemand.RemainingOutputRequired) /
2112 : controlSpaceFrac;
2113 : }
2114 1 : if (thisZoneMoistureDemand.RemainingOutputRequired != 0.0) {
2115 0 : latentRatio = (state.dataZoneEnergyDemand->spaceSysMoistureDemand(this->controlSpaceIndex).RemainingOutputRequired /
2116 0 : thisZoneMoistureDemand.RemainingOutputRequired) /
2117 : controlSpaceFrac;
2118 : }
2119 : }
2120 1 : } break;
2121 :
2122 1 : case DataZoneEquipment::ZoneEquipTstatControl::Maximum: {
2123 1 : int maxSpaceIndex = 0;
2124 1 : Real64 maxDeltaTemp = 0.0; // Only positive deltaTemps are relevant
2125 1 : Real64 maxSpaceFrac = 1.0;
2126 4 : for (auto &splitterSpace : this->spaces) {
2127 : Real64 spaceTemp =
2128 3 : state.dataZoneTempPredictorCorrector->spaceHeatBalance(splitterSpace.spaceIndex).T1; // Based on calcPredictedSystemLoad usage
2129 3 : Real64 spaceDeltaTemp = max((zoneTstatSetpt.setptLo - spaceTemp), (spaceTemp - zoneTstatSetpt.setptHi));
2130 3 : if (spaceDeltaTemp > maxDeltaTemp) {
2131 1 : maxSpaceIndex = splitterSpace.spaceIndex;
2132 1 : maxSpaceFrac = splitterSpace.fraction;
2133 1 : maxDeltaTemp = spaceDeltaTemp;
2134 : }
2135 1 : }
2136 1 : if ((maxSpaceIndex > 0) && (maxSpaceFrac > 0.0)) {
2137 1 : if (thisZoneEnergyDemand.RemainingOutputRequired != 0.0) {
2138 1 : sensibleRatio = (state.dataZoneEnergyDemand->spaceSysEnergyDemand(maxSpaceIndex).RemainingOutputRequired /
2139 1 : thisZoneEnergyDemand.RemainingOutputRequired) /
2140 : maxSpaceFrac;
2141 : }
2142 1 : if (thisZoneMoistureDemand.RemainingOutputRequired != 0.0) {
2143 0 : latentRatio = (state.dataZoneEnergyDemand->spaceSysMoistureDemand(maxSpaceIndex).RemainingOutputRequired /
2144 0 : thisZoneMoistureDemand.RemainingOutputRequired) /
2145 : maxSpaceFrac;
2146 : }
2147 : }
2148 1 : } break;
2149 0 : default:
2150 0 : break;
2151 : }
2152 : // Save unadjusted zone loads to restore later
2153 2 : this->saveZoneSysSensibleDemand = thisZoneEnergyDemand;
2154 2 : this->saveZoneSysMoistureDemand = thisZoneMoistureDemand;
2155 : // Apply zone load adjustment
2156 4 : ZoneEquipmentManager::adjustSystemOutputRequired(sensibleRatio,
2157 : latentRatio,
2158 2 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum),
2159 2 : state.dataZoneEnergyDemand->ZoneSysMoistureDemand(zoneNum),
2160 : equipTypeNum);
2161 : }
2162 :
2163 1 : void ZoneEquipmentSplitter::distributeOutput(EnergyPlusData &state,
2164 : int const zoneNum,
2165 : Real64 const sysOutputProvided,
2166 : Real64 const latOutputProvided,
2167 : Real64 const nonAirSysOutput,
2168 : int const equipTypeNum)
2169 : {
2170 4 : for (auto &splitterSpace : this->spaces) {
2171 3 : if (this->tstatControl != DataZoneEquipment::ZoneEquipTstatControl::Ideal) {
2172 : // Restore zone loads to unadjusted values (for all ZoneEquipTstatControl types except Ideal)
2173 3 : state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum) = this->saveZoneSysSensibleDemand;
2174 3 : state.dataZoneEnergyDemand->ZoneSysMoistureDemand(zoneNum) = this->saveZoneSysMoistureDemand;
2175 : }
2176 :
2177 3 : Real64 spaceFraction = splitterSpace.fraction;
2178 3 : if (this->tstatControl == DataZoneEquipment::ZoneEquipTstatControl::Ideal) {
2179 : // Proportion output by sensible space load / zone load (varies every timestep, overrides outputFraction)
2180 0 : auto const &thisZoneSysEnergyDemand = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(zoneNum);
2181 0 : if (thisZoneSysEnergyDemand.RemainingOutputRequired != 0.0) {
2182 0 : spaceFraction = state.dataZoneEnergyDemand->spaceSysEnergyDemand(splitterSpace.spaceIndex).RemainingOutputRequired /
2183 0 : thisZoneSysEnergyDemand.RemainingOutputRequired;
2184 : }
2185 : }
2186 :
2187 3 : Real64 spaceSysOutputProvided = sysOutputProvided * spaceFraction;
2188 3 : Real64 spaceLatOutputProvided = latOutputProvided * spaceFraction;
2189 3 : state.dataZoneTempPredictorCorrector->spaceHeatBalance(splitterSpace.spaceIndex).NonAirSystemResponse += nonAirSysOutput * spaceFraction;
2190 3 : if (this->zoneEquipOutletNodeNum > 0 && splitterSpace.spaceNodeNum > 0) {
2191 3 : auto const &equipOutletNode = state.dataLoopNodes->Node(this->zoneEquipOutletNodeNum);
2192 3 : auto &spaceInletNode = state.dataLoopNodes->Node(splitterSpace.spaceNodeNum);
2193 3 : spaceInletNode.MassFlowRate = equipOutletNode.MassFlowRate * spaceFraction;
2194 3 : spaceInletNode.MassFlowRateMaxAvail = equipOutletNode.MassFlowRateMaxAvail * spaceFraction;
2195 3 : spaceInletNode.MassFlowRateMinAvail = equipOutletNode.MassFlowRateMinAvail * spaceFraction;
2196 3 : spaceInletNode.Temp = equipOutletNode.Temp;
2197 3 : spaceInletNode.HumRat = equipOutletNode.HumRat;
2198 3 : spaceInletNode.CO2 = equipOutletNode.CO2;
2199 : }
2200 3 : ZoneEquipmentManager::updateSystemOutputRequired(state,
2201 : zoneNum,
2202 : spaceSysOutputProvided,
2203 : spaceLatOutputProvided,
2204 3 : state.dataZoneEnergyDemand->spaceSysEnergyDemand(splitterSpace.spaceIndex),
2205 3 : state.dataZoneEnergyDemand->spaceSysMoistureDemand(splitterSpace.spaceIndex),
2206 : equipTypeNum);
2207 1 : }
2208 1 : }
2209 :
2210 476 : void EquipConfiguration::beginEnvirnInit(EnergyPlusData &state)
2211 : {
2212 476 : auto &zoneNode = state.dataLoopNodes->Node(this->ZoneNode);
2213 476 : zoneNode.Temp = 20.0;
2214 476 : zoneNode.MassFlowRate = 0.0;
2215 476 : zoneNode.Quality = 1.0;
2216 476 : zoneNode.Press = state.dataEnvrn->OutBaroPress;
2217 476 : zoneNode.HumRat = state.dataEnvrn->OutHumRat;
2218 476 : zoneNode.Enthalpy = Psychrometrics::PsyHFnTdbW(zoneNode.Temp, zoneNode.HumRat);
2219 476 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2220 0 : zoneNode.CO2 = state.dataContaminantBalance->OutdoorCO2;
2221 : }
2222 476 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2223 0 : zoneNode.GenContam = state.dataContaminantBalance->OutdoorGC;
2224 : }
2225 :
2226 979 : for (int const nodeNum : this->InletNode) {
2227 503 : auto &inNode = state.dataLoopNodes->Node(nodeNum);
2228 503 : inNode.Temp = 20.0;
2229 503 : inNode.MassFlowRate = 0.0;
2230 503 : inNode.Quality = 1.0;
2231 503 : inNode.Press = state.dataEnvrn->OutBaroPress;
2232 503 : inNode.HumRat = state.dataEnvrn->OutHumRat;
2233 503 : inNode.Enthalpy = Psychrometrics::PsyHFnTdbW(inNode.Temp, inNode.HumRat);
2234 503 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2235 0 : inNode.CO2 = state.dataContaminantBalance->OutdoorCO2;
2236 : }
2237 503 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2238 0 : inNode.GenContam = state.dataContaminantBalance->OutdoorGC;
2239 : }
2240 : }
2241 :
2242 756 : for (int const nodeNum : this->ExhaustNode) {
2243 280 : auto &exhNode = state.dataLoopNodes->Node(nodeNum);
2244 280 : exhNode.Temp = 20.0;
2245 280 : exhNode.MassFlowRate = 0.0;
2246 280 : exhNode.Quality = 1.0;
2247 280 : exhNode.Press = state.dataEnvrn->OutBaroPress;
2248 280 : exhNode.HumRat = state.dataEnvrn->OutHumRat;
2249 280 : exhNode.Enthalpy = Psychrometrics::PsyHFnTdbW(exhNode.Temp, exhNode.HumRat);
2250 280 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2251 0 : exhNode.CO2 = state.dataContaminantBalance->OutdoorCO2;
2252 : }
2253 280 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2254 0 : exhNode.GenContam = state.dataContaminantBalance->OutdoorGC;
2255 : }
2256 : }
2257 :
2258 : // BG CR 7122 following resets return air node.
2259 476 : int NumRetNodes = this->NumReturnNodes;
2260 476 : if (NumRetNodes > 0) {
2261 904 : for (int const nodeNum : this->ReturnNode) {
2262 452 : auto &returnNode = state.dataLoopNodes->Node(nodeNum);
2263 452 : returnNode.Temp = 20.0;
2264 452 : returnNode.MassFlowRate = 0.0;
2265 452 : returnNode.Quality = 1.0;
2266 452 : returnNode.Press = state.dataEnvrn->OutBaroPress;
2267 452 : returnNode.HumRat = state.dataEnvrn->OutHumRat;
2268 452 : returnNode.Enthalpy = Psychrometrics::PsyHFnTdbW(returnNode.Temp, returnNode.HumRat);
2269 452 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2270 0 : returnNode.CO2 = state.dataContaminantBalance->OutdoorCO2;
2271 : }
2272 452 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2273 0 : returnNode.GenContam = state.dataContaminantBalance->OutdoorGC;
2274 : }
2275 : }
2276 : }
2277 476 : }
2278 :
2279 276964 : void EquipConfiguration::hvacTimeStepInit(EnergyPlusData &state, bool FirstHVACIteration)
2280 : {
2281 276964 : auto &zoneNode = state.dataLoopNodes->Node(this->ZoneNode);
2282 276964 : this->ExcessZoneExh = 0.0;
2283 :
2284 276964 : if (FirstHVACIteration) {
2285 317407 : for (int const nodeNum : this->ExhaustNode) {
2286 117532 : auto &exhNode = state.dataLoopNodes->Node(nodeNum);
2287 117532 : exhNode.Temp = zoneNode.Temp;
2288 117532 : exhNode.HumRat = zoneNode.HumRat;
2289 117532 : exhNode.Enthalpy = zoneNode.Enthalpy;
2290 117532 : exhNode.Press = zoneNode.Press;
2291 117532 : exhNode.Quality = zoneNode.Quality;
2292 117532 : exhNode.MassFlowRate = 0.0;
2293 117532 : exhNode.MassFlowRateMaxAvail = 0.0;
2294 117532 : exhNode.MassFlowRateMinAvail = 0.0;
2295 117532 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2296 0 : exhNode.CO2 = zoneNode.CO2;
2297 : }
2298 117532 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2299 0 : exhNode.GenContam = zoneNode.GenContam;
2300 : }
2301 : }
2302 : }
2303 276964 : }
2304 :
2305 277112 : void EquipConfiguration::calcReturnFlows(EnergyPlusData &state,
2306 : Real64 &ExpTotalReturnMassFlow, // Expected total return air mass flow rate
2307 : Real64 &FinalTotalReturnMassFlow // Final total return air mass flow rate
2308 : )
2309 : {
2310 277112 : int numRetNodes = this->NumReturnNodes;
2311 277112 : Real64 totReturnFlow = 0.0; // Total flow to all return nodes in the zone (kg/s)
2312 277112 : Real64 totVarReturnFlow =
2313 : 0.0; // Total variable return flow, for return nodes connected to an airloop with an OA system or not with specified flow (kg/s)
2314 277112 : Real64 returnSchedFrac = this->returnFlowFracSched->getCurrentVal();
2315 277112 : this->FixedReturnFlow = false;
2316 277112 : FinalTotalReturnMassFlow = 0.0;
2317 277112 : this->TotAvailAirLoopOA = 0.0;
2318 :
2319 : // Set initial flow rate for each return node
2320 545753 : for (int returnNum = 1; returnNum <= numRetNodes; ++returnNum) {
2321 268641 : int retNode = this->ReturnNode(returnNum);
2322 :
2323 268641 : if (retNode > 0) {
2324 268641 : Real64 returnNodeMassFlow = 0.0;
2325 268641 : auto &retNodeData(state.dataLoopNodes->Node(retNode));
2326 :
2327 268641 : int inletNum = this->ReturnNodeInletNum(returnNum); // which inlet node matches this return node (same airloop)
2328 268641 : int ADUNum = 0;
2329 268641 : if (inletNum > 0) {
2330 120305 : ADUNum = this->InletNodeADUNum(inletNum);
2331 : }
2332 268641 : int airLoop = this->ReturnNodeAirLoopNum(returnNum);
2333 268641 : Real64 airLoopReturnFrac = 1.0;
2334 268641 : if (airLoop > 0) {
2335 : // Establish corresponding airloop inlet(s) mass flow rate and set return node max/min/maxavail
2336 120400 : Real64 inletMassFlow = 0.0;
2337 120400 : int maxMinNodeNum = 0;
2338 120400 : auto const &thisAirLoopFlow(state.dataAirLoop->AirLoopFlow(airLoop));
2339 120400 : if (ADUNum > 0) {
2340 : // Zone return node could carry supply flow to zone without leaks plus any induced flow from plenum (but don't include other
2341 : // secondary flows from exhaust nodes)
2342 113333 : inletMassFlow = state.dataDefineEquipment->AirDistUnit(ADUNum).MassFlowRateZSup +
2343 113333 : state.dataDefineEquipment->AirDistUnit(ADUNum).MassFlowRatePlenInd;
2344 113333 : maxMinNodeNum = state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum;
2345 7067 : } else if (inletNum > 0) {
2346 : // If not connected to an ADU, then use the inlet node flow
2347 6969 : inletMassFlow = state.dataLoopNodes->Node(this->InletNode(inletNum)).MassFlowRate;
2348 6969 : maxMinNodeNum = this->InletNode(inletNum);
2349 : }
2350 120400 : if (maxMinNodeNum > 0) {
2351 120302 : auto const &maxMinNodeData(state.dataLoopNodes->Node(maxMinNodeNum));
2352 120302 : retNodeData.MassFlowRateMax = maxMinNodeData.MassFlowRateMax;
2353 120302 : retNodeData.MassFlowRateMin = maxMinNodeData.MassFlowRateMin;
2354 120302 : retNodeData.MassFlowRateMaxAvail = maxMinNodeData.MassFlowRateMaxAvail;
2355 : } else {
2356 98 : auto const &zoneNodeData(state.dataLoopNodes->Node(this->ZoneNode));
2357 98 : retNodeData.MassFlowRateMax = zoneNodeData.MassFlowRateMax;
2358 98 : retNodeData.MassFlowRateMin = zoneNodeData.MassFlowRateMin;
2359 98 : retNodeData.MassFlowRateMaxAvail = zoneNodeData.MassFlowRateMaxAvail;
2360 : }
2361 :
2362 120400 : airLoopReturnFrac = thisAirLoopFlow.DesReturnFrac;
2363 120400 : if (state.dataAirSystemsData->PrimaryAirSystems(airLoop).OASysExists && (thisAirLoopFlow.MaxOutAir > 0.0)) {
2364 : // Set return flow as fraction of matching inlet node flow if there is an OA system and available OA flow > 0.0
2365 105573 : returnNodeMassFlow = airLoopReturnFrac * inletMassFlow;
2366 105573 : this->TotAvailAirLoopOA += thisAirLoopFlow.MaxOutAir;
2367 : } else {
2368 : // Set return flow to matching inlet node flow
2369 14827 : returnNodeMassFlow = inletMassFlow;
2370 14827 : this->FixedReturnFlow(returnNum) = true;
2371 : }
2372 : } else {
2373 148241 : returnNodeMassFlow = 0.0;
2374 : }
2375 :
2376 : // Return node 1 is special
2377 268641 : if (returnNum == 1) {
2378 : // Make no return air flow adjustments during sizing
2379 268631 : if ((state.dataGlobal->DoingSizing) && numRetNodes == 1) {
2380 91164 : returnNodeMassFlow = ExpTotalReturnMassFlow;
2381 91164 : if (airLoop > 0) {
2382 0 : if (!state.dataAirSystemsData->PrimaryAirSystems(airLoop).OASysExists ||
2383 0 : (state.dataAirLoop->AirLoopFlow(airLoop).MaxOutAir == 0.0)) {
2384 0 : ExpTotalReturnMassFlow = max(0.0, ExpTotalReturnMassFlow - this->ZoneExhBalanced + this->ZoneExh);
2385 0 : returnNodeMassFlow = ExpTotalReturnMassFlow;
2386 : }
2387 : }
2388 177467 : } else if (!state.dataGlobal->DoingSizing) {
2389 177467 : if (this->NumReturnFlowBasisNodes > 0) {
2390 : // Set base return air flow rate for node 1 using basis node flow rates
2391 2 : Real64 basisNodesMassFlow = 0.0;
2392 8 : for (int nodeNum = 1; nodeNum <= this->NumReturnFlowBasisNodes; ++nodeNum) {
2393 6 : basisNodesMassFlow += state.dataLoopNodes->Node(this->ReturnFlowBasisNode(nodeNum)).MassFlowRate;
2394 : }
2395 2 : returnNodeMassFlow = max(0.0, (basisNodesMassFlow * returnSchedFrac));
2396 2 : this->FixedReturnFlow(returnNum) = true;
2397 : } else {
2398 : // If only 1 return node, use the standard return mass flow
2399 177465 : if ((numRetNodes == 1) && !this->FixedReturnFlow(returnNum)) {
2400 162648 : returnNodeMassFlow = max(0.0, (ExpTotalReturnMassFlow * returnSchedFrac * airLoopReturnFrac));
2401 : }
2402 : }
2403 : }
2404 : }
2405 268641 : totReturnFlow += returnNodeMassFlow;
2406 268641 : retNodeData.MassFlowRate = returnNodeMassFlow;
2407 268641 : retNodeData.MassFlowRateMinAvail = 0.0;
2408 268641 : if (!this->FixedReturnFlow(returnNum)) {
2409 253814 : totVarReturnFlow += returnNodeMassFlow;
2410 : }
2411 : }
2412 : }
2413 :
2414 : // if zone mass balance true, set to expected return flow
2415 277112 : if (state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment != DataHeatBalance::AdjustmentType::NoAdjustReturnAndMixing) {
2416 : // applies zone return flow schedule multiplier
2417 114 : ExpTotalReturnMassFlow = returnSchedFrac * ExpTotalReturnMassFlow;
2418 : // set air flow rate for each return node
2419 114 : Real64 zoneTotReturnFlow = 0.0;
2420 114 : Real64 returnNodeMassFlow = 0.0;
2421 228 : for (int returnNum = 1; returnNum <= numRetNodes; ++returnNum) {
2422 114 : int retNode = this->ReturnNode(returnNum);
2423 114 : if (retNode > 0) {
2424 114 : if (numRetNodes == 1) {
2425 114 : returnNodeMassFlow = ExpTotalReturnMassFlow;
2426 : } else { // multiple return nodes
2427 0 : if (ExpTotalReturnMassFlow > 0.0) {
2428 0 : Real64 returnAdjFactor = state.dataLoopNodes->Node(retNode).MassFlowRate / ExpTotalReturnMassFlow;
2429 0 : returnNodeMassFlow = returnAdjFactor * ExpTotalReturnMassFlow;
2430 : } else {
2431 0 : returnNodeMassFlow = 0.0;
2432 : }
2433 : }
2434 : }
2435 114 : zoneTotReturnFlow += returnNodeMassFlow;
2436 : }
2437 : // Adjust return node flows if zone total return flow is > 0
2438 114 : if (zoneTotReturnFlow > 0.0) {
2439 88 : for (int returnNum = 1; returnNum <= numRetNodes; ++returnNum) {
2440 44 : int retNode = this->ReturnNode(returnNum);
2441 44 : if (retNode > 0) {
2442 44 : if (numRetNodes == 1) {
2443 : // set it to expected return flows
2444 44 : state.dataLoopNodes->Node(retNode).MassFlowRate = ExpTotalReturnMassFlow;
2445 44 : FinalTotalReturnMassFlow = ExpTotalReturnMassFlow;
2446 : } else { // multiple return nodes, adjust nodes flow
2447 0 : Real64 newReturnFlow = 0.0;
2448 0 : Real64 returnAdjFactor = ExpTotalReturnMassFlow / zoneTotReturnFlow;
2449 0 : Real64 curReturnFlow = state.dataLoopNodes->Node(retNode).MassFlowRate;
2450 0 : newReturnFlow = curReturnFlow * returnAdjFactor;
2451 0 : state.dataLoopNodes->Node(retNode).MassFlowRate = newReturnFlow;
2452 0 : FinalTotalReturnMassFlow += newReturnFlow;
2453 : }
2454 : }
2455 : }
2456 : } else {
2457 70 : FinalTotalReturnMassFlow = ExpTotalReturnMassFlow;
2458 : }
2459 : } else {
2460 : // Adjust return flows if greater than expected (i.e. there is exhaust or mixing flow reducing the total available for return)
2461 276998 : if ((totReturnFlow > ExpTotalReturnMassFlow) && (totVarReturnFlow > 0.0)) {
2462 0 : Real64 newReturnFlow = 0.0;
2463 0 : Real64 returnAdjFactor = (1 - ((totReturnFlow - ExpTotalReturnMassFlow) / totVarReturnFlow)); // Return flow adjustment factor
2464 0 : for (int returnNum = 1; returnNum <= numRetNodes; ++returnNum) {
2465 0 : int retNode = this->ReturnNode(returnNum);
2466 0 : Real64 curReturnFlow = state.dataLoopNodes->Node(retNode).MassFlowRate;
2467 0 : if (retNode > 0) {
2468 0 : if (!this->FixedReturnFlow(returnNum)) {
2469 0 : newReturnFlow = curReturnFlow * returnAdjFactor;
2470 0 : FinalTotalReturnMassFlow += newReturnFlow;
2471 0 : state.dataLoopNodes->Node(retNode).MassFlowRate = newReturnFlow;
2472 : } else {
2473 0 : FinalTotalReturnMassFlow += curReturnFlow;
2474 : }
2475 : }
2476 : }
2477 0 : } else {
2478 276998 : FinalTotalReturnMassFlow = totReturnFlow;
2479 : }
2480 : }
2481 277112 : }
2482 :
2483 : } // namespace EnergyPlus::DataZoneEquipment
|