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