Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, 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/HVACFan.hh>
66 : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
67 : #include <EnergyPlus/HVACVariableRefrigerantFlow.hh>
68 : #include <EnergyPlus/HeatRecovery.hh>
69 : #include <EnergyPlus/HeatingCoils.hh>
70 : #include <EnergyPlus/Humidifiers.hh>
71 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
72 : #include <EnergyPlus/MixedAir.hh>
73 : #include <EnergyPlus/NodeInputManager.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 (UtilityRoutines::SameString(dSpec.name, objectName) && dSpec.m_AirLoopMixer_Num == object_num) {
201 1 : return &dSpec;
202 : }
203 : }
204 :
205 0 : ShowSevereError(state, "AirLoopMixer factory: Error getting inputs for system named: " + objectName);
206 0 : return nullptr;
207 : }
208 :
209 1 : void AirLoopMixer::getAirLoopMixer(EnergyPlusData &state)
210 : {
211 1 : bool errorsFound(false);
212 :
213 2 : std::string cCurrentModuleObject = "AirLoopHVAC:Mixer";
214 2 : std::string cFieldName;
215 :
216 2 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(cCurrentModuleObject);
217 1 : if (instances == state.dataInputProcessing->inputProcessor->epJSON.end()) {
218 0 : errorsFound = true;
219 : } else {
220 1 : int AirLoopMixerNum = 0;
221 1 : auto &instancesValue = instances.value();
222 2 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
223 :
224 1 : auto const &fields = instance.value();
225 1 : auto const &thisObjectName = instance.key();
226 1 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(cCurrentModuleObject, thisObjectName);
227 1 : ++AirLoopMixerNum;
228 2 : AirLoopMixer thisMixer;
229 :
230 1 : thisMixer.name = UtilityRoutines::MakeUPPERCase(thisObjectName);
231 1 : thisMixer.OutletNodeName = UtilityRoutines::MakeUPPERCase(fields.at("outlet_node_name").get<std::string>());
232 1 : thisMixer.m_AirLoopMixer_Num = AirLoopMixerNum - 1;
233 1 : thisMixer.OutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
234 : thisMixer.OutletNodeName,
235 : errorsFound,
236 : DataLoopNode::ConnectionObjectType::AirLoopHVACMixer,
237 : thisObjectName,
238 : DataLoopNode::NodeFluidType::Air,
239 : DataLoopNode::ConnectionType::Outlet,
240 : NodeInputManager::CompFluidStream::Primary,
241 1 : DataLoopNode::ObjectIsParent);
242 :
243 2 : auto NodeNames = fields.find("nodes");
244 1 : if (NodeNames != fields.end()) {
245 2 : auto NodeArray = NodeNames.value();
246 1 : thisMixer.numOfInletNodes = NodeArray.size();
247 1 : int num = 0;
248 6 : for (nlohmann::json &NodeDOASName : NodeArray) {
249 5 : num += 1;
250 10 : std::string name = UtilityRoutines::MakeUPPERCase(NodeDOASName.at("inlet_node_name").get<std::string>());
251 5 : int NodeNum = UtilityRoutines::FindItemInList(name, state.dataLoopNodes->NodeID);
252 5 : if (NodeNum > 0 && num <= thisMixer.numOfInletNodes) {
253 5 : thisMixer.InletNodeName.push_back(name);
254 5 : thisMixer.InletNodeNum.push_back(NodeNum);
255 : } else {
256 0 : cFieldName = "Inlet Node Name";
257 0 : ShowSevereError(state, cCurrentModuleObject + ", \"" + thisMixer.name + "\" " + name + " not found: " + cFieldName);
258 0 : errorsFound = true;
259 : }
260 : }
261 : }
262 :
263 1 : state.dataAirLoopHVACDOAS->airloopMixer.push_back(thisMixer);
264 : }
265 1 : if (errorsFound) {
266 0 : ShowFatalError(state, "getAirLoopMixer: Previous errors cause termination.");
267 : }
268 : }
269 1 : } // namespace AirLoopMixer
270 :
271 10882 : void AirLoopMixer::CalcAirLoopMixer(EnergyPlusData &state)
272 : {
273 10882 : Real64 outletTemp = 0.0;
274 10882 : Real64 outletHumRat = 0.0;
275 10882 : Real64 massSum = 0.0;
276 : int InletNum;
277 :
278 65292 : for (int i = 1; i <= this->numOfInletNodes; i++) {
279 54410 : InletNum = this->InletNodeNum[i - 1];
280 54410 : massSum += state.dataLoopNodes->Node(InletNum).MassFlowRate;
281 54410 : outletTemp += state.dataLoopNodes->Node(InletNum).MassFlowRate * state.dataLoopNodes->Node(InletNum).Temp;
282 54410 : outletHumRat += state.dataLoopNodes->Node(InletNum).MassFlowRate * state.dataLoopNodes->Node(InletNum).HumRat;
283 : }
284 10882 : if (massSum > 0.0) {
285 5358 : state.dataLoopNodes->Node(this->OutletNodeNum).Temp = outletTemp / massSum;
286 5358 : state.dataLoopNodes->Node(this->OutletNodeNum).HumRat = outletHumRat / massSum;
287 5358 : state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRate = massSum;
288 5358 : state.dataLoopNodes->Node(this->OutletNodeNum).Enthalpy = Psychrometrics::PsyHFnTdbW(outletTemp / massSum, outletHumRat / massSum);
289 5358 : this->OutletTemp = state.dataLoopNodes->Node(this->OutletNodeNum).Temp;
290 : } else {
291 5524 : state.dataLoopNodes->Node(this->OutletNodeNum).Temp = state.dataLoopNodes->Node(this->InletNodeNum[0]).Temp;
292 5524 : state.dataLoopNodes->Node(this->OutletNodeNum).HumRat = state.dataLoopNodes->Node(this->InletNodeNum[0]).HumRat;
293 5524 : state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRate = 0.0;
294 5524 : state.dataLoopNodes->Node(this->OutletNodeNum).Enthalpy = state.dataLoopNodes->Node(this->InletNodeNum[0]).Enthalpy;
295 5524 : this->OutletTemp = state.dataLoopNodes->Node(this->InletNodeNum[0]).Temp;
296 : }
297 10882 : }
298 :
299 1 : int getAirLoopMixerIndex(EnergyPlusData &state, std::string const &objectName)
300 : {
301 1 : if (state.dataAirLoopHVACDOAS->getAirLoopMixerInputOnceFlag) {
302 1 : AirLoopMixer::getAirLoopMixer(state);
303 1 : state.dataAirLoopHVACDOAS->getAirLoopMixerInputOnceFlag = false;
304 : }
305 :
306 1 : int index = -1;
307 1 : for (std::size_t loop = 0; loop < state.dataAirLoopHVACDOAS->airloopMixer.size(); ++loop) {
308 1 : AirLoopMixer *thisAirLoopMixerObjec = &state.dataAirLoopHVACDOAS->airloopMixer[loop];
309 1 : if (UtilityRoutines::SameString(objectName, thisAirLoopMixerObjec->name)) {
310 1 : index = loop;
311 1 : return index;
312 : }
313 : }
314 0 : ShowSevereError(state, "getAirLoopMixer: did not find AirLoopHVAC:Mixer name =" + objectName + ". Check inputs");
315 0 : return index;
316 : }
317 :
318 1 : AirLoopSplitter *AirLoopSplitter::factory(EnergyPlusData &state, int object_num, std::string const &objectName)
319 : {
320 :
321 1 : if (state.dataAirLoopHVACDOAS->getAirLoopSplitterInputOnceFlag) {
322 0 : AirLoopSplitter::getAirLoopSplitter(state);
323 0 : state.dataAirLoopHVACDOAS->getAirLoopSplitterInputOnceFlag = false;
324 : }
325 :
326 1 : int SplitterNum = -1;
327 1 : for (auto &dSpec : state.dataAirLoopHVACDOAS->airloopSplitter) {
328 1 : SplitterNum++;
329 1 : if (UtilityRoutines::SameString(dSpec.name, objectName) && dSpec.m_AirLoopSplitter_Num == object_num) {
330 1 : return &dSpec;
331 : }
332 : }
333 0 : ShowSevereError(state, "AirLoopSplitter factory: Error getting inputs for system named: " + objectName);
334 0 : return nullptr;
335 : }
336 :
337 10882 : void AirLoopSplitter::CalcAirLoopSplitter(EnergyPlusData &state, Real64 Temp, Real64 HumRat)
338 : {
339 65292 : for (int i = 0; i < this->numOfOutletNodes; i++) {
340 54410 : state.dataLoopNodes->Node(this->OutletNodeNum[i]).Temp = Temp;
341 54410 : state.dataLoopNodes->Node(this->OutletNodeNum[i]).HumRat = HumRat;
342 54410 : state.dataLoopNodes->Node(this->OutletNodeNum[i]).Enthalpy = Psychrometrics::PsyHFnTdbW(Temp, HumRat);
343 : }
344 10882 : this->InletTemp = Temp;
345 10882 : }
346 :
347 1 : int getAirLoopSplitterIndex(EnergyPlusData &state, std::string const &objectName)
348 : {
349 1 : if (state.dataAirLoopHVACDOAS->getAirLoopSplitterInputOnceFlag) {
350 1 : AirLoopSplitter::getAirLoopSplitter(state);
351 1 : state.dataAirLoopHVACDOAS->getAirLoopSplitterInputOnceFlag = false;
352 : }
353 :
354 1 : int index = -1;
355 1 : for (std::size_t loop = 0; loop < state.dataAirLoopHVACDOAS->airloopSplitter.size(); ++loop) {
356 1 : AirLoopSplitter *thisAirLoopSplitterObjec = &state.dataAirLoopHVACDOAS->airloopSplitter[loop];
357 1 : if (UtilityRoutines::SameString(objectName, thisAirLoopSplitterObjec->name)) {
358 1 : index = loop;
359 1 : return index;
360 : }
361 : }
362 0 : ShowSevereError(state, "getAirLoopSplitter: did not find AirLoopSplitter name =" + objectName + ". Check inputs");
363 0 : return index;
364 : }
365 :
366 1 : void AirLoopSplitter::getAirLoopSplitter(EnergyPlusData &state)
367 : {
368 1 : bool errorsFound(false);
369 :
370 2 : std::string cCurrentModuleObject = "AirLoopHVAC:Splitter";
371 2 : std::string cFieldName;
372 :
373 2 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(cCurrentModuleObject);
374 1 : if (instances == state.dataInputProcessing->inputProcessor->epJSON.end()) {
375 0 : errorsFound = true;
376 : } else {
377 1 : int AirLoopSplitterNum = 0;
378 1 : auto &instancesValue = instances.value();
379 2 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
380 :
381 1 : auto const &fields = instance.value();
382 1 : auto const &thisObjectName = instance.key();
383 1 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(cCurrentModuleObject, thisObjectName);
384 :
385 1 : ++AirLoopSplitterNum;
386 2 : AirLoopSplitter thisSplitter;
387 :
388 1 : thisSplitter.name = UtilityRoutines::MakeUPPERCase(thisObjectName);
389 1 : thisSplitter.InletNodeName = UtilityRoutines::MakeUPPERCase(fields.at("inlet_node_name").get<std::string>());
390 1 : thisSplitter.m_AirLoopSplitter_Num = AirLoopSplitterNum - 1;
391 :
392 2 : auto NodeNames = fields.find("nodes");
393 1 : if (NodeNames != fields.end()) {
394 2 : auto NodeArray = NodeNames.value();
395 1 : thisSplitter.numOfOutletNodes = NodeArray.size();
396 1 : int num = 0;
397 6 : for (nlohmann::json &NodeDOASName : NodeArray) {
398 5 : num += 1;
399 10 : std::string name = UtilityRoutines::MakeUPPERCase(NodeDOASName.at("outlet_node_name").get<std::string>());
400 5 : int NodeNum = UtilityRoutines::FindItemInList(name, state.dataLoopNodes->NodeID);
401 5 : if (NodeNum > 0 && num <= thisSplitter.numOfOutletNodes) {
402 5 : thisSplitter.OutletNodeName.push_back(name);
403 5 : thisSplitter.OutletNodeNum.push_back(NodeNum);
404 : } else {
405 0 : cFieldName = "Outlet Node Name";
406 0 : ShowSevereError(state, cCurrentModuleObject + ", \"" + thisSplitter.name + "\" " + cFieldName + " not found: " + name);
407 0 : errorsFound = true;
408 : }
409 : }
410 : }
411 :
412 1 : state.dataAirLoopHVACDOAS->airloopSplitter.push_back(thisSplitter);
413 : }
414 1 : if (errorsFound) {
415 0 : ShowFatalError(state, "getAirLoopSplitter: Previous errors cause termination.");
416 : }
417 : }
418 1 : } // namespace AirLoopSplitter
419 :
420 1 : void AirLoopDOAS::getAirLoopDOASInput(EnergyPlusData &state)
421 : {
422 :
423 : using ScheduleManager::GetScheduleIndex;
424 :
425 1 : bool errorsFound(false);
426 :
427 2 : std::string cCurrentModuleObject = "AirLoopHVAC:DedicatedOutdoorAirSystem";
428 2 : std::string cFieldName;
429 :
430 2 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find(cCurrentModuleObject);
431 1 : if (instances == state.dataInputProcessing->inputProcessor->epJSON.end()) {
432 0 : errorsFound = true;
433 : } else {
434 1 : int AirLoopDOASNum = 0;
435 1 : auto &instancesValue = instances.value();
436 2 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
437 :
438 1 : auto const &fields = instance.value();
439 1 : auto const &thisObjectName = instance.key();
440 1 : state.dataInputProcessing->inputProcessor->markObjectAsUsed(cCurrentModuleObject, thisObjectName);
441 1 : ++AirLoopDOASNum;
442 2 : AirLoopDOAS thisDOAS;
443 :
444 1 : thisDOAS.Name = UtilityRoutines::MakeUPPERCase(thisObjectName);
445 : // get OA and avail num
446 1 : thisDOAS.OASystemName = UtilityRoutines::MakeUPPERCase(fields.at("airloophvac_outdoorairsystem_name").get<std::string>());
447 1 : thisDOAS.m_OASystemNum = UtilityRoutines::FindItemInList(thisDOAS.OASystemName, state.dataAirLoop->OutsideAirSys);
448 1 : if (thisDOAS.m_OASystemNum == 0) {
449 0 : cFieldName = "AirLoopHVAC:OutdoorAirSystem Name";
450 0 : ShowSevereError(state,
451 0 : cCurrentModuleObject + ", \"" + thisDOAS.Name + "\" " + cFieldName + " not found: " + thisDOAS.OASystemName);
452 0 : errorsFound = true;
453 : }
454 : // Check controller type
455 2 : std::string CurrentModuleObject = "AirLoopHVAC:OutdoorAirSystem";
456 3 : for (int InListNum = 1; InListNum <= state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).NumControllers; ++InListNum) {
457 2 : if (UtilityRoutines::SameString(state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).ControllerType(InListNum),
458 2 : "Controller:OutdoorAir")) {
459 0 : ShowSevereError(state,
460 0 : "When " + CurrentModuleObject + " = " +
461 0 : state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).ControllerName(InListNum) +
462 : " is used in AirLoopHVAC:DedicatedOutdoorAirSystem,");
463 0 : ShowContinueError(state, "The Controller:OutdoorAir can not be used as a controller. Please remove it");
464 0 : errorsFound = true;
465 : }
466 : }
467 :
468 : // get inlet and outlet node number from equipment list
469 1 : CurrentModuleObject = "AirLoopHVAC:OutdoorAirSystem:EquipmentList";
470 1 : int CoolingCoilOrder = 0;
471 1 : int FanOrder = 0;
472 4 : for (int CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).NumComponents; ++CompNum) {
473 3 : auto &CompType = state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).ComponentType(CompNum);
474 3 : auto &CompName = state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).ComponentName(CompNum);
475 3 : auto &thisInletNodeNum = state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).InletNodeNum(CompNum);
476 3 : auto &thisOutletNodeNum = state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).OutletNodeNum(CompNum);
477 :
478 3 : bool InletNodeErrFlag = false;
479 3 : bool OutletNodeErrFlag = false;
480 :
481 6 : auto typeNameUC = UtilityRoutines::MakeUPPERCase(state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).ComponentType(CompNum));
482 3 : auto foundType = static_cast<ValidEquipListType>(getEnumerationValue(validEquipNamesUC, typeNameUC));
483 :
484 3 : switch (foundType) {
485 0 : case ValidEquipListType::OutdoorAirMixer:
486 0 : ShowSevereError(state,
487 0 : format("When {} = {} is used in AirLoopHVAC:DedicatedOutdoorAirSystem,", CurrentModuleObject, CompName));
488 0 : ShowContinueError(state, " the OUTDOORAIR:MIXER can not be used as a component. Please remove it");
489 0 : errorsFound = true;
490 0 : break;
491 :
492 0 : case ValidEquipListType::FanConstantVolume:
493 0 : ShowSevereError(state,
494 0 : format("When {} = {} is used in AirLoopHVAC:DedicatedOutdoorAirSystem,", CurrentModuleObject, CompName));
495 0 : ShowContinueError(state,
496 : " the FAN:CONSTANTVOLUME can not be used as a component. The allowed fan types are FAN:SYSTEMMODEL and "
497 : "FAN:COMPONENTMODEL. Please change it");
498 0 : errorsFound = true;
499 0 : break;
500 :
501 0 : case ValidEquipListType::FanVariableVolume:
502 0 : ShowSevereError(state,
503 0 : format("When {} = {} is used in AirLoopHVAC:DedicatedOutdoorAirSystem,", CurrentModuleObject, CompName));
504 0 : ShowContinueError(state,
505 : " the FAN:VARIABLEVOLUME can not be used as a component. The allowed fan types are FAN:SYSTEMMODEL and "
506 : "FAN:COMPONENTMODEL. Please change it");
507 0 : errorsFound = true;
508 0 : break;
509 :
510 1 : case ValidEquipListType::FanSystemModel:
511 1 : thisDOAS.FanName = CompName;
512 1 : thisDOAS.m_FanTypeNum = SimAirServingZones::CompType::Fan_System_Object;
513 1 : thisDOAS.m_FanIndex = HVACFan::getFanObjectVectorIndex(state, CompName);
514 1 : thisInletNodeNum = state.dataHVACFan->fanObjs[thisDOAS.m_FanIndex]->inletNodeNum;
515 1 : if (thisInletNodeNum == 0) {
516 0 : InletNodeErrFlag = true;
517 : }
518 1 : thisOutletNodeNum = state.dataHVACFan->fanObjs[thisDOAS.m_FanIndex]->outletNodeNum;
519 1 : if (thisOutletNodeNum == 0) {
520 0 : OutletNodeErrFlag = true;
521 : }
522 1 : thisDOAS.m_FanInletNodeNum = thisInletNodeNum;
523 1 : thisDOAS.m_FanOutletNodeNum = thisOutletNodeNum;
524 1 : if (CompNum == 1) {
525 1 : thisDOAS.FanBeforeCoolingCoilFlag = true;
526 : }
527 1 : FanOrder = CompNum;
528 1 : break;
529 :
530 0 : case ValidEquipListType::FanComponentModel:
531 0 : thisDOAS.m_FanTypeNum = SimAirServingZones::CompType::Fan_ComponentModel;
532 0 : Fans::GetFanIndex(state, CompName, thisDOAS.m_FanIndex, errorsFound);
533 0 : thisDOAS.FanName = CompName;
534 0 : if (CompNum == 1) {
535 0 : thisDOAS.FanBeforeCoolingCoilFlag = true;
536 : }
537 0 : thisInletNodeNum = Fans::GetFanInletNode(state, typeNameUC, CompName, InletNodeErrFlag);
538 0 : thisOutletNodeNum = Fans::GetFanOutletNode(state, typeNameUC, CompName, OutletNodeErrFlag);
539 0 : thisDOAS.m_FanInletNodeNum = thisInletNodeNum;
540 0 : thisDOAS.m_FanOutletNodeNum = thisOutletNodeNum;
541 0 : FanOrder = CompNum;
542 0 : break;
543 :
544 1 : case ValidEquipListType::CoilCoolingWater:
545 1 : thisInletNodeNum = WaterCoils::GetCoilInletNode(state, typeNameUC, CompName, InletNodeErrFlag);
546 1 : thisOutletNodeNum = WaterCoils::GetCoilOutletNode(state, typeNameUC, CompName, OutletNodeErrFlag);
547 1 : thisDOAS.CWCtrlNodeNum = WaterCoils::GetCoilWaterInletNode(state, "COIL:COOLING:WATER", CompName, errorsFound);
548 1 : if (errorsFound) {
549 0 : ShowContinueError(state, format("The control node number is not found in {} = {}", CurrentModuleObject, CompName));
550 : }
551 1 : PlantUtilities::ScanPlantLoopsForObject(
552 : state, CompName, DataPlant::PlantEquipmentType::CoilWaterCooling, thisDOAS.CWPlantLoc, errorsFound, _, _, _, _, _);
553 1 : if (errorsFound) { // is this really needed here, program fatals out later on when errorsFound = true
554 0 : ShowFatalError(state, "GetAirLoopDOASInput: Program terminated for previous conditions.");
555 : }
556 1 : CoolingCoilOrder = CompNum;
557 1 : break;
558 :
559 1 : case ValidEquipListType::CoilHeatingWater:
560 1 : thisInletNodeNum = WaterCoils::GetCoilInletNode(state, typeNameUC, CompName, InletNodeErrFlag);
561 1 : thisOutletNodeNum = WaterCoils::GetCoilOutletNode(state, typeNameUC, CompName, OutletNodeErrFlag);
562 1 : thisDOAS.HWCtrlNodeNum = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating: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::CoilWaterSimpleHeating, thisDOAS.HWPlantLoc, 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 : break;
572 :
573 0 : case ValidEquipListType::CoilHeatingSteam:
574 0 : thisInletNodeNum = SteamCoils::GetCoilSteamInletNode(state, CompType, CompName, InletNodeErrFlag);
575 0 : thisOutletNodeNum = SteamCoils::GetCoilSteamOutletNode(state, CompType, CompName, OutletNodeErrFlag);
576 0 : break;
577 :
578 0 : case ValidEquipListType::CoilCoolingWaterDetailedGeometry:
579 0 : thisInletNodeNum = WaterCoils::GetCoilInletNode(state, typeNameUC, CompName, InletNodeErrFlag);
580 0 : thisOutletNodeNum = WaterCoils::GetCoilOutletNode(state, typeNameUC, CompName, OutletNodeErrFlag);
581 0 : thisDOAS.CWCtrlNodeNum =
582 0 : WaterCoils::GetCoilWaterInletNode(state, "Coil:Cooling:Water:DetailedGeometry", CompName, errorsFound);
583 0 : if (errorsFound) {
584 0 : ShowContinueError(state, format("The control node number is not found in {} = {}", CurrentModuleObject, CompName));
585 : }
586 0 : PlantUtilities::ScanPlantLoopsForObject(state,
587 : CompName,
588 : DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling,
589 : thisDOAS.CWPlantLoc,
590 : errorsFound,
591 : _,
592 : _,
593 : _,
594 : _,
595 : _);
596 0 : if (errorsFound) { // is this really needed here, program fatals out later on when errorsFound = true
597 0 : ShowFatalError(state, "GetAirLoopDOASInput: Program terminated for previous conditions.");
598 : }
599 0 : CoolingCoilOrder = CompNum;
600 0 : break;
601 :
602 0 : case ValidEquipListType::CoilHeatingElectric:
603 : case ValidEquipListType::CoilHeatingFuel:
604 0 : thisInletNodeNum = HeatingCoils::GetCoilInletNode(state, typeNameUC, CompName, InletNodeErrFlag);
605 0 : thisOutletNodeNum = HeatingCoils::GetCoilOutletNode(state, typeNameUC, CompName, OutletNodeErrFlag);
606 0 : break;
607 :
608 0 : case ValidEquipListType::CoilSystemCoolingWaterHeatExchangerAssisted:
609 0 : thisInletNodeNum = HVACHXAssistedCoolingCoil::GetCoilInletNode(state, CompType, CompName, InletNodeErrFlag);
610 0 : thisOutletNodeNum = HVACHXAssistedCoolingCoil::GetCoilOutletNode(state, CompType, CompName, OutletNodeErrFlag);
611 0 : break;
612 :
613 0 : case ValidEquipListType::CoilSystemCoolingDX:
614 : case ValidEquipListType::AirLoopHVACUnitarySystem:
615 0 : if (state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).compPointer[CompNum] == nullptr) {
616 0 : UnitarySystems::UnitarySys thisSys;
617 0 : state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).compPointer[CompNum] =
618 0 : UnitarySystems::UnitarySys::factory(state, DataHVACGlobals::UnitarySys_AnyCoilType, CompName, false, 0);
619 : }
620 0 : thisInletNodeNum = state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum)
621 0 : .compPointer[CompNum]
622 0 : ->getAirInNode(state, CompName, 0, InletNodeErrFlag);
623 0 : thisOutletNodeNum = state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum)
624 0 : .compPointer[CompNum]
625 0 : ->getAirOutNode(state, CompName, 0, OutletNodeErrFlag);
626 0 : CoolingCoilOrder = CompNum;
627 0 : break;
628 :
629 0 : case ValidEquipListType::CoilSystemHeatingDX:
630 0 : thisInletNodeNum = HVACDXHeatPumpSystem::GetHeatingCoilInletNodeNum(state, CompName, InletNodeErrFlag);
631 0 : thisOutletNodeNum = HVACDXHeatPumpSystem::GetHeatingCoilOutletNodeNum(state, CompName, OutletNodeErrFlag);
632 0 : break;
633 :
634 0 : case ValidEquipListType::CoilUserDefined:
635 0 : ShowSevereError(state,
636 0 : format("When {} = {} is used in AirLoopHVAC:DedicatedOutdoorAirSystem,", CurrentModuleObject, CompName));
637 0 : ShowContinueError(state, " the COIL:USERDEFINED can not be used as a component.");
638 0 : errorsFound = true;
639 0 : break;
640 :
641 0 : case ValidEquipListType::HeatExchangerAirToAirFlatPlate:
642 : case ValidEquipListType::HeatExchangerAirToAirSensibleAndLatent:
643 : case ValidEquipListType::HeatExchangerDesiccantBalancedFlow:
644 0 : state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).HeatExchangerFlag = true;
645 0 : thisInletNodeNum = HeatRecovery::GetSupplyInletNode(state, CompName, InletNodeErrFlag);
646 0 : thisOutletNodeNum = HeatRecovery::GetSupplyOutletNode(state, CompName, OutletNodeErrFlag);
647 0 : break;
648 :
649 0 : case ValidEquipListType::DehumidifierDesiccantNoFans:
650 : case ValidEquipListType::DehumidifierDesiccantSystem:
651 0 : thisInletNodeNum = DesiccantDehumidifiers::GetProcAirInletNodeNum(state, CompName, InletNodeErrFlag);
652 0 : thisOutletNodeNum = DesiccantDehumidifiers::GetProcAirOutletNodeNum(state, CompName, OutletNodeErrFlag);
653 0 : break;
654 :
655 0 : case ValidEquipListType::HumidifierSteamElectric:
656 : case ValidEquipListType::HumidifierSteamGas:
657 0 : thisInletNodeNum = Humidifiers::GetAirInletNodeNum(state, CompName, InletNodeErrFlag);
658 0 : thisOutletNodeNum = Humidifiers::GetAirOutletNodeNum(state, CompName, OutletNodeErrFlag);
659 0 : break;
660 :
661 0 : case ValidEquipListType::SolarCollectorUnglazedTranspired:
662 0 : thisInletNodeNum = TranspiredCollector::GetAirInletNodeNum(state, CompName, InletNodeErrFlag);
663 0 : thisOutletNodeNum = TranspiredCollector::GetAirOutletNodeNum(state, CompName, OutletNodeErrFlag);
664 0 : break;
665 :
666 0 : case ValidEquipListType::SolarCollectorFlatPlatePhotovoltaicThermal:
667 0 : thisInletNodeNum = PhotovoltaicThermalCollectors::GetAirInletNodeNum(state, CompName, InletNodeErrFlag);
668 0 : thisOutletNodeNum = PhotovoltaicThermalCollectors::GetAirOutletNodeNum(state, CompName, OutletNodeErrFlag);
669 0 : break;
670 :
671 0 : case ValidEquipListType::EvaporativeCoolerDirectCeldekPad:
672 : case ValidEquipListType::EvaporativeCoolerIndirectCeldekPad:
673 : case ValidEquipListType::EvaporativeCoolerIndirectWetCoil:
674 : case ValidEquipListType::EvaporativeCoolerIndirectResearchSpecial:
675 : case ValidEquipListType::EvaporativeCoolerDirectResearchSpecial:
676 0 : thisInletNodeNum = EvaporativeCoolers::GetInletNodeNum(state, CompName, InletNodeErrFlag);
677 0 : thisOutletNodeNum = EvaporativeCoolers::GetOutletNodeNum(state, CompName, OutletNodeErrFlag);
678 0 : break;
679 :
680 0 : case ValidEquipListType::ZoneHVACTerminalUnitVariableRefrigerantFlow:
681 0 : thisInletNodeNum = HVACVariableRefrigerantFlow::GetVRFTUInAirNodeFromName(state, CompName, InletNodeErrFlag);
682 0 : thisOutletNodeNum = HVACVariableRefrigerantFlow::GetVRFTUOutAirNodeFromName(state, CompName, OutletNodeErrFlag);
683 0 : break;
684 :
685 0 : default:
686 0 : ShowSevereError(state,
687 0 : format(R"({} = "{}" invalid Outside Air Component="{}".)",
688 : CurrentModuleObject,
689 : CompName,
690 0 : state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).ComponentType(CompNum)));
691 0 : errorsFound = true;
692 : }
693 3 : if (CoolingCoilOrder > FanOrder && !thisDOAS.FanBeforeCoolingCoilFlag) {
694 0 : thisDOAS.FanBeforeCoolingCoilFlag = true;
695 : }
696 3 : if (InletNodeErrFlag) {
697 0 : ShowSevereError(state, "Inlet node number is not found in " + CurrentModuleObject + " = " + std::string{CompName});
698 0 : errorsFound = true;
699 : }
700 3 : if (OutletNodeErrFlag) {
701 0 : ShowSevereError(state, "Outlet node number is not found in " + CurrentModuleObject + " = " + std::string{CompName});
702 0 : errorsFound = true;
703 : }
704 : }
705 :
706 1 : thisDOAS.m_InletNodeNum = state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).InletNodeNum(1);
707 2 : thisDOAS.m_OutletNodeNum = state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum)
708 1 : .OutletNodeNum(state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).NumComponents);
709 1 : state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).AirLoopDOASNum = AirLoopDOASNum - 1;
710 : // Set up parent-child connection
711 3 : BranchNodeConnections::SetUpCompSets(state,
712 : cCurrentModuleObject,
713 : thisDOAS.Name,
714 : "AIRLOOPHVAC:OUTDOORAIRSYSTEM",
715 : thisDOAS.OASystemName,
716 1 : state.dataLoopNodes->NodeID(thisDOAS.m_InletNodeNum),
717 2 : state.dataLoopNodes->NodeID(thisDOAS.m_OutletNodeNum));
718 :
719 1 : if (state.dataAirLoop->OutsideAirSys(thisDOAS.m_OASystemNum).HeatExchangerFlag) {
720 0 : thisDOAS.m_HeatExchangerFlag = true;
721 : }
722 :
723 1 : thisDOAS.AvailManagerSchedName = UtilityRoutines::MakeUPPERCase(fields.at("availability_schedule_name").get<std::string>());
724 1 : thisDOAS.m_AvailManagerSchedPtr = GetScheduleIndex(state, thisDOAS.AvailManagerSchedName);
725 1 : if (thisDOAS.m_AvailManagerSchedPtr == 0) {
726 0 : cFieldName = "Availability Schedule Name";
727 0 : ShowSevereError(
728 : state,
729 0 : format("{}, \"{}\" {} not found: {}", cCurrentModuleObject, thisDOAS.Name, cFieldName, thisDOAS.AvailManagerSchedName));
730 0 : errorsFound = true;
731 : }
732 :
733 1 : thisDOAS.AirLoopMixerName = UtilityRoutines::MakeUPPERCase(fields.at("airloophvac_mixer_name").get<std::string>()); //
734 1 : thisDOAS.m_AirLoopMixerIndex = getAirLoopMixerIndex(state, thisDOAS.AirLoopMixerName);
735 1 : if (thisDOAS.m_AirLoopMixerIndex < 0) {
736 0 : cFieldName = "AirLoopHVAC:Mixer Name";
737 0 : ShowSevereError(state,
738 0 : cCurrentModuleObject + ", \"" + thisDOAS.Name + "\" " + cFieldName + " not found: " + thisDOAS.AirLoopMixerName);
739 0 : errorsFound = true;
740 : }
741 2 : AirLoopMixer thisAirLoopMixer;
742 1 : thisDOAS.m_CompPointerAirLoopMixer = thisAirLoopMixer.factory(state, thisDOAS.m_AirLoopMixerIndex, thisDOAS.AirLoopMixerName);
743 1 : thisDOAS.AirLoopSplitterName = UtilityRoutines::MakeUPPERCase(fields.at("airloophvac_splitter_name").get<std::string>()); //
744 1 : thisDOAS.m_AirLoopSplitterIndex = getAirLoopSplitterIndex(state, thisDOAS.AirLoopSplitterName);
745 1 : if (thisDOAS.m_AirLoopSplitterIndex < 0) {
746 0 : cFieldName = "AirLoopHVAC:Splitter Name";
747 0 : ShowSevereError(
748 0 : state, cCurrentModuleObject + ", \"" + thisDOAS.Name + "\" " + cFieldName + " not found: " + thisDOAS.AirLoopSplitterName);
749 0 : errorsFound = true;
750 : }
751 2 : AirLoopSplitter thisAirLoopSplitter;
752 1 : thisDOAS.m_CompPointerAirLoopSplitter =
753 1 : thisAirLoopSplitter.factory(state, thisDOAS.m_AirLoopSplitterIndex, thisDOAS.AirLoopSplitterName);
754 :
755 : // get pretreated desing conditions
756 1 : thisDOAS.PreheatTemp = fields.at("preheat_design_temperature").get<Real64>();
757 1 : thisDOAS.PreheatHumRat = fields.at("preheat_design_humidity_ratio").get<Real64>();
758 1 : thisDOAS.PrecoolTemp = fields.at("precool_design_temperature").get<Real64>();
759 1 : thisDOAS.PrecoolHumRat = fields.at("precool_design_humidity_ratio").get<Real64>();
760 :
761 : // get info on AirLoops
762 1 : thisDOAS.NumOfAirLoops = fields.at("number_of_airloophvac").get<int>(); //
763 1 : if (thisDOAS.NumOfAirLoops < 1) {
764 0 : cFieldName = "Number of AirLoopHVAC";
765 0 : ShowSevereError(state,
766 0 : fmt::format("{}, \"{}\" {} = {}", cCurrentModuleObject, thisDOAS.Name, cFieldName, thisDOAS.NumOfAirLoops));
767 0 : ShowContinueError(state, " The minimum value should be 1.");
768 0 : errorsFound = true;
769 : }
770 :
771 2 : auto AirLoopNames = fields.find("airloophvacs");
772 1 : if (AirLoopNames != fields.end()) {
773 2 : auto AirLoopArray = AirLoopNames.value();
774 1 : int num = 0;
775 6 : for (auto AirLoopHVACName : AirLoopArray) {
776 10 : std::string name = UtilityRoutines::MakeUPPERCase(AirLoopHVACName.at("airloophvac_name").get<std::string>());
777 5 : int LoopNum = UtilityRoutines::FindItemInList(name, state.dataAirSystemsData->PrimaryAirSystems);
778 5 : num += 1;
779 5 : if (LoopNum > 0 && num <= thisDOAS.NumOfAirLoops) {
780 5 : thisDOAS.AirLoopName.push_back(name);
781 5 : thisDOAS.m_AirLoopNum.push_back(LoopNum);
782 : } else {
783 0 : cFieldName = "AirLoopHVAC Name";
784 0 : ShowSevereError(state, cCurrentModuleObject + ", \"" + thisDOAS.Name + "\" " + cFieldName + " not found: " + name);
785 0 : errorsFound = true;
786 : }
787 : }
788 : }
789 :
790 1 : thisDOAS.m_AirLoopDOASNum = AirLoopDOASNum - 1;
791 1 : state.dataAirLoopHVACDOAS->airloopDOAS.push_back(thisDOAS);
792 : }
793 :
794 : // Check valid OA controller
795 7 : for (int OASysNum = 1; OASysNum <= state.dataAirLoop->NumOASystems; OASysNum++) {
796 6 : if (UtilityRoutines::SameString(state.dataAirLoop->OutsideAirSys(OASysNum).ControllerListName, "")) {
797 0 : if (state.dataAirLoop->OutsideAirSys(OASysNum).AirLoopDOASNum == -1) {
798 0 : ShowSevereError(state,
799 0 : "AirLoopHVAC:OutdoorAirSystem = \"" + state.dataAirLoop->OutsideAirSys(OASysNum).Name +
800 : "\" invalid Controller List Name = \" not found.");
801 0 : errorsFound = true;
802 : }
803 : }
804 : }
805 1 : if (errorsFound) {
806 0 : ShowFatalError(state, "getAirLoopHVACDOAS: Previous errors cause termination.");
807 : }
808 : }
809 1 : }
810 :
811 10882 : void AirLoopDOAS::initAirLoopDOAS(EnergyPlusData &state, bool const FirstHVACIteration)
812 : {
813 : int LoopOA;
814 : int NodeNum;
815 : Real64 SchAvailValue;
816 : static constexpr std::string_view RoutineName = "AirLoopDOAS::initAirLoopDOAS";
817 10882 : bool ErrorsFound = false;
818 :
819 10882 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
820 : Real64 rho;
821 5 : state.dataSize->CurSysNum = this->m_OASystemNum;
822 20 : for (int CompNum = 1; CompNum <= state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).NumComponents; ++CompNum) {
823 30 : std::string CompType = state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).ComponentType(CompNum);
824 30 : std::string CompName = state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).ComponentName(CompNum);
825 15 : if (UtilityRoutines::SameString(CompType, "FAN:SYSTEMMODEL")) {
826 5 : state.dataHVACFan->fanObjs[this->m_FanIndex]->simulate(state);
827 : }
828 15 : if (UtilityRoutines::SameString(CompType, "FAN:COMPONENTMODEL")) {
829 0 : Fans::SimulateFanComponents(state, CompName, FirstHVACIteration, this->m_FanIndex);
830 : }
831 :
832 15 : if (UtilityRoutines::SameString(CompType, "COIL:HEATING:WATER")) {
833 5 : WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, this->m_HeatCoilNum);
834 5 : Real64 CoilMaxVolFlowRate = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", CompName, ErrorsFound);
835 10 : rho = FluidProperties::GetDensityGlycol(state,
836 5 : state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).FluidName,
837 : DataGlobalConstants::HWInitConvTemp,
838 5 : state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).FluidIndex,
839 : RoutineName);
840 5 : PlantUtilities::InitComponentNodes(state,
841 : 0.0,
842 : CoilMaxVolFlowRate * rho,
843 : this->HWCtrlNodeNum,
844 5 : state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).OutletNodeNum(CompNum));
845 : }
846 15 : if (UtilityRoutines::SameString(CompType, "COIL:COOLING:WATER")) {
847 5 : WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, this->m_CoolCoilNum);
848 5 : Real64 CoilMaxVolFlowRate = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Cooling:Water", CompName, ErrorsFound);
849 10 : rho = FluidProperties::GetDensityGlycol(state,
850 5 : state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
851 : DataGlobalConstants::CWInitConvTemp,
852 5 : state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
853 : RoutineName);
854 5 : PlantUtilities::InitComponentNodes(state,
855 : 0.0,
856 : CoilMaxVolFlowRate * rho,
857 : this->CWCtrlNodeNum,
858 5 : state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).OutletNodeNum(CompNum));
859 : }
860 15 : if (UtilityRoutines::SameString(CompType, "COIL:COOLING:WATER:DETAILEDGEOMETRY")) {
861 0 : WaterCoils::SimulateWaterCoilComponents(state, CompName, FirstHVACIteration, this->m_CoolCoilNum);
862 : Real64 CoilMaxVolFlowRate =
863 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Cooling:Water:DetailedGeometry", CompName, ErrorsFound);
864 0 : rho = FluidProperties::GetDensityGlycol(state,
865 0 : state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
866 : DataGlobalConstants::CWInitConvTemp,
867 0 : state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
868 : RoutineName);
869 0 : PlantUtilities::InitComponentNodes(state,
870 : 0.0,
871 : CoilMaxVolFlowRate * rho,
872 : this->CWCtrlNodeNum,
873 0 : state.dataAirLoop->OutsideAirSys(this->m_OASystemNum).OutletNodeNum(CompNum));
874 : }
875 : }
876 :
877 5 : this->MyEnvrnFlag = false;
878 5 : if (ErrorsFound) {
879 0 : ShowFatalError(state, "initAirLoopDOAS: Previous errors cause termination.");
880 : }
881 : }
882 :
883 10882 : if (!state.dataGlobal->BeginEnvrnFlag) {
884 10832 : this->MyEnvrnFlag = true;
885 : }
886 :
887 10882 : this->SumMassFlowRate = 0.0;
888 :
889 65292 : for (LoopOA = 0; LoopOA < this->m_CompPointerAirLoopSplitter->numOfOutletNodes; LoopOA++) {
890 54410 : NodeNum = this->m_CompPointerAirLoopSplitter->OutletNodeNum[LoopOA];
891 54410 : this->SumMassFlowRate += state.dataLoopNodes->Node(NodeNum).MassFlowRate;
892 : }
893 :
894 10882 : SchAvailValue = ScheduleManager::GetCurrentScheduleValue(state, this->m_AvailManagerSchedPtr);
895 10882 : if (SchAvailValue < 1.0) {
896 0 : this->SumMassFlowRate = 0.0;
897 : }
898 10882 : state.dataLoopNodes->Node(this->m_InletNodeNum).MassFlowRate = this->SumMassFlowRate;
899 10882 : }
900 :
901 10882 : void AirLoopDOAS::CalcAirLoopDOAS(EnergyPlusData &state, bool const FirstHVACIteration)
902 : {
903 : using MixedAir::ManageOutsideAirSystem;
904 :
905 10882 : this->m_CompPointerAirLoopMixer->CalcAirLoopMixer(state);
906 10882 : if (this->m_FanIndex > -1) {
907 10882 : state.dataLoopNodes->Node(this->m_FanInletNodeNum).MassFlowRateMaxAvail = this->SumMassFlowRate;
908 10882 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMaxAvail = this->SumMassFlowRate;
909 10882 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMax = this->SumMassFlowRate;
910 : }
911 10882 : ManageOutsideAirSystem(state, this->OASystemName, FirstHVACIteration, 0, this->m_OASystemNum);
912 10882 : Real64 Temp = state.dataLoopNodes->Node(this->m_OutletNodeNum).Temp;
913 10882 : Real64 HumRat = state.dataLoopNodes->Node(this->m_OutletNodeNum).HumRat;
914 10882 : state.dataLoopNodes->Node(this->m_OutletNodeNum).Enthalpy = Psychrometrics::PsyHFnTdbW(Temp, HumRat);
915 :
916 10882 : this->m_CompPointerAirLoopSplitter->CalcAirLoopSplitter(state, Temp, HumRat);
917 10882 : }
918 :
919 1 : void AirLoopDOAS::SizingAirLoopDOAS(EnergyPlusData &state)
920 : {
921 1 : Real64 sizingMassFlow = 0;
922 : int AirLoopNum;
923 :
924 6 : for (int AirLoop = 1; AirLoop <= this->NumOfAirLoops; AirLoop++) {
925 5 : AirLoopNum = this->m_AirLoopNum[AirLoop - 1];
926 5 : this->m_OACtrlNum.push_back(state.dataAirLoop->AirLoopControlInfo(AirLoopNum).OACtrlNum);
927 :
928 5 : if (this->m_OACtrlNum[AirLoop - 1] > 0) {
929 5 : sizingMassFlow += state.dataMixedAir->OAController(this->m_OACtrlNum[AirLoop - 1]).MaxOA;
930 : }
931 : }
932 1 : this->SizingMassFlow = sizingMassFlow;
933 1 : this->GetDesignDayConditions(state);
934 :
935 1 : if (this->m_FanIndex > -1 && this->m_FanTypeNum == SimAirServingZones::CompType::Fan_System_Object) {
936 1 : state.dataHVACFan->fanObjs[this->m_FanIndex]->designAirVolFlowRate = sizingMassFlow / state.dataEnvrn->StdRhoAir;
937 1 : state.dataLoopNodes->Node(this->m_FanInletNodeNum).MassFlowRateMaxAvail = sizingMassFlow;
938 1 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMaxAvail = sizingMassFlow;
939 1 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMax = sizingMassFlow;
940 : }
941 1 : bool errorsFound = false;
942 1 : if (this->m_FanIndex > 0 && this->m_FanTypeNum == SimAirServingZones::CompType::Fan_ComponentModel) {
943 0 : Fans::SetFanData(state, this->m_FanIndex, errorsFound, Name, sizingMassFlow / state.dataEnvrn->StdRhoAir, 0);
944 0 : state.dataFans->Fan(this->m_FanIndex).MaxAirMassFlowRate = sizingMassFlow;
945 0 : state.dataLoopNodes->Node(this->m_FanInletNodeNum).MassFlowRateMaxAvail = sizingMassFlow;
946 0 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMaxAvail = sizingMassFlow;
947 0 : state.dataLoopNodes->Node(this->m_FanOutletNodeNum).MassFlowRateMax = sizingMassFlow;
948 : }
949 1 : if (errorsFound) {
950 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
951 : }
952 1 : state.dataSize->CurSysNum = state.dataHVACGlobal->NumPrimaryAirSys + this->m_AirLoopDOASNum + 1;
953 1 : state.dataSize->CurOASysNum = this->m_OASystemNum;
954 1 : }
955 :
956 1 : void getAirLoopHVACDOASInput(EnergyPlusData &state)
957 : {
958 1 : if (state.dataAirLoopHVACDOAS->GetInputOnceFlag) {
959 1 : AirLoopDOAS::getAirLoopDOASInput(state);
960 1 : state.dataAirLoopHVACDOAS->GetInputOnceFlag = false;
961 : }
962 1 : }
963 :
964 1 : void AirLoopDOAS::GetDesignDayConditions(EnergyPlusData &state)
965 : {
966 4 : for (auto &env : state.dataWeatherManager->Environment) {
967 3 : if (env.KindOfEnvrn != DataGlobalConstants::KindOfSim::DesignDay && env.KindOfEnvrn != DataGlobalConstants::KindOfSim::RunPeriodDesign)
968 1 : continue;
969 2 : if (env.maxCoolingOATSizing > this->SizingCoolOATemp) {
970 2 : this->SizingCoolOATemp = env.maxCoolingOATSizing;
971 : // DesignDayNum = 0 for KindOfSim == RunPeriodDesign
972 4 : if (env.KindOfEnvrn == DataGlobalConstants::KindOfSim::DesignDay &&
973 2 : state.dataWeatherManager->DesDayInput(env.DesignDayNum).PressureEntered) {
974 2 : this->SizingCoolOAHumRat = Psychrometrics::PsyWFnTdpPb(
975 2 : state, env.maxCoolingOADPSizing, state.dataWeatherManager->DesDayInput(env.DesignDayNum).PressBarom);
976 : } else {
977 0 : this->SizingCoolOAHumRat = Psychrometrics::PsyWFnTdpPb(state, env.maxCoolingOADPSizing, state.dataEnvrn->StdBaroPress);
978 : }
979 : }
980 2 : if (env.minHeatingOATSizing < this->HeatOutTemp) {
981 1 : this->HeatOutTemp = env.minHeatingOATSizing;
982 2 : if (env.KindOfEnvrn == DataGlobalConstants::KindOfSim::DesignDay &&
983 1 : state.dataWeatherManager->DesDayInput(env.DesignDayNum).PressureEntered) {
984 1 : this->HeatOutHumRat = Psychrometrics::PsyWFnTdpPb(
985 1 : state, env.minHeatingOADPSizing, state.dataWeatherManager->DesDayInput(env.DesignDayNum).PressBarom);
986 : } else {
987 0 : this->HeatOutHumRat = Psychrometrics::PsyWFnTdpPb(state, env.minHeatingOADPSizing, state.dataEnvrn->StdBaroPress);
988 : }
989 : }
990 : }
991 1 : }
992 :
993 5358 : void CheckConvergence(EnergyPlusData &state)
994 : {
995 :
996 : Real64 maxDiff;
997 : Real64 Diff;
998 : Real64 OldTemp;
999 10716 : for (auto &loop : state.dataAirLoopHVACDOAS->airloopDOAS) {
1000 5358 : maxDiff = 0.0;
1001 10716 : Diff = std::abs(loop.m_CompPointerAirLoopSplitter->InletTemp -
1002 5358 : state.dataLoopNodes->Node(loop.m_CompPointerAirLoopSplitter->OutletNodeNum[0]).Temp);
1003 5358 : if (Diff > maxDiff) {
1004 0 : maxDiff = Diff;
1005 : }
1006 5358 : if (loop.m_HeatExchangerFlag) {
1007 0 : OldTemp = loop.m_CompPointerAirLoopMixer->OutletTemp;
1008 0 : loop.m_CompPointerAirLoopMixer->CalcAirLoopMixer(state);
1009 0 : Diff = std::abs(OldTemp - loop.m_CompPointerAirLoopMixer->OutletTemp);
1010 0 : if (Diff > maxDiff) {
1011 0 : maxDiff = Diff;
1012 : }
1013 : }
1014 5358 : if (maxDiff > 1.0e-6) {
1015 0 : if (loop.ConveCount == 0) {
1016 0 : ++loop.ConveCount;
1017 0 : ShowWarningError(state, "Convergence limit is above 1.0e-6 for unit=" + loop.Name);
1018 0 : ShowContinueErrorTimeStamp(
1019 0 : state, format("The max difference of node temperatures between AirLoopDOAS outlet and OA mixer inlet ={:.6R}", maxDiff));
1020 : } else {
1021 0 : ++loop.ConveCount;
1022 0 : ShowRecurringWarningErrorAtEnd(state,
1023 0 : loop.Name + "\": The max difference of node temperatures exceeding 1.0e-6 continues...",
1024 : loop.ConveIndex,
1025 : maxDiff,
1026 : maxDiff);
1027 : }
1028 : }
1029 : }
1030 5358 : }
1031 :
1032 : } // namespace AirLoopHVACDOAS
1033 2313 : } // namespace EnergyPlus
|