Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <string>
50 :
51 : // EnergyPlus Headers
52 : #include <EnergyPlus/AirLoopHVACDOAS.hh>
53 : #include <EnergyPlus/BranchNodeConnections.hh>
54 : #include <EnergyPlus/Data/EnergyPlusData.hh>
55 : #include <EnergyPlus/DataAirLoop.hh>
56 : #include <EnergyPlus/DataAirSystems.hh>
57 : #include <EnergyPlus/DataEnvironment.hh>
58 : #include <EnergyPlus/DataLoopNode.hh>
59 : #include <EnergyPlus/DataSizing.hh>
60 : #include <EnergyPlus/DesiccantDehumidifiers.hh>
61 : #include <EnergyPlus/EvaporativeCoolers.hh>
62 : #include <EnergyPlus/Fans.hh>
63 : #include <EnergyPlus/FluidProperties.hh>
64 : #include <EnergyPlus/HVACDXHeatPumpSystem.hh>
65 : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
66 : #include <EnergyPlus/HVACVariableRefrigerantFlow.hh>
67 : #include <EnergyPlus/HeatRecovery.hh>
68 : #include <EnergyPlus/HeatingCoils.hh>
69 : #include <EnergyPlus/Humidifiers.hh>
70 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
71 : #include <EnergyPlus/MixedAir.hh>
72 : #include <EnergyPlus/NodeInputManager.hh>
73 : #include <EnergyPlus/OutAirNodeManager.hh>
74 : #include <EnergyPlus/PhotovoltaicThermalCollectors.hh>
75 : #include <EnergyPlus/PlantUtilities.hh>
76 : #include <EnergyPlus/Psychrometrics.hh>
77 : #include <EnergyPlus/ScheduleManager.hh>
78 : #include <EnergyPlus/SimAirServingZones.hh>
79 : #include <EnergyPlus/SteamCoils.hh>
80 : #include <EnergyPlus/TranspiredCollector.hh>
81 : #include <EnergyPlus/UnitarySystem.hh>
82 : #include <EnergyPlus/UtilityRoutines.hh>
83 : #include <EnergyPlus/WaterCoils.hh>
84 : #include <EnergyPlus/WeatherManager.hh>
85 :
86 : namespace EnergyPlus {
87 :
88 : namespace AirLoopHVACDOAS {
89 :
90 : // the equipment list object has its own subset of E+ components that are valid, this covers that list
91 : enum class ValidEquipListType
92 : {
93 : Invalid = -1,
94 : OutdoorAirMixer,
95 : FanConstantVolume,
96 : FanVariableVolume,
97 : FanSystemModel,
98 : FanComponentModel,
99 : CoilCoolingWater,
100 : CoilHeatingWater,
101 : CoilHeatingSteam,
102 : CoilCoolingWaterDetailedGeometry,
103 : CoilHeatingElectric,
104 : CoilHeatingFuel,
105 : CoilSystemCoolingWaterHeatExchangerAssisted,
106 : CoilSystemCoolingDX,
107 : CoilSystemHeatingDX,
108 : AirLoopHVACUnitarySystem,
109 : CoilUserDefined,
110 : HeatExchangerAirToAirFlatPlate,
111 : HeatExchangerAirToAirSensibleAndLatent,
112 : HeatExchangerDesiccantBalancedFlow,
113 : DehumidifierDesiccantNoFans,
114 : DehumidifierDesiccantSystem,
115 : HumidifierSteamElectric,
116 : HumidifierSteamGas,
117 : SolarCollectorUnglazedTranspired,
118 : SolarCollectorFlatPlatePhotovoltaicThermal,
119 : EvaporativeCoolerDirectCeldekPad,
120 : EvaporativeCoolerIndirectCeldekPad,
121 : EvaporativeCoolerIndirectWetCoil,
122 : EvaporativeCoolerIndirectResearchSpecial,
123 : EvaporativeCoolerDirectResearchSpecial,
124 : ZoneHVACTerminalUnitVariableRefrigerantFlow,
125 : Num
126 : };
127 : constexpr std::array<std::string_view, static_cast<int>(ValidEquipListType::Num)> validEquipNamesUC = {
128 : "OUTDOORAIR:MIXER",
129 : "FAN:CONSTANTVOLUME",
130 : "FAN:VARIABLEVOLUME",
131 : "FAN:SYSTEMMODEL",
132 : "FAN:COMPONENTMODEL",
133 : "COIL:COOLING:WATER",
134 : "COIL:HEATING:WATER",
135 : "COIL:HEATING:STEAM",
136 : "COIL:COOLING:WATER:DETAILEDGEOMETRY",
137 : "COIL:HEATING:ELECTRIC",
138 : "COIL:HEATING:FUEL",
139 : "COILSYSTEM:COOLING:WATER:HEATEXCHANGERASSISTED",
140 : "COILSYSTEM:COOLING:DX",
141 : "COILSYSTEM:HEATING:DX",
142 : "AIRLOOPHVAC:UNITARYSYSTEM",
143 : "COIL:USERDEFINED",
144 : "HEATEXCHANGER:AIRTOAIR:FLATPLATE",
145 : "HEATEXCHANGER:AIRTOAIR:SENSIBLEANDLATENT",
146 : "HEATEXCHANGER:DESICCANT:BALANCEDFLOW",
147 : "DEHUMIDIFIER:DESICCANT:NOFANS",
148 : "DEHUMIDIFIER:DESICCANT:SYSTEM",
149 : "HUMIDIFIER:STEAM:ELECTRIC",
150 : "HUMIDIFIER:STEAM:GAS",
151 : "SOLARCOLLECTOR:UNGLAZEDTRANSPIRED",
152 : "SOLARCOLLECTOR:FLATPLATE:PHOTOVOLTAICTHERMAL",
153 : "EVAPORATIVECOOLER:DIRECT:CELDEKPAD",
154 : "EVAPORATIVECOOLER:INDIRECT:CELDEKPAD",
155 : "EVAPORATIVECOOLER:INDIRECT:WETCOIL",
156 : "EVAPORATIVECOOLER:INDIRECT:RESEARCHSPECIAL",
157 : "EVAPORATIVECOOLER:DIRECT:RESEARCHSPECIAL",
158 : "ZONEHVAC:TERMINALUNIT:VARIABLEREFRIGERANTFLOW",
159 : };
160 :
161 10882 : void AirLoopDOAS::SimAirLoopHVACDOAS(EnergyPlusData &state, bool const FirstHVACIteration, int &CompIndex)
162 : {
163 :
164 : // Obtains and Allocates unitary system related parameters from input file
165 10882 : if (state.dataAirLoopHVACDOAS->GetInputOnceFlag) {
166 : // Get the AirLoopHVACDOAS input
167 0 : getAirLoopDOASInput(state);
168 0 : state.dataAirLoopHVACDOAS->GetInputOnceFlag = false;
169 : }
170 :
171 10882 : if (CompIndex == -1) {
172 0 : CompIndex = this->m_AirLoopDOASNum;
173 : }
174 :
175 10882 : if (this->SizingOnceFlag) {
176 1 : this->SizingAirLoopDOAS(state);
177 1 : this->SizingOnceFlag = false;
178 : }
179 :
180 10882 : this->initAirLoopDOAS(state, FirstHVACIteration);
181 :
182 10882 : if (this->SumMassFlowRate == 0.0 && !state.dataGlobal->BeginEnvrnFlag) {
183 5474 : state.dataLoopNodes->Node(this->m_CompPointerAirLoopMixer->OutletNodeNum).MassFlowRate = 0.0;
184 : }
185 :
186 10882 : this->CalcAirLoopDOAS(state, FirstHVACIteration);
187 10882 : }
188 :
189 1 : AirLoopMixer *AirLoopMixer::factory(EnergyPlusData &state, int object_num, std::string const &objectName)
190 : {
191 :
192 1 : if (state.dataAirLoopHVACDOAS->getAirLoopMixerInputOnceFlag) {
193 0 : AirLoopMixer::getAirLoopMixer(state);
194 0 : state.dataAirLoopHVACDOAS->getAirLoopMixerInputOnceFlag = false;
195 : }
196 :
197 1 : int MixerNum = -1;
198 1 : for (auto &dSpec : state.dataAirLoopHVACDOAS->airloopMixer) {
199 1 : ++MixerNum;
200 1 : if (Util::SameString(dSpec.name, objectName) && dSpec.m_AirLoopMixer_Num == object_num) {
201 1 : return &dSpec;
202 : }
203 2 : }
204 :
205 0 : ShowSevereError(state, format("AirLoopMixer factory: Error getting inputs for system named: {}", objectName));
206 0 : return nullptr;
207 : }
208 :
209 1 : void AirLoopMixer::getAirLoopMixer(EnergyPlusData &state)
210 : {
211 :
212 1 : std::string const cCurrentModuleObject = "AirLoopHVAC:Mixer";
213 :
214 1 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(cCurrentModuleObject);
215 1 : if (instances != state.dataInputProcessing->inputProcessor->epJSON.end()) {
216 1 : bool errorsFound(false);
217 1 : std::string cFieldName;
218 1 : int AirLoopMixerNum = 0;
219 1 : auto &instancesValue = instances.value();
220 2 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
221 :
222 1 : auto const &fields = instance.value();
223 1 : std::string const &thisObjectName = instance.key();
224 1 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(cCurrentModuleObject, thisObjectName);
225 1 : ++AirLoopMixerNum;
226 1 : AirLoopMixer thisMixer;
227 :
228 1 : thisMixer.name = Util::makeUPPER(thisObjectName);
229 1 : thisMixer.OutletNodeName = Util::makeUPPER(fields.at("outlet_node_name").get<std::string>());
230 1 : thisMixer.m_AirLoopMixer_Num = AirLoopMixerNum - 1;
231 1 : thisMixer.OutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
232 : thisMixer.OutletNodeName,
233 : errorsFound,
234 : DataLoopNode::ConnectionObjectType::AirLoopHVACMixer,
235 : thisObjectName,
236 : DataLoopNode::NodeFluidType::Air,
237 : DataLoopNode::ConnectionType::Outlet,
238 : NodeInputManager::CompFluidStream::Primary,
239 : DataLoopNode::ObjectIsParent);
240 :
241 1 : auto NodeNames = fields.find("nodes");
242 1 : if (NodeNames != fields.end()) {
243 1 : auto const &NodeArray = NodeNames.value();
244 1 : thisMixer.numOfInletNodes = NodeArray.size();
245 1 : int num = 0;
246 6 : for (auto const &NodeDOASName : NodeArray) {
247 5 : num += 1;
248 10 : std::string name = Util::makeUPPER(NodeDOASName.at("inlet_node_name").get<std::string>());
249 5 : int NodeNum = NodeInputManager::GetOnlySingleNode(state,
250 : name,
251 : errorsFound,
252 : DataLoopNode::ConnectionObjectType::AirLoopHVACMixer,
253 : thisObjectName,
254 : DataLoopNode::NodeFluidType::Air,
255 : DataLoopNode::ConnectionType::Inlet,
256 : NodeInputManager::CompFluidStream::Primary,
257 5 : DataLoopNode::ObjectIsParent);
258 5 : if (NodeNum > 0 && num <= thisMixer.numOfInletNodes) {
259 5 : thisMixer.InletNodeName.push_back(name);
260 5 : thisMixer.InletNodeNum.push_back(NodeNum);
261 : } else {
262 0 : cFieldName = "Inlet Node Name";
263 0 : ShowSevereError(state, format("{}, \"{}\" {} not found: {}", cCurrentModuleObject, thisMixer.name, name, cFieldName));
264 0 : errorsFound = true;
265 : }
266 6 : }
267 : }
268 :
269 1 : state.dataAirLoopHVACDOAS->airloopMixer.push_back(thisMixer);
270 2 : }
271 1 : if (errorsFound) {
272 0 : ShowFatalError(state, "getAirLoopMixer: Previous errors cause termination.");
273 : }
274 1 : }
275 1 : } // namespace AirLoopMixer
276 :
277 10882 : void AirLoopMixer::CalcAirLoopMixer(EnergyPlusData &state)
278 : {
279 10882 : Real64 outletTemp = 0.0;
280 10882 : Real64 outletHumRat = 0.0;
281 10882 : Real64 massSum = 0.0;
282 :
283 65292 : for (int i = 1; i <= this->numOfInletNodes; i++) {
284 54410 : int InletNum = this->InletNodeNum[i - 1];
285 54410 : massSum += state.dataLoopNodes->Node(InletNum).MassFlowRate;
286 54410 : outletTemp += state.dataLoopNodes->Node(InletNum).MassFlowRate * state.dataLoopNodes->Node(InletNum).Temp;
287 54410 : outletHumRat += state.dataLoopNodes->Node(InletNum).MassFlowRate * state.dataLoopNodes->Node(InletNum).HumRat;
288 : }
289 10882 : if (massSum > 0.0) {
290 5358 : state.dataLoopNodes->Node(this->OutletNodeNum).Temp = outletTemp / massSum;
291 5358 : state.dataLoopNodes->Node(this->OutletNodeNum).HumRat = outletHumRat / massSum;
292 5358 : state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRate = massSum;
293 5358 : state.dataLoopNodes->Node(this->OutletNodeNum).Enthalpy = Psychrometrics::PsyHFnTdbW(outletTemp / massSum, outletHumRat / massSum);
294 5358 : this->OutletTemp = state.dataLoopNodes->Node(this->OutletNodeNum).Temp;
295 : } else {
296 5524 : state.dataLoopNodes->Node(this->OutletNodeNum).Temp = state.dataLoopNodes->Node(this->InletNodeNum[0]).Temp;
297 5524 : state.dataLoopNodes->Node(this->OutletNodeNum).HumRat = state.dataLoopNodes->Node(this->InletNodeNum[0]).HumRat;
298 5524 : state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRate = 0.0;
299 5524 : state.dataLoopNodes->Node(this->OutletNodeNum).Enthalpy = state.dataLoopNodes->Node(this->InletNodeNum[0]).Enthalpy;
300 5524 : this->OutletTemp = state.dataLoopNodes->Node(this->InletNodeNum[0]).Temp;
301 : }
302 10882 : }
303 :
304 1 : int getAirLoopMixerIndex(EnergyPlusData &state, std::string const &objectName)
305 : {
306 1 : if (state.dataAirLoopHVACDOAS->getAirLoopMixerInputOnceFlag) {
307 1 : AirLoopMixer::getAirLoopMixer(state);
308 1 : state.dataAirLoopHVACDOAS->getAirLoopMixerInputOnceFlag = false;
309 : }
310 :
311 1 : int index = -1;
312 1 : for (std::size_t loop = 0; loop < state.dataAirLoopHVACDOAS->airloopMixer.size(); ++loop) {
313 1 : AirLoopMixer *thisAirLoopMixerObjec = &state.dataAirLoopHVACDOAS->airloopMixer[loop];
314 1 : if (Util::SameString(objectName, thisAirLoopMixerObjec->name)) {
315 1 : index = loop;
316 1 : return index;
317 : }
318 : }
319 0 : ShowSevereError(state, format("getAirLoopMixer: did not find AirLoopHVAC:Mixer name ={}. Check inputs", objectName));
320 0 : return index;
321 : }
322 :
323 1 : AirLoopSplitter *AirLoopSplitter::factory(EnergyPlusData &state, int object_num, std::string const &objectName)
324 : {
325 :
326 1 : if (state.dataAirLoopHVACDOAS->getAirLoopSplitterInputOnceFlag) {
327 0 : AirLoopSplitter::getAirLoopSplitter(state);
328 0 : state.dataAirLoopHVACDOAS->getAirLoopSplitterInputOnceFlag = false;
329 : }
330 :
331 1 : int SplitterNum = -1;
332 1 : for (auto &dSpec : state.dataAirLoopHVACDOAS->airloopSplitter) {
333 1 : SplitterNum++;
334 1 : if (Util::SameString(dSpec.name, objectName) && dSpec.m_AirLoopSplitter_Num == object_num) {
335 1 : return &dSpec;
336 : }
337 2 : }
338 0 : ShowSevereError(state, format("AirLoopSplitter factory: Error getting inputs for system named: {}", objectName));
339 0 : return nullptr;
340 : }
341 :
342 10882 : void AirLoopSplitter::CalcAirLoopSplitter(EnergyPlusData &state, Real64 Temp, Real64 HumRat)
343 : {
344 65292 : for (int i = 0; i < this->numOfOutletNodes; i++) {
345 54410 : state.dataLoopNodes->Node(this->OutletNodeNum[i]).Temp = Temp;
346 54410 : state.dataLoopNodes->Node(this->OutletNodeNum[i]).HumRat = HumRat;
347 54410 : state.dataLoopNodes->Node(this->OutletNodeNum[i]).Enthalpy = Psychrometrics::PsyHFnTdbW(Temp, HumRat);
348 : }
349 10882 : this->InletTemp = Temp;
350 10882 : }
351 :
352 1 : int getAirLoopSplitterIndex(EnergyPlusData &state, std::string const &objectName)
353 : {
354 1 : if (state.dataAirLoopHVACDOAS->getAirLoopSplitterInputOnceFlag) {
355 1 : AirLoopSplitter::getAirLoopSplitter(state);
356 1 : state.dataAirLoopHVACDOAS->getAirLoopSplitterInputOnceFlag = false;
357 : }
358 :
359 1 : int index = -1;
360 1 : for (std::size_t loop = 0; loop < state.dataAirLoopHVACDOAS->airloopSplitter.size(); ++loop) {
361 1 : AirLoopSplitter *thisAirLoopSplitterObjec = &state.dataAirLoopHVACDOAS->airloopSplitter[loop];
362 1 : if (Util::SameString(objectName, thisAirLoopSplitterObjec->name)) {
363 1 : index = loop;
364 1 : return index;
365 : }
366 : }
367 0 : ShowSevereError(state, format("getAirLoopSplitter: did not find AirLoopSplitter name ={}. Check inputs", objectName));
368 0 : return index;
369 : }
370 :
371 1 : void AirLoopSplitter::getAirLoopSplitter(EnergyPlusData &state)
372 : {
373 :
374 1 : std::string const cCurrentModuleObject = "AirLoopHVAC:Splitter";
375 :
376 1 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(cCurrentModuleObject);
377 1 : if (instances != state.dataInputProcessing->inputProcessor->epJSON.end()) {
378 1 : bool errorsFound(false);
379 1 : std::string cFieldName;
380 1 : int AirLoopSplitterNum = 0;
381 1 : auto &instancesValue = instances.value();
382 2 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
383 :
384 1 : auto const &fields = instance.value();
385 1 : std::string const &thisObjectName = instance.key();
386 1 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(cCurrentModuleObject, thisObjectName);
387 :
388 1 : ++AirLoopSplitterNum;
389 1 : AirLoopSplitter thisSplitter;
390 :
391 1 : thisSplitter.name = Util::makeUPPER(thisObjectName);
392 1 : thisSplitter.InletNodeName = Util::makeUPPER(fields.at("inlet_node_name").get<std::string>());
393 1 : thisSplitter.InletNodeNum = NodeInputManager::GetOnlySingleNode(state,
394 : thisSplitter.InletNodeName,
395 : errorsFound,
396 : DataLoopNode::ConnectionObjectType::AirLoopHVACSplitter,
397 : thisObjectName,
398 : DataLoopNode::NodeFluidType::Air,
399 : DataLoopNode::ConnectionType::Inlet,
400 : NodeInputManager::CompFluidStream::Primary,
401 : DataLoopNode::ObjectIsParent);
402 1 : thisSplitter.m_AirLoopSplitter_Num = AirLoopSplitterNum - 1;
403 :
404 1 : auto NodeNames = fields.find("nodes");
405 1 : if (NodeNames != fields.end()) {
406 1 : auto const &NodeArray = NodeNames.value();
407 1 : thisSplitter.numOfOutletNodes = NodeArray.size();
408 1 : int num = 0;
409 6 : for (auto const &NodeDOASName : NodeArray) {
410 5 : num += 1;
411 :
412 10 : std::string name = Util::makeUPPER(NodeDOASName.at("outlet_node_name").get<std::string>());
413 5 : int NodeNum = NodeInputManager::GetOnlySingleNode(state,
414 : name,
415 : errorsFound,
416 : DataLoopNode::ConnectionObjectType::AirLoopHVACSplitter,
417 : thisObjectName,
418 : DataLoopNode::NodeFluidType::Air,
419 : DataLoopNode::ConnectionType::Inlet,
420 : NodeInputManager::CompFluidStream::Primary,
421 5 : DataLoopNode::ObjectIsParent);
422 5 : if (NodeNum > 0 && num <= thisSplitter.numOfOutletNodes) {
423 5 : thisSplitter.OutletNodeName.push_back(name);
424 5 : thisSplitter.OutletNodeNum.push_back(NodeNum);
425 : } else {
426 0 : cFieldName = "Outlet Node Name";
427 0 : ShowSevereError(state, format("{}, \"{}\"{} not found: {}", cCurrentModuleObject, thisSplitter.name, cFieldName, name));
428 0 : errorsFound = true;
429 : }
430 6 : }
431 : }
432 :
433 1 : state.dataAirLoopHVACDOAS->airloopSplitter.push_back(thisSplitter);
434 2 : }
435 1 : if (errorsFound) {
436 0 : ShowFatalError(state, "getAirLoopSplitter: Previous errors cause termination.");
437 : }
438 1 : }
439 1 : } // namespace AirLoopSplitter
440 :
441 1 : void AirLoopDOAS::getAirLoopDOASInput(EnergyPlusData &state)
442 : {
443 :
444 1 : std::string const cCurrentModuleObject = "AirLoopHVAC:DedicatedOutdoorAirSystem";
445 :
446 1 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(cCurrentModuleObject);
447 1 : if (instances != state.dataInputProcessing->inputProcessor->epJSON.end()) {
448 1 : bool errorsFound(false);
449 1 : std::string cFieldName;
450 1 : int AirLoopDOASNum = 0;
451 1 : auto &instancesValue = instances.value();
452 2 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
453 :
454 1 : auto const &fields = instance.value();
455 1 : std::string const &thisObjectName = instance.key();
456 1 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(cCurrentModuleObject, thisObjectName);
457 1 : ++AirLoopDOASNum;
458 1 : AirLoopDOAS thisDOAS;
459 :
460 1 : thisDOAS.Name = Util::makeUPPER(thisObjectName);
461 : // get OA and avail num
462 1 : thisDOAS.OASystemName = Util::makeUPPER(fields.at("airloophvac_outdoorairsystem_name").get<std::string>());
463 1 : thisDOAS.m_OASystemNum = Util::FindItemInList(thisDOAS.OASystemName, state.dataAirLoop->OutsideAirSys);
464 :
465 1 : if (thisDOAS.m_OASystemNum == 0) {
466 0 : cFieldName = "AirLoopHVAC:OutdoorAirSystem Name";
467 0 : ShowSevereError(state,
468 0 : format("{}, \"{}\", {} not found: {}\n", cCurrentModuleObject, thisDOAS.Name, cFieldName, thisDOAS.OASystemName));
469 0 : errorsFound = true;
470 : }
471 : // Check controller type
472 1 : std::string_view CurrentModuleObject = "AirLoopHVAC:OutdoorAirSystem";
473 1 : auto &thisOutsideAirSys = state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum);
474 3 : for (int InListNum = 1; InListNum <= thisOutsideAirSys.NumControllers; ++InListNum) {
475 2 : if (Util::SameString(thisOutsideAirSys.ControllerType(InListNum), "Controller:OutdoorAir")) {
476 0 : ShowSevereError(state,
477 0 : format("When {} = {} is used in AirLoopHVAC:DedicatedOutdoorAirSystem,",
478 : CurrentModuleObject,
479 : thisOutsideAirSys.ControllerName(InListNum)));
480 0 : ShowContinueError(state, "The Controller:OutdoorAir can not be used as a controller. Please remove it");
481 0 : errorsFound = true;
482 : }
483 : }
484 :
485 : // get inlet and outlet node number from equipment list
486 1 : CurrentModuleObject = "AirLoopHVAC:OutdoorAirSystem:EquipmentList";
487 1 : int CoolingCoilOrder = 0;
488 1 : int FanOrder = 0;
489 4 : for (int CompNum = 1; CompNum <= thisOutsideAirSys.NumComponents; ++CompNum) {
490 3 : std::string &CompType = thisOutsideAirSys.ComponentType(CompNum);
491 3 : std::string &CompName = thisOutsideAirSys.ComponentName(CompNum);
492 :
493 3 : bool InletNodeErrFlag = false;
494 3 : bool OutletNodeErrFlag = false;
495 :
496 3 : const std::string typeNameUC = Util::makeUPPER(thisOutsideAirSys.ComponentType(CompNum));
497 3 : ValidEquipListType foundType = static_cast<ValidEquipListType>(getEnumValue(validEquipNamesUC, typeNameUC));
498 :
499 3 : switch (foundType) {
500 0 : case ValidEquipListType::OutdoorAirMixer:
501 0 : ShowSevereError(state,
502 0 : format("When {} = {} is used in AirLoopHVAC:DedicatedOutdoorAirSystem,", CurrentModuleObject, CompName));
503 0 : ShowContinueError(state, " the OUTDOORAIR:MIXER can not be used as a component. Please remove it");
504 0 : errorsFound = true;
505 0 : break;
506 :
507 0 : case ValidEquipListType::FanConstantVolume:
508 0 : ShowSevereError(state,
509 0 : format("When {} = {} is used in AirLoopHVAC:DedicatedOutdoorAirSystem,", CurrentModuleObject, CompName));
510 0 : ShowContinueError(state,
511 : " the FAN:CONSTANTVOLUME can not be used as a component. The allowed fan types are FAN:SYSTEMMODEL and "
512 : "FAN:COMPONENTMODEL. Please change it");
513 0 : errorsFound = true;
514 0 : break;
515 :
516 0 : case ValidEquipListType::FanVariableVolume:
517 0 : ShowSevereError(state,
518 0 : format("When {} = {} is used in AirLoopHVAC:DedicatedOutdoorAirSystem,", CurrentModuleObject, CompName));
519 0 : ShowContinueError(state,
520 : " the FAN:VARIABLEVOLUME can not be used as a component. The allowed fan types are FAN:SYSTEMMODEL and "
521 : "FAN:COMPONENTMODEL. Please change it");
522 0 : errorsFound = true;
523 0 : break;
524 :
525 1 : case ValidEquipListType::FanSystemModel:
526 1 : thisDOAS.FanName = CompName;
527 1 : thisDOAS.m_FanTypeNum = SimAirServingZones::CompType::Fan_System_Object;
528 1 : thisDOAS.m_FanIndex = Fans::GetFanIndex(state, CompName);
529 1 : thisOutsideAirSys.InletNodeNum(CompNum) = state.dataFans->fans(thisDOAS.m_FanIndex)->inletNodeNum;
530 1 : if (thisOutsideAirSys.InletNodeNum(CompNum) == 0) {
531 0 : InletNodeErrFlag = true;
532 : }
533 1 : thisOutsideAirSys.OutletNodeNum(CompNum) = state.dataFans->fans(thisDOAS.m_FanIndex)->outletNodeNum;
534 1 : if (thisOutsideAirSys.OutletNodeNum(CompNum) == 0) {
535 0 : OutletNodeErrFlag = true;
536 : }
537 1 : thisDOAS.m_FanInletNodeNum = thisOutsideAirSys.InletNodeNum(CompNum);
538 1 : thisDOAS.m_FanOutletNodeNum = thisOutsideAirSys.OutletNodeNum(CompNum);
539 1 : if (CompNum == 1) {
540 1 : thisDOAS.FanBeforeCoolingCoilFlag = true;
541 : }
542 1 : FanOrder = CompNum;
543 1 : break;
544 :
545 0 : case ValidEquipListType::FanComponentModel:
546 0 : thisDOAS.m_FanTypeNum = SimAirServingZones::CompType::Fan_ComponentModel;
547 0 : thisDOAS.m_FanIndex = Fans::GetFanIndex(state, CompName);
548 0 : thisDOAS.FanName = CompName;
549 0 : if (CompNum == 1) {
550 0 : thisDOAS.FanBeforeCoolingCoilFlag = true;
551 : }
552 0 : thisOutsideAirSys.InletNodeNum(CompNum) = state.dataFans->fans(thisDOAS.m_FanIndex)->inletNodeNum;
553 0 : thisOutsideAirSys.OutletNodeNum(CompNum) = state.dataFans->fans(thisDOAS.m_FanIndex)->outletNodeNum;
554 0 : thisDOAS.m_FanInletNodeNum = thisOutsideAirSys.InletNodeNum(CompNum);
555 0 : thisDOAS.m_FanOutletNodeNum = thisOutsideAirSys.OutletNodeNum(CompNum);
556 0 : FanOrder = CompNum;
557 0 : break;
558 :
559 1 : case ValidEquipListType::CoilCoolingWater:
560 1 : thisOutsideAirSys.InletNodeNum(CompNum) = WaterCoils::GetCoilInletNode(state, typeNameUC, CompName, InletNodeErrFlag);
561 1 : thisOutsideAirSys.OutletNodeNum(CompNum) = WaterCoils::GetCoilOutletNode(state, typeNameUC, CompName, OutletNodeErrFlag);
562 1 : thisDOAS.CWCtrlNodeNum = WaterCoils::GetCoilWaterInletNode(state, "COIL:COOLING:WATER", CompName, errorsFound);
563 1 : if (errorsFound) {
564 0 : ShowContinueError(state, format("The control node number is not found in {} = {}", CurrentModuleObject, CompName));
565 : }
566 1 : PlantUtilities::ScanPlantLoopsForObject(
567 : state, CompName, DataPlant::PlantEquipmentType::CoilWaterCooling, thisDOAS.CWPlantLoc, errorsFound, _, _, _, _, _);
568 1 : if (errorsFound) { // is this really needed here, program fatals out later on when errorsFound = true
569 0 : ShowFatalError(state, "GetAirLoopDOASInput: Program terminated for previous conditions.");
570 : }
571 1 : CoolingCoilOrder = CompNum;
572 1 : break;
573 :
574 1 : case ValidEquipListType::CoilHeatingWater:
575 1 : thisOutsideAirSys.InletNodeNum(CompNum) = WaterCoils::GetCoilInletNode(state, typeNameUC, CompName, InletNodeErrFlag);
576 1 : thisOutsideAirSys.OutletNodeNum(CompNum) = WaterCoils::GetCoilOutletNode(state, typeNameUC, CompName, OutletNodeErrFlag);
577 1 : thisDOAS.HWCtrlNodeNum = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", CompName, errorsFound);
578 1 : if (errorsFound) {
579 0 : ShowContinueError(state, format("The control node number is not found in {} = {}", CurrentModuleObject, CompName));
580 : }
581 1 : PlantUtilities::ScanPlantLoopsForObject(
582 : state, CompName, DataPlant::PlantEquipmentType::CoilWaterSimpleHeating, thisDOAS.HWPlantLoc, errorsFound, _, _, _, _, _);
583 1 : if (errorsFound) { // is this really needed here, program fatals out later on when errorsFound = true
584 0 : ShowFatalError(state, "GetAirLoopDOASInput: Program terminated for previous conditions.");
585 : }
586 1 : break;
587 :
588 0 : case ValidEquipListType::CoilHeatingSteam:
589 0 : thisOutsideAirSys.InletNodeNum(CompNum) = SteamCoils::GetCoilSteamInletNode(state, CompType, CompName, InletNodeErrFlag);
590 0 : thisOutsideAirSys.OutletNodeNum(CompNum) = SteamCoils::GetCoilSteamOutletNode(state, CompType, CompName, OutletNodeErrFlag);
591 0 : break;
592 :
593 0 : case ValidEquipListType::CoilCoolingWaterDetailedGeometry:
594 0 : thisOutsideAirSys.InletNodeNum(CompNum) = WaterCoils::GetCoilInletNode(state, typeNameUC, CompName, InletNodeErrFlag);
595 0 : thisOutsideAirSys.OutletNodeNum(CompNum) = WaterCoils::GetCoilOutletNode(state, typeNameUC, CompName, OutletNodeErrFlag);
596 0 : thisDOAS.CWCtrlNodeNum =
597 0 : WaterCoils::GetCoilWaterInletNode(state, "Coil:Cooling:Water:DetailedGeometry", CompName, errorsFound);
598 0 : if (errorsFound) {
599 0 : ShowContinueError(state, format("The control node number is not found in {} = {}", CurrentModuleObject, CompName));
600 : }
601 0 : PlantUtilities::ScanPlantLoopsForObject(state,
602 : CompName,
603 : DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling,
604 : thisDOAS.CWPlantLoc,
605 : errorsFound,
606 : _,
607 : _,
608 : _,
609 : _,
610 : _);
611 0 : if (errorsFound) { // is this really needed here, program fatals out later on when errorsFound = true
612 0 : ShowFatalError(state, "GetAirLoopDOASInput: Program terminated for previous conditions.");
613 : }
614 0 : CoolingCoilOrder = CompNum;
615 0 : break;
616 :
617 0 : case ValidEquipListType::CoilHeatingElectric:
618 : case ValidEquipListType::CoilHeatingFuel:
619 0 : thisOutsideAirSys.InletNodeNum(CompNum) = HeatingCoils::GetCoilInletNode(state, typeNameUC, CompName, InletNodeErrFlag);
620 0 : thisOutsideAirSys.OutletNodeNum(CompNum) = HeatingCoils::GetCoilOutletNode(state, typeNameUC, CompName, OutletNodeErrFlag);
621 0 : break;
622 :
623 0 : case ValidEquipListType::CoilSystemCoolingWaterHeatExchangerAssisted:
624 0 : thisOutsideAirSys.InletNodeNum(CompNum) =
625 0 : HVACHXAssistedCoolingCoil::GetCoilInletNode(state, CompType, CompName, InletNodeErrFlag);
626 0 : thisOutsideAirSys.OutletNodeNum(CompNum) =
627 0 : HVACHXAssistedCoolingCoil::GetCoilOutletNode(state, CompType, CompName, OutletNodeErrFlag);
628 0 : break;
629 :
630 0 : case ValidEquipListType::CoilSystemCoolingDX:
631 : case ValidEquipListType::AirLoopHVACUnitarySystem:
632 0 : if (thisOutsideAirSys.compPointer[CompNum] == nullptr) {
633 0 : UnitarySystems::UnitarySys thisSys;
634 0 : thisOutsideAirSys.compPointer[CompNum] =
635 0 : UnitarySystems::UnitarySys::factory(state, HVAC::UnitarySysType::Unitary_AnyCoilType, CompName, false, 0);
636 0 : }
637 0 : thisOutsideAirSys.InletNodeNum(CompNum) =
638 0 : thisOutsideAirSys.compPointer[CompNum]->getAirInNode(state, CompName, 0, InletNodeErrFlag);
639 0 : thisOutsideAirSys.OutletNodeNum(CompNum) =
640 0 : thisOutsideAirSys.compPointer[CompNum]->getAirOutNode(state, CompName, 0, OutletNodeErrFlag);
641 0 : CoolingCoilOrder = CompNum;
642 0 : break;
643 :
644 0 : case ValidEquipListType::CoilSystemHeatingDX:
645 0 : thisOutsideAirSys.InletNodeNum(CompNum) = HVACDXHeatPumpSystem::GetHeatingCoilInletNodeNum(state, CompName, InletNodeErrFlag);
646 0 : thisOutsideAirSys.OutletNodeNum(CompNum) =
647 0 : HVACDXHeatPumpSystem::GetHeatingCoilOutletNodeNum(state, CompName, OutletNodeErrFlag);
648 0 : break;
649 :
650 0 : case ValidEquipListType::CoilUserDefined:
651 0 : ShowSevereError(state,
652 0 : format("When {} = {} is used in AirLoopHVAC:DedicatedOutdoorAirSystem,", CurrentModuleObject, CompName));
653 0 : ShowContinueError(state, " the COIL:USERDEFINED can not be used as a component.");
654 0 : errorsFound = true;
655 0 : break;
656 :
657 0 : case ValidEquipListType::HeatExchangerAirToAirFlatPlate:
658 : case ValidEquipListType::HeatExchangerAirToAirSensibleAndLatent:
659 : case ValidEquipListType::HeatExchangerDesiccantBalancedFlow:
660 0 : thisOutsideAirSys.HeatExchangerFlag = true;
661 0 : thisOutsideAirSys.InletNodeNum(CompNum) = HeatRecovery::GetSupplyInletNode(state, CompName, InletNodeErrFlag);
662 0 : thisOutsideAirSys.OutletNodeNum(CompNum) = HeatRecovery::GetSupplyOutletNode(state, CompName, OutletNodeErrFlag);
663 0 : break;
664 :
665 0 : case ValidEquipListType::DehumidifierDesiccantNoFans:
666 : case ValidEquipListType::DehumidifierDesiccantSystem:
667 0 : thisOutsideAirSys.InletNodeNum(CompNum) = DesiccantDehumidifiers::GetProcAirInletNodeNum(state, CompName, InletNodeErrFlag);
668 0 : thisOutsideAirSys.OutletNodeNum(CompNum) =
669 0 : DesiccantDehumidifiers::GetProcAirOutletNodeNum(state, CompName, OutletNodeErrFlag);
670 0 : break;
671 :
672 0 : case ValidEquipListType::HumidifierSteamElectric:
673 : case ValidEquipListType::HumidifierSteamGas:
674 0 : thisOutsideAirSys.InletNodeNum(CompNum) = Humidifiers::GetAirInletNodeNum(state, CompName, InletNodeErrFlag);
675 0 : thisOutsideAirSys.OutletNodeNum(CompNum) = Humidifiers::GetAirOutletNodeNum(state, CompName, OutletNodeErrFlag);
676 0 : break;
677 :
678 0 : case ValidEquipListType::SolarCollectorUnglazedTranspired:
679 0 : thisOutsideAirSys.InletNodeNum(CompNum) = TranspiredCollector::GetAirInletNodeNum(state, CompName, InletNodeErrFlag);
680 0 : thisOutsideAirSys.OutletNodeNum(CompNum) = TranspiredCollector::GetAirOutletNodeNum(state, CompName, OutletNodeErrFlag);
681 0 : break;
682 :
683 0 : case ValidEquipListType::SolarCollectorFlatPlatePhotovoltaicThermal:
684 0 : thisOutsideAirSys.InletNodeNum(CompNum) =
685 0 : PhotovoltaicThermalCollectors::GetAirInletNodeNum(state, CompName, InletNodeErrFlag);
686 0 : thisOutsideAirSys.OutletNodeNum(CompNum) =
687 0 : PhotovoltaicThermalCollectors::GetAirOutletNodeNum(state, CompName, OutletNodeErrFlag);
688 0 : break;
689 :
690 0 : case ValidEquipListType::EvaporativeCoolerDirectCeldekPad:
691 : case ValidEquipListType::EvaporativeCoolerIndirectCeldekPad:
692 : case ValidEquipListType::EvaporativeCoolerIndirectWetCoil:
693 : case ValidEquipListType::EvaporativeCoolerIndirectResearchSpecial:
694 : case ValidEquipListType::EvaporativeCoolerDirectResearchSpecial:
695 0 : thisOutsideAirSys.InletNodeNum(CompNum) = EvaporativeCoolers::GetInletNodeNum(state, CompName, InletNodeErrFlag);
696 0 : thisOutsideAirSys.OutletNodeNum(CompNum) = EvaporativeCoolers::GetOutletNodeNum(state, CompName, OutletNodeErrFlag);
697 0 : break;
698 :
699 0 : case ValidEquipListType::ZoneHVACTerminalUnitVariableRefrigerantFlow:
700 0 : thisOutsideAirSys.InletNodeNum(CompNum) =
701 0 : HVACVariableRefrigerantFlow::GetVRFTUInAirNodeFromName(state, CompName, InletNodeErrFlag);
702 0 : thisOutsideAirSys.OutletNodeNum(CompNum) =
703 0 : HVACVariableRefrigerantFlow::GetVRFTUOutAirNodeFromName(state, CompName, OutletNodeErrFlag);
704 0 : break;
705 :
706 0 : default:
707 0 : ShowSevereError(state,
708 0 : format(R"({} = "{}" invalid Outside Air Component="{}".)",
709 : CurrentModuleObject,
710 : CompName,
711 : thisOutsideAirSys.ComponentType(CompNum)));
712 0 : errorsFound = true;
713 : }
714 3 : if (CoolingCoilOrder > FanOrder && !thisDOAS.FanBeforeCoolingCoilFlag) {
715 0 : thisDOAS.FanBeforeCoolingCoilFlag = true;
716 : }
717 3 : if (InletNodeErrFlag) {
718 0 : ShowSevereError(state, format("Inlet node number is not found in {} = {}", CurrentModuleObject, CompName));
719 0 : errorsFound = true;
720 : }
721 3 : if (OutletNodeErrFlag) {
722 0 : ShowSevereError(state, format("Outlet node number is not found in {} = {}", CurrentModuleObject, CompName));
723 0 : errorsFound = true;
724 : }
725 : // Check node connection to ensure that the outlet node of the previous component is the inlet node of the current component
726 3 : if (CompNum > 1) {
727 2 : if (thisOutsideAirSys.InletNodeNum(CompNum) != thisOutsideAirSys.OutletNodeNum(CompNum - 1)) {
728 0 : ShowSevereError(state,
729 0 : format("getAirLoopMixer: Node Connection Error in AirLoopHVAC:DedicatedOutdoorAirSystem = {}. Inlet node "
730 : "of {} as current component is not same as the outlet node of "
731 : "{} as previous component",
732 : thisDOAS.Name,
733 : thisOutsideAirSys.ComponentName(CompNum),
734 : thisOutsideAirSys.ComponentName(CompNum - 1)));
735 0 : ShowContinueError(state,
736 0 : format("The inlet node name = {}, and the outlet node name = {}.",
737 0 : state.dataLoopNodes->NodeID(thisOutsideAirSys.InletNodeNum(CompNum)),
738 0 : state.dataLoopNodes->NodeID(thisOutsideAirSys.OutletNodeNum(CompNum - 1))));
739 0 : errorsFound = true;
740 : }
741 : }
742 3 : }
743 :
744 1 : thisDOAS.m_InletNodeNum = thisOutsideAirSys.InletNodeNum(1);
745 1 : thisDOAS.m_OutletNodeNum = thisOutsideAirSys.OutletNodeNum(thisOutsideAirSys.NumComponents);
746 1 : thisOutsideAirSys.AirLoopDOASNum = AirLoopDOASNum - 1;
747 : // Set up parent-child connection
748 2 : BranchNodeConnections::SetUpCompSets(state,
749 : cCurrentModuleObject,
750 : thisDOAS.Name,
751 : "AIRLOOPHVAC:OUTDOORAIRSYSTEM",
752 : thisDOAS.OASystemName,
753 1 : state.dataLoopNodes->NodeID(thisDOAS.m_InletNodeNum),
754 1 : state.dataLoopNodes->NodeID(thisDOAS.m_OutletNodeNum));
755 :
756 1 : if (thisOutsideAirSys.HeatExchangerFlag) {
757 0 : thisDOAS.m_HeatExchangerFlag = true;
758 : }
759 :
760 1 : thisDOAS.AvailManagerSchedName = Util::makeUPPER(fields.at("availability_schedule_name").get<std::string>());
761 1 : thisDOAS.m_AvailManagerSchedPtr = ScheduleManager::GetScheduleIndex(state, thisDOAS.AvailManagerSchedName);
762 1 : if (thisDOAS.m_AvailManagerSchedPtr == 0) {
763 0 : cFieldName = "Availability Schedule Name";
764 0 : ShowSevereError(
765 : state,
766 0 : format("{}, \"{}\" {} not found: {}", cCurrentModuleObject, thisDOAS.Name, cFieldName, thisDOAS.AvailManagerSchedName));
767 0 : errorsFound = true;
768 : }
769 :
770 1 : thisDOAS.AirLoopMixerName = Util::makeUPPER(fields.at("airloophvac_mixer_name").get<std::string>()); //
771 1 : thisDOAS.m_AirLoopMixerIndex = getAirLoopMixerIndex(state, thisDOAS.AirLoopMixerName);
772 1 : if (thisDOAS.m_AirLoopMixerIndex < 0) {
773 0 : cFieldName = "AirLoopHVAC:Mixer Name";
774 0 : ShowSevereError(
775 0 : state, format("{}, \"{}\" {} not found: {}", cCurrentModuleObject, thisDOAS.Name, cFieldName, thisDOAS.AirLoopMixerName));
776 0 : errorsFound = true;
777 : }
778 2 : AirLoopMixer thisAirLoopMixer;
779 1 : thisDOAS.m_CompPointerAirLoopMixer = thisAirLoopMixer.factory(state, thisDOAS.m_AirLoopMixerIndex, thisDOAS.AirLoopMixerName);
780 1 : thisDOAS.AirLoopSplitterName = Util::makeUPPER(fields.at("airloophvac_splitter_name").get<std::string>()); //
781 1 : thisDOAS.m_AirLoopSplitterIndex = getAirLoopSplitterIndex(state, thisDOAS.AirLoopSplitterName);
782 1 : if (thisDOAS.m_AirLoopSplitterIndex < 0) {
783 0 : cFieldName = "AirLoopHVAC:Splitter Name";
784 0 : ShowSevereError(
785 0 : state, format("{}, \"{}\" {} not found: {}", cCurrentModuleObject, thisDOAS.Name, cFieldName, thisDOAS.AirLoopSplitterName));
786 0 : errorsFound = true;
787 : }
788 2 : AirLoopSplitter thisAirLoopSplitter;
789 1 : thisDOAS.m_CompPointerAirLoopSplitter =
790 1 : thisAirLoopSplitter.factory(state, thisDOAS.m_AirLoopSplitterIndex, thisDOAS.AirLoopSplitterName);
791 :
792 : // get pretreated desing conditions
793 1 : thisDOAS.PreheatTemp = fields.at("preheat_design_temperature").get<Real64>();
794 1 : thisDOAS.PreheatHumRat = fields.at("preheat_design_humidity_ratio").get<Real64>();
795 1 : thisDOAS.PrecoolTemp = fields.at("precool_design_temperature").get<Real64>();
796 1 : thisDOAS.PrecoolHumRat = fields.at("precool_design_humidity_ratio").get<Real64>();
797 :
798 : // get info on AirLoops
799 1 : thisDOAS.NumOfAirLoops = fields.at("number_of_airloophvac").get<int>(); //
800 1 : if (thisDOAS.NumOfAirLoops < 1) {
801 0 : cFieldName = "Number of AirLoopHVAC";
802 0 : ShowSevereError(state,
803 0 : fmt::format("{}, \"{}\" {} = {}", cCurrentModuleObject, thisDOAS.Name, cFieldName, thisDOAS.NumOfAirLoops));
804 0 : ShowContinueError(state, " The minimum value should be 1.");
805 0 : errorsFound = true;
806 : }
807 :
808 2 : auto AirLoopNames = fields.find("airloophvacs");
809 1 : if (AirLoopNames != fields.end()) {
810 1 : auto const &AirLoopArray = AirLoopNames.value();
811 1 : int num = 0;
812 6 : for (auto const &AirLoopHVACName : AirLoopArray) {
813 10 : std::string name = Util::makeUPPER(AirLoopHVACName.at("airloophvac_name").get<std::string>());
814 5 : int LoopNum = Util::FindItemInList(name, state.dataAirSystemsData->PrimaryAirSystems);
815 :
816 5 : num += 1;
817 5 : if (LoopNum > 0 && num <= thisDOAS.NumOfAirLoops) {
818 5 : thisDOAS.AirLoopName.push_back(name);
819 5 : thisDOAS.m_AirLoopNum.push_back(LoopNum);
820 : } else {
821 0 : cFieldName = "AirLoopHVAC Name";
822 0 : ShowSevereError(state, format("{}, \"{}\" {} not found: {}", cCurrentModuleObject, thisDOAS.Name, cFieldName, name));
823 0 : errorsFound = true;
824 : }
825 6 : }
826 : }
827 :
828 1 : thisDOAS.m_AirLoopDOASNum = AirLoopDOASNum - 1;
829 1 : state.dataAirLoopHVACDOAS->airloopDOAS.push_back(thisDOAS);
830 :
831 1 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, thisDOAS.m_InletNodeNum)) {
832 0 : ShowSevereError(state,
833 0 : format("Inlet node ({}) is not one of OutdoorAir:Node in {} = {}",
834 0 : state.dataLoopNodes->NodeID(thisDOAS.m_InletNodeNum),
835 : CurrentModuleObject,
836 : thisDOAS.Name));
837 0 : errorsFound = true;
838 : }
839 :
840 : // Ensure the outlet node is the splitter inlet node, otherwise issue a severe error
841 1 : if (thisDOAS.m_OutletNodeNum != thisDOAS.m_CompPointerAirLoopSplitter->InletNodeNum) {
842 0 : ShowSevereError(
843 : state,
844 0 : format("The outlet node is not the inlet node of AirLoopHVAC:Splitter in {} = {}", CurrentModuleObject, thisDOAS.Name));
845 0 : ShowContinueError(state,
846 0 : format("The outlet node name is {}, and the inlet node name of AirLoopHVAC:Splitter is {}",
847 0 : state.dataLoopNodes->NodeID(thisDOAS.m_OutletNodeNum),
848 0 : state.dataLoopNodes->NodeID(thisDOAS.m_CompPointerAirLoopSplitter->InletNodeNum)));
849 0 : errorsFound = true;
850 : }
851 2 : }
852 :
853 : // Check valid OA controller
854 7 : for (int OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; OASysNum++) {
855 6 : if (Util::SameString(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerListName, "")) {
856 0 : if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum == -1) {
857 0 : ShowSevereError(state,
858 0 : format("AirLoopHVAC:OutdoorAirSystem = \"{}\" invalid Controller List Name = \" not found.",
859 0 : state.dataAirLoop->OutsideAirSys(OASysNum).Name));
860 0 : errorsFound = true;
861 : }
862 : }
863 : }
864 1 : if (errorsFound) {
865 0 : ShowFatalError(state, "getAirLoopHVACDOAS: Previous errors cause termination.");
866 : }
867 1 : }
868 1 : }
869 :
870 10882 : void AirLoopDOAS::initAirLoopDOAS(EnergyPlusData &state, bool const FirstHVACIteration)
871 : {
872 : int LoopOA;
873 : Real64 SchAvailValue;
874 : static constexpr std::string_view RoutineName = "AirLoopDOAS::initAirLoopDOAS";
875 :
876 10882 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
877 5 : bool ErrorsFound = false;
878 : Real64 rho;
879 20 : for (int CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).NumComponents; ++CompNum) {
880 15 : std::string const &CompType = state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).ComponentType(CompNum);
881 15 : std::string const &CompName = state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).ComponentName(CompNum);
882 15 : if (Util::SameString(CompType, "FAN:SYSTEMMODEL")) {
883 5 : state.dataFans->fans(this->m_FanIndex)->simulate(state, FirstHVACIteration);
884 : }
885 15 : if (Util::SameString(CompType, "FAN:COMPONENTMODEL")) {
886 0 : state.dataFans->fans(this->m_FanIndex)->simulate(state, FirstHVACIteration);
887 : }
888 :
889 15 : if (Util::SameString(CompType, "COIL:HEATING:WATER")) {
890 5 : WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, this->m_HeatCoilNum);
891 5 : Real64 CoilMaxVolFlowRate = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", CompName, ErrorsFound);
892 5 : rho = FluidProperties::GetDensityGlycol(state,
893 5 : state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).FluidName,
894 : Constant::HWInitConvTemp,
895 5 : state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).FluidIndex,
896 : RoutineName);
897 5 : PlantUtilities::InitComponentNodes(state,
898 : 0.0,
899 : CoilMaxVolFlowRate * rho,
900 : this->HWCtrlNodeNum,
901 5 : state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).OutletNodeNum(CompNum));
902 : }
903 15 : if (Util::SameString(CompType, "COIL:COOLING:WATER")) {
904 5 : WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, this->m_CoolCoilNum);
905 5 : Real64 CoilMaxVolFlowRate = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Cooling:Water", CompName, ErrorsFound);
906 5 : rho = FluidProperties::GetDensityGlycol(state,
907 5 : state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
908 : Constant::CWInitConvTemp,
909 5 : state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
910 : RoutineName);
911 5 : PlantUtilities::InitComponentNodes(state,
912 : 0.0,
913 : CoilMaxVolFlowRate * rho,
914 : this->CWCtrlNodeNum,
915 5 : state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).OutletNodeNum(CompNum));
916 : }
917 15 : if (Util::SameString(CompType, "COIL:COOLING:WATER:DETAILEDGEOMETRY")) {
918 0 : WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, this->m_CoolCoilNum);
919 : Real64 CoilMaxVolFlowRate =
920 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Cooling:Water:DetailedGeometry", CompName, ErrorsFound);
921 0 : rho = FluidProperties::GetDensityGlycol(state,
922 0 : state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
923 : Constant::CWInitConvTemp,
924 0 : state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
925 : RoutineName);
926 0 : PlantUtilities::InitComponentNodes(state,
927 : 0.0,
928 : CoilMaxVolFlowRate * rho,
929 : this->CWCtrlNodeNum,
930 0 : state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).OutletNodeNum(CompNum));
931 : }
932 : }
933 :
934 5 : this->MyEnvrnFlag = false;
935 5 : if (ErrorsFound) {
936 0 : ShowFatalError(state, "initAirLoopDOAS: Previous errors cause termination.");
937 : }
938 : }
939 :
940 10882 : if (!state.dataGlobal->BeginEnvrnFlag) {
941 10832 : this->MyEnvrnFlag = true;
942 : }
943 :
944 10882 : this->SumMassFlowRate = 0.0;
945 :
946 65292 : for (LoopOA = 0; LoopOA < this->m_CompPointerAirLoopSplitter->numOfOutletNodes; LoopOA++) {
947 54410 : int NodeNum = this->m_CompPointerAirLoopSplitter->OutletNodeNum[LoopOA];
948 54410 : this->SumMassFlowRate += state.dataLoopNodes->Node(NodeNum).MassFlowRate;
949 : }
950 :
951 10882 : SchAvailValue = ScheduleManager::GetCurrentScheduleValue(state, this->m_AvailManagerSchedPtr);
952 10882 : if (SchAvailValue < 1.0) {
953 0 : this->SumMassFlowRate = 0.0;
954 : }
955 10882 : state.dataLoopNodes->Node(this->m_InletNodeNum).MassFlowRate = this->SumMassFlowRate;
956 10882 : }
957 :
958 10882 : void AirLoopDOAS::CalcAirLoopDOAS(EnergyPlusData &state, bool const FirstHVACIteration)
959 : {
960 : using MixedAir::ManageOutsideAirSystem;
961 :
962 10882 : this->m_CompPointerAirLoopMixer->CalcAirLoopMixer(state);
963 10882 : if (this->m_FanIndex > 0) {
964 10882 : if (this->m_FanInletNodeNum == this->m_InletNodeNum) {
965 10882 : state.dataLoopNodes->Node(this->m_FanInletNodeNum).MassFlowRateMaxAvail = this->SumMassFlowRate;
966 10882 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMaxAvail = this->SumMassFlowRate;
967 10882 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMax = this->SumMassFlowRate;
968 : } else {
969 0 : state.dataLoopNodes->Node(this->m_InletNodeNum).MassFlowRateMax = this->SumMassFlowRate;
970 0 : state.dataLoopNodes->Node(this->m_InletNodeNum).MassFlowRateMaxAvail = this->SumMassFlowRate;
971 : }
972 : }
973 10882 : ManageOutsideAirSystem(state, this->OASystemName, FirstHVACIteration, 0, this->m_OASystemNum);
974 10882 : Real64 Temp = state.dataLoopNodes->Node(this->m_OutletNodeNum).Temp;
975 10882 : Real64 HumRat = state.dataLoopNodes->Node(this->m_OutletNodeNum).HumRat;
976 10882 : state.dataLoopNodes->Node(this->m_OutletNodeNum).Enthalpy = Psychrometrics::PsyHFnTdbW(Temp, HumRat);
977 :
978 10882 : this->m_CompPointerAirLoopSplitter->CalcAirLoopSplitter(state, Temp, HumRat);
979 10882 : }
980 :
981 1 : void AirLoopDOAS::SizingAirLoopDOAS(EnergyPlusData &state)
982 : {
983 1 : Real64 sizingMassFlow = 0;
984 :
985 6 : for (int AirLoop = 1; AirLoop <= this->NumOfAirLoops; AirLoop++) {
986 5 : int AirLoopNum = this->m_AirLoopNum[AirLoop - 1];
987 5 : this->m_OACtrlNum.push_back(state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OACtrlNum);
988 :
989 5 : if (this->m_OACtrlNum[AirLoop - 1] > 0) {
990 5 : sizingMassFlow += state.dataMixedAir->OAController(this->m_OACtrlNum[AirLoop - 1]).MaxOA;
991 : }
992 : }
993 1 : this->SizingMassFlow = sizingMassFlow;
994 1 : this->GetDesignDayConditions(state);
995 :
996 1 : if (this->m_FanIndex > 0 && this->m_FanTypeNum == SimAirServingZones::CompType::Fan_System_Object) {
997 1 : state.dataFans->fans(this->m_FanIndex)->maxAirFlowRate = sizingMassFlow / state.dataEnvrn->StdRhoAir;
998 1 : state.dataLoopNodes->Node(this->m_FanInletNodeNum).MassFlowRateMaxAvail = sizingMassFlow;
999 1 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMaxAvail = sizingMassFlow;
1000 1 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMax = sizingMassFlow;
1001 : }
1002 1 : bool errorsFound = false;
1003 1 : if (this->m_FanIndex > 0 && this->m_FanTypeNum == SimAirServingZones::CompType::Fan_ComponentModel) {
1004 0 : state.dataFans->fans(this->m_FanIndex)->maxAirFlowRate = sizingMassFlow / state.dataEnvrn->StdRhoAir;
1005 0 : state.dataFans->fans(this->m_FanIndex)->minAirFlowRate = 0.0;
1006 0 : state.dataFans->fans(this->m_FanIndex)->maxAirMassFlowRate = sizingMassFlow;
1007 0 : state.dataLoopNodes->Node(this->m_FanInletNodeNum).MassFlowRateMaxAvail = sizingMassFlow;
1008 0 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMaxAvail = sizingMassFlow;
1009 0 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMax = sizingMassFlow;
1010 : }
1011 1 : if (errorsFound) {
1012 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
1013 : }
1014 1 : state.dataSize->CurSysNum = state.dataHVACGlobal->NumPrimaryAirSys + this->m_AirLoopDOASNum + 1;
1015 1 : state.dataSize->CurOASysNum = this->m_OASystemNum;
1016 1 : }
1017 :
1018 1 : void getAirLoopHVACDOASInput(EnergyPlusData &state)
1019 : {
1020 1 : if (state.dataAirLoopHVACDOAS->GetInputOnceFlag) {
1021 1 : AirLoopDOAS::getAirLoopDOASInput(state);
1022 1 : state.dataAirLoopHVACDOAS->GetInputOnceFlag = false;
1023 : }
1024 1 : }
1025 :
1026 1 : void AirLoopDOAS::GetDesignDayConditions(EnergyPlusData &state)
1027 : {
1028 4 : for (auto &env : state.dataWeather->Environment) {
1029 3 : if (env.KindOfEnvrn != Constant::KindOfSim::DesignDay && env.KindOfEnvrn != Constant::KindOfSim::RunPeriodDesign) continue;
1030 2 : if (env.maxCoolingOATSizing > this->SizingCoolOATemp) {
1031 2 : this->SizingCoolOATemp = env.maxCoolingOATSizing;
1032 : // DesignDayNum = 0 for KindOfSim == RunPeriodDesign
1033 2 : if (env.KindOfEnvrn == Constant::KindOfSim::DesignDay && state.dataWeather->DesDayInput(env.DesignDayNum).PressureEntered) {
1034 2 : this->SizingCoolOAHumRat =
1035 2 : Psychrometrics::PsyWFnTdpPb(state, env.maxCoolingOADPSizing, state.dataWeather->DesDayInput(env.DesignDayNum).PressBarom);
1036 : } else {
1037 0 : this->SizingCoolOAHumRat = Psychrometrics::PsyWFnTdpPb(state, env.maxCoolingOADPSizing, state.dataEnvrn->StdBaroPress);
1038 : }
1039 : }
1040 2 : if (env.minHeatingOATSizing < this->HeatOutTemp) {
1041 1 : this->HeatOutTemp = env.minHeatingOATSizing;
1042 1 : if (env.KindOfEnvrn == Constant::KindOfSim::DesignDay && state.dataWeather->DesDayInput(env.DesignDayNum).PressureEntered) {
1043 1 : this->HeatOutHumRat =
1044 1 : Psychrometrics::PsyWFnTdpPb(state, env.minHeatingOADPSizing, state.dataWeather->DesDayInput(env.DesignDayNum).PressBarom);
1045 : } else {
1046 0 : this->HeatOutHumRat = Psychrometrics::PsyWFnTdpPb(state, env.minHeatingOADPSizing, state.dataEnvrn->StdBaroPress);
1047 : }
1048 : }
1049 : }
1050 1 : }
1051 :
1052 5358 : void CheckConvergence(EnergyPlusData &state)
1053 : {
1054 :
1055 : Real64 maxDiff;
1056 : Real64 Diff;
1057 : Real64 OldTemp;
1058 10716 : for (auto &loop : state.dataAirLoopHVACDOAS->airloopDOAS) {
1059 5358 : maxDiff = 0.0;
1060 10716 : Diff = std::abs(loop.m_CompPointerAirLoopSplitter->InletTemp -
1061 5358 : state.dataLoopNodes->Node(loop.m_CompPointerAirLoopSplitter->OutletNodeNum[0]).Temp);
1062 5358 : if (Diff > maxDiff) {
1063 0 : maxDiff = Diff;
1064 : }
1065 5358 : if (loop.m_HeatExchangerFlag) {
1066 0 : OldTemp = loop.m_CompPointerAirLoopMixer->OutletTemp;
1067 0 : loop.m_CompPointerAirLoopMixer->CalcAirLoopMixer(state);
1068 0 : Diff = std::abs(OldTemp - loop.m_CompPointerAirLoopMixer->OutletTemp);
1069 0 : if (Diff > maxDiff) {
1070 0 : maxDiff = Diff;
1071 : }
1072 : }
1073 5358 : if (maxDiff > 1.0e-6) {
1074 0 : if (loop.ConveCount == 0) {
1075 0 : ++loop.ConveCount;
1076 0 : ShowWarningError(state, format("Convergence limit is above 1.0e-6 for unit={}", loop.Name));
1077 0 : ShowContinueErrorTimeStamp(
1078 0 : state, format("The max difference of node temperatures between AirLoopDOAS outlet and OA mixer inlet ={:.6R}", maxDiff));
1079 : } else {
1080 0 : ++loop.ConveCount;
1081 0 : ShowRecurringWarningErrorAtEnd(state,
1082 0 : loop.Name + "\": The max difference of node temperatures exceeding 1.0e-6 continues...",
1083 0 : loop.ConveIndex,
1084 : maxDiff,
1085 : maxDiff);
1086 : }
1087 : }
1088 5358 : }
1089 5358 : }
1090 :
1091 : } // namespace AirLoopHVACDOAS
1092 : } // namespace EnergyPlus
|