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 <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Fmath.hh>
53 :
54 : // EnergyPlus Headers
55 : #include <EnergyPlus/Autosizing/All_Simple_Sizing.hh>
56 : #include <EnergyPlus/Autosizing/SystemAirFlowSizing.hh>
57 : #include <EnergyPlus/BranchNodeConnections.hh>
58 : #include <EnergyPlus/Coils/CoilCoolingDX.hh>
59 : #include <EnergyPlus/DXCoils.hh>
60 : #include <EnergyPlus/Data/EnergyPlusData.hh>
61 : #include <EnergyPlus/DataContaminantBalance.hh>
62 : #include <EnergyPlus/DataHVACGlobals.hh>
63 : #include <EnergyPlus/DataIPShortCuts.hh>
64 : #include <EnergyPlus/DataLoopNode.hh>
65 : #include <EnergyPlus/DataSizing.hh>
66 : #include <EnergyPlus/EMSManager.hh>
67 : #include <EnergyPlus/General.hh>
68 : #include <EnergyPlus/GeneralRoutines.hh>
69 : #include <EnergyPlus/GlobalNames.hh>
70 : #include <EnergyPlus/HeatRecovery.hh>
71 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
72 : #include <EnergyPlus/NodeInputManager.hh>
73 : #include <EnergyPlus/OutputProcessor.hh>
74 : #include <EnergyPlus/Psychrometrics.hh>
75 : #include <EnergyPlus/ScheduleManager.hh>
76 : #include <EnergyPlus/UtilityRoutines.hh>
77 : #include <EnergyPlus/VariableSpeedCoils.hh>
78 :
79 : namespace EnergyPlus {
80 :
81 : namespace HeatRecovery {
82 :
83 : // Module containing the routines dealing with heat recovery from exhaust or relief air
84 :
85 : // MODULE INFORMATION:
86 : // AUTHOR Michael Wetter
87 : // DATE WRITTEN March 1999
88 : // MODIFIED F Buhl Nov 2000, D Shirey Feb 2003, R. Raustad April 2003
89 : // RE-ENGINEERED na
90 :
91 : // PURPOSE OF THIS MODULE:
92 : // To encapsulate the data and routines required to model heat
93 : // recovery components in the EnergyPlus HVAC simulation
94 :
95 : // METHODOLOGY EMPLOYED:
96 : // Heat exchanger effectiveness - NTU models are used.
97 :
98 : // REFERENCES:
99 : // M. Wetter, Simulation Model Air-to-Air Plate Heat Exchanger,LBNL Report 42354, 1999.
100 : // ARI Standard 1060-2001,Rating Air-to-Air Heat Exchangers for Energy Recovery Ventilation Equipment, www.ari.org
101 : // ASHRAE Standard 84, Method of Testing Air-To-Air Heat Exchangers, www.ashrae.org
102 : // U.S. Environmental Protection Agency software "SAVES" -
103 : // School Advanced Ventilation Engineering Software http://www.epa.gov/iaq/schooldesign/saves.html
104 :
105 : Real64 constexpr KELVZERO = 273.16;
106 : Real64 constexpr SMALL = 1.e-10;
107 : constexpr std::array<std::string_view, static_cast<int>(FrostControlOption::Num)> frostControlNamesUC = {
108 : "NONE", "EXHAUSTONLY", "EXHAUSTAIRRECIRCULATION", "MINIMUMEXHAUSTTEMPERATURE"};
109 :
110 3964330 : void SimHeatRecovery(EnergyPlusData &state,
111 : std::string_view CompName, // name of the heat exchanger unit
112 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
113 : int &CompIndex, // Pointer to Component
114 : int const FanOpMode, // Supply air fan operating mode
115 : Optional<Real64 const> HXPartLoadRatio, // Part load ratio requested of DX compressor
116 : Optional_bool_const HXUnitEnable, // Flag to operate heat exchanger
117 : Optional_int_const CompanionCoilIndex, // index of companion cooling coil
118 : Optional_bool_const RegenInletIsOANode, // flag to determine if supply inlet is OA node, if so air flow cycles
119 : Optional_bool_const EconomizerFlag, // economizer operation flag passed by airloop or OA sys
120 : Optional_bool_const HighHumCtrlFlag, // high humidity control flag passed by airloop or OA sys
121 : Optional_int_const CompanionCoilType_Num // cooling coil type of coil
122 : )
123 : {
124 :
125 : // SUBROUTINE INFORMATION:
126 : // AUTHOR Michael Wetter
127 : // DATE WRITTEN March 1999
128 : // MODIFIED Fred Buhl November 2000, R. Raustad FSEC - Feb 2009
129 : // RE-ENGINEERED na
130 :
131 : // PURPOSE OF THIS SUBROUTINE:
132 : // Manage the simulation of a heat recovery unit
133 :
134 3964330 : if (state.dataHeatRecovery->GetInputFlag) {
135 24 : GetHeatRecoveryInput(state);
136 24 : state.dataHeatRecovery->GetInputFlag = false;
137 : }
138 :
139 : // Find the correct unit index
140 : int HeatExchNum; // index of unit being simulated
141 3964330 : if (CompIndex == 0) {
142 158 : HeatExchNum = UtilityRoutines::FindItemInList(CompName, state.dataHeatRecovery->ExchCond);
143 158 : if (HeatExchNum == 0) {
144 0 : ShowFatalError(state, format("SimHeatRecovery: Unit not found={}", CompName));
145 : }
146 158 : CompIndex = HeatExchNum;
147 : } else {
148 3964172 : HeatExchNum = CompIndex;
149 3964172 : if (HeatExchNum > state.dataHeatRecovery->NumHeatExchangers || HeatExchNum < 1) {
150 0 : ShowFatalError(state,
151 0 : format("SimHeatRecovery: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
152 : HeatExchNum,
153 0 : state.dataHeatRecovery->NumHeatExchangers,
154 0 : CompName));
155 : }
156 3964172 : if (state.dataHeatRecovery->CheckEquipName(HeatExchNum)) {
157 158 : if (CompName != state.dataHeatRecovery->ExchCond(HeatExchNum).Name) {
158 0 : ShowFatalError(state,
159 0 : format("SimHeatRecovery: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
160 : HeatExchNum,
161 : CompName,
162 0 : state.dataHeatRecovery->ExchCond(HeatExchNum).Name));
163 : }
164 158 : state.dataHeatRecovery->CheckEquipName(HeatExchNum) = false;
165 : }
166 : }
167 :
168 3964330 : int CompanionCoilNum = present(CompanionCoilIndex) ? int(CompanionCoilIndex) : 0; // Index to companion cooling coil
169 3964330 : int companionCoilType = present(CompanionCoilType_Num) ? int(CompanionCoilType_Num) : 0;
170 :
171 : bool HXUnitOn; // flag to enable heat exchanger
172 3964330 : if (present(HXUnitEnable)) {
173 2142262 : HXUnitOn = HXUnitEnable;
174 : // When state.dataHeatRecovery->CalledFromParentObject is TRUE, this SIM routine was called by a parent object that passed in
175 : // HXUnitEnable. HX will use the DX coil part-load ratio (optional CompanionCoilIndex must be present) or PLR passed in if not used with
176 : // DX coil (optional CompanionCoilIndex must not be present).
177 2142262 : state.dataHeatRecovery->CalledFromParentObject = true;
178 : } else {
179 : // HX is placed on a BRANCH, optional arguments are not passed in from SimAirServingZones.
180 : // HX will calculate its own part-load ratio if optional HXUnitEnable flag is not present
181 1822068 : HXUnitOn = true;
182 1822068 : state.dataHeatRecovery->CalledFromParentObject = false;
183 : }
184 :
185 3964330 : auto &thisExch = state.dataHeatRecovery->ExchCond(HeatExchNum);
186 :
187 3964330 : thisExch.initialize(state, CompanionCoilNum, companionCoilType);
188 :
189 : // call the correct heat exchanger calculation routine
190 3964330 : switch (state.dataHeatRecovery->ExchCond(HeatExchNum).ExchType) {
191 758449 : case DataHVACGlobals::HX_AIRTOAIR_FLATPLATE:
192 758449 : thisExch.CalcAirToAirPlateHeatExch(state, HXUnitOn, EconomizerFlag, HighHumCtrlFlag);
193 758449 : break;
194 :
195 2533886 : case DataHVACGlobals::HX_AIRTOAIR_GENERIC:
196 2533886 : thisExch.CalcAirToAirGenericHeatExch(state, HXUnitOn, FirstHVACIteration, FanOpMode, EconomizerFlag, HighHumCtrlFlag, HXPartLoadRatio);
197 2533886 : break;
198 :
199 671995 : case DataHVACGlobals::HX_DESICCANT_BALANCED:
200 671995 : Real64 PartLoadRatio = present(HXPartLoadRatio) ? Real64(HXPartLoadRatio) : 1.0; // Part load ratio requested of DX compressor
201 671995 : bool RegInIsOANode = present(RegenInletIsOANode) && bool(RegenInletIsOANode);
202 671995 : thisExch.CalcDesiccantBalancedHeatExch(
203 : state, HXUnitOn, FirstHVACIteration, FanOpMode, PartLoadRatio, CompanionCoilNum, RegInIsOANode, EconomizerFlag, HighHumCtrlFlag);
204 671995 : break;
205 : }
206 :
207 3964330 : thisExch.UpdateHeatRecovery(state);
208 :
209 3964330 : thisExch.ReportHeatRecovery(state);
210 3964330 : }
211 :
212 41 : void GetHeatRecoveryInput(EnergyPlusData &state)
213 : {
214 :
215 : // SUBROUTINE INFORMATION:
216 : // AUTHOR Michael Wetter
217 : // DATE WRITTEN March 1999
218 : // MODIFIED F Buhl Nov 2000, D Shirey Feb 2003, R. Raustad FSEC - Feb 2009 (EconoLockout inputs)
219 : // RE-ENGINEERED na
220 :
221 : // PURPOSE OF THIS SUBROUTINE:
222 : // Obtains input data for heat recovery units and stores it in
223 : // appropriate data structures.
224 :
225 : // METHODOLOGY EMPLOYED:
226 : // Uses InputProcessor "Get" routines to obtain data.
227 :
228 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
229 : int NumAlphas; // Number of Alphas for each GetObjectItem call
230 : int NumNumbers; // Number of Numbers for each GetObjectItem call
231 : int IOStatus; // Used in GetObjectItem
232 41 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
233 41 : constexpr const char *RoutineName("GetHeatRecoveryInput: "); // include trailing blank space
234 41 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
235 :
236 41 : int NumAirToAirPlateExchs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "HeatExchanger:AirToAir:FlatPlate");
237 : int NumAirToAirGenericExchs =
238 41 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "HeatExchanger:AirToAir:SensibleAndLatent");
239 41 : int NumDesiccantBalancedExchs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "HeatExchanger:Desiccant:BalancedFlow");
240 : int NumDesBalExchsPerfDataType1 =
241 41 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "HeatExchanger:Desiccant:BalancedFlow:PerformanceDataType1");
242 41 : state.dataHeatRecovery->NumHeatExchangers = NumAirToAirPlateExchs + NumAirToAirGenericExchs + NumDesiccantBalancedExchs;
243 :
244 : // allocate the data array
245 41 : state.dataHeatRecovery->ExchCond.allocate(state.dataHeatRecovery->NumHeatExchangers);
246 41 : state.dataHeatRecovery->HeatExchangerUniqueNames.reserve(state.dataHeatRecovery->NumHeatExchangers);
247 41 : state.dataHeatRecovery->CheckEquipName.dimension(state.dataHeatRecovery->NumHeatExchangers, true);
248 :
249 41 : if (NumDesBalExchsPerfDataType1 > 0) {
250 5 : state.dataHeatRecovery->BalDesDehumPerfData.allocate(NumDesBalExchsPerfDataType1);
251 : }
252 :
253 : // loop over the air to air plate heat exchangers and load their input data
254 55 : for (int ExchIndex = 1; ExchIndex <= NumAirToAirPlateExchs; ++ExchIndex) {
255 14 : cCurrentModuleObject = "HeatExchanger:AirToAir:FlatPlate";
256 98 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
257 : cCurrentModuleObject,
258 : ExchIndex,
259 14 : state.dataIPShortCut->cAlphaArgs,
260 : NumAlphas,
261 14 : state.dataIPShortCut->rNumericArgs,
262 : NumNumbers,
263 : IOStatus,
264 14 : state.dataIPShortCut->lNumericFieldBlanks,
265 14 : state.dataIPShortCut->lAlphaFieldBlanks,
266 14 : state.dataIPShortCut->cAlphaFieldNames,
267 14 : state.dataIPShortCut->cNumericFieldNames);
268 14 : int const ExchNum = ExchIndex;
269 14 : auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
270 14 : thisExchanger.NumericFieldNames.allocate(NumNumbers);
271 14 : thisExchanger.NumericFieldNames = "";
272 14 : thisExchanger.NumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
273 :
274 28 : GlobalNames::VerifyUniqueInterObjectName(state,
275 14 : state.dataHeatRecovery->HeatExchangerUniqueNames,
276 14 : state.dataIPShortCut->cAlphaArgs(1),
277 : cCurrentModuleObject,
278 14 : state.dataIPShortCut->cAlphaFieldNames(1),
279 : ErrorsFound);
280 :
281 14 : thisExchanger.Name = state.dataIPShortCut->cAlphaArgs(1);
282 14 : thisExchanger.ExchType = DataHVACGlobals::HX_AIRTOAIR_FLATPLATE;
283 14 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
284 0 : thisExchanger.SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
285 : } else {
286 14 : thisExchanger.SchedPtr = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
287 14 : if (thisExchanger.SchedPtr == 0) {
288 0 : ShowSevereError(state,
289 0 : format("{}{}: invalid {} entered ={} for {}={}",
290 : RoutineName,
291 : cCurrentModuleObject,
292 0 : state.dataIPShortCut->cAlphaFieldNames(2),
293 0 : state.dataIPShortCut->cAlphaArgs(2),
294 0 : state.dataIPShortCut->cAlphaFieldNames(1),
295 0 : state.dataIPShortCut->cAlphaArgs(1)));
296 0 : ErrorsFound = true;
297 : }
298 : }
299 :
300 14 : constexpr std::array<std::string_view, static_cast<int>(HXConfiguration::Num)> hxConfigurationNamesUC = {
301 : "COUNTERFLOW", "PARALLELFLOW", "CROSSFLOWBOTHUNMIXED", "CROSS_FLOW_OTHER_NOT_USED"};
302 14 : thisExchanger.FlowArr = static_cast<HXConfiguration>(getEnumerationValue(hxConfigurationNamesUC, state.dataIPShortCut->cAlphaArgs(3)));
303 14 : if (thisExchanger.FlowArr == HXConfiguration::Invalid) {
304 0 : ShowSevereError(state, format("{}: incorrect flow arrangement: {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(3)));
305 0 : ErrorsFound = true;
306 : }
307 :
308 14 : if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
309 0 : thisExchanger.EconoLockOut = true;
310 : } else {
311 14 : BooleanSwitch toggle = getYesNoValue(state.dataIPShortCut->cAlphaArgs(4));
312 14 : if (toggle == BooleanSwitch::Invalid) {
313 0 : ShowSevereError(state, format("{}: incorrect econo lockout: {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(4)));
314 : }
315 14 : thisExchanger.EconoLockOut = static_cast<bool>(toggle);
316 : }
317 :
318 14 : thisExchanger.hARatio = state.dataIPShortCut->rNumericArgs(1);
319 14 : thisExchanger.NomSupAirVolFlow = state.dataIPShortCut->rNumericArgs(2);
320 14 : thisExchanger.NomSupAirInTemp = state.dataIPShortCut->rNumericArgs(3);
321 14 : thisExchanger.NomSupAirOutTemp = state.dataIPShortCut->rNumericArgs(4);
322 14 : thisExchanger.NomSecAirVolFlow = state.dataIPShortCut->rNumericArgs(5);
323 14 : thisExchanger.NomSecAirInTemp = state.dataIPShortCut->rNumericArgs(6);
324 14 : thisExchanger.NomElecPower = state.dataIPShortCut->rNumericArgs(7);
325 28 : thisExchanger.SupInletNode = GetOnlySingleNode(state,
326 14 : state.dataIPShortCut->cAlphaArgs(5),
327 : ErrorsFound,
328 : DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirFlatPlate,
329 : thisExchanger.Name,
330 : DataLoopNode::NodeFluidType::Air,
331 : DataLoopNode::ConnectionType::Inlet,
332 : NodeInputManager::CompFluidStream::Primary,
333 14 : DataLoopNode::ObjectIsNotParent);
334 28 : thisExchanger.SupOutletNode = GetOnlySingleNode(state,
335 14 : state.dataIPShortCut->cAlphaArgs(6),
336 : ErrorsFound,
337 : DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirFlatPlate,
338 : thisExchanger.Name,
339 : DataLoopNode::NodeFluidType::Air,
340 : DataLoopNode::ConnectionType::Outlet,
341 : NodeInputManager::CompFluidStream::Primary,
342 14 : DataLoopNode::ObjectIsNotParent);
343 28 : thisExchanger.SecInletNode = GetOnlySingleNode(state,
344 14 : state.dataIPShortCut->cAlphaArgs(7),
345 : ErrorsFound,
346 : DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirFlatPlate,
347 : thisExchanger.Name,
348 : DataLoopNode::NodeFluidType::Air,
349 : DataLoopNode::ConnectionType::Inlet,
350 : NodeInputManager::CompFluidStream::Secondary,
351 14 : DataLoopNode::ObjectIsNotParent);
352 28 : thisExchanger.SecOutletNode = GetOnlySingleNode(state,
353 14 : state.dataIPShortCut->cAlphaArgs(8),
354 : ErrorsFound,
355 : DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirFlatPlate,
356 : thisExchanger.Name,
357 : DataLoopNode::NodeFluidType::Air,
358 : DataLoopNode::ConnectionType::Outlet,
359 : NodeInputManager::CompFluidStream::Secondary,
360 14 : DataLoopNode::ObjectIsNotParent);
361 :
362 42 : BranchNodeConnections::TestCompSet(state,
363 14 : DataHVACGlobals::cHXTypes(thisExchanger.ExchType),
364 : thisExchanger.Name,
365 14 : state.dataIPShortCut->cAlphaArgs(5),
366 14 : state.dataIPShortCut->cAlphaArgs(6),
367 : "Process Air Nodes");
368 :
369 : } // end of input loop over air to air plate heat exchangers
370 :
371 : // loop over the air to air generic heat exchangers and load their input data
372 178 : for (int ExchIndex = 1; ExchIndex <= NumAirToAirGenericExchs; ++ExchIndex) {
373 137 : cCurrentModuleObject = "HeatExchanger:AirToAir:SensibleAndLatent";
374 959 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
375 : cCurrentModuleObject,
376 : ExchIndex,
377 137 : state.dataIPShortCut->cAlphaArgs,
378 : NumAlphas,
379 137 : state.dataIPShortCut->rNumericArgs,
380 : NumNumbers,
381 : IOStatus,
382 137 : state.dataIPShortCut->lNumericFieldBlanks,
383 137 : state.dataIPShortCut->lAlphaFieldBlanks,
384 137 : state.dataIPShortCut->cAlphaFieldNames,
385 137 : state.dataIPShortCut->cNumericFieldNames);
386 137 : int const ExchNum = ExchIndex + NumAirToAirPlateExchs;
387 137 : auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
388 137 : thisExchanger.NumericFieldNames.allocate(NumNumbers);
389 137 : thisExchanger.NumericFieldNames = "";
390 137 : thisExchanger.NumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
391 :
392 274 : GlobalNames::VerifyUniqueInterObjectName(state,
393 137 : state.dataHeatRecovery->HeatExchangerUniqueNames,
394 137 : state.dataIPShortCut->cAlphaArgs(1),
395 : cCurrentModuleObject,
396 137 : state.dataIPShortCut->cAlphaFieldNames(1),
397 : ErrorsFound);
398 :
399 137 : thisExchanger.Name = state.dataIPShortCut->cAlphaArgs(1);
400 137 : thisExchanger.ExchType = DataHVACGlobals::HX_AIRTOAIR_GENERIC;
401 137 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
402 1 : thisExchanger.SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
403 : } else {
404 136 : thisExchanger.SchedPtr = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
405 136 : if (thisExchanger.SchedPtr == 0) {
406 0 : ShowSevereError(state,
407 0 : format("{}{}: invalid {} entered ={} for {}={}",
408 : RoutineName,
409 : cCurrentModuleObject,
410 0 : state.dataIPShortCut->cAlphaFieldNames(2),
411 0 : state.dataIPShortCut->cAlphaArgs(2),
412 0 : state.dataIPShortCut->cAlphaFieldNames(1),
413 0 : thisExchanger.Name));
414 0 : ErrorsFound = true;
415 : }
416 : }
417 137 : thisExchanger.NomSupAirVolFlow = state.dataIPShortCut->rNumericArgs(1);
418 137 : thisExchanger.HeatEffectSensible100 = state.dataIPShortCut->rNumericArgs(2);
419 137 : thisExchanger.HeatEffectLatent100 = state.dataIPShortCut->rNumericArgs(3);
420 137 : thisExchanger.HeatEffectSensible75 = state.dataIPShortCut->rNumericArgs(4);
421 137 : thisExchanger.HeatEffectLatent75 = state.dataIPShortCut->rNumericArgs(5);
422 137 : if (thisExchanger.HeatEffectSensible75 < thisExchanger.HeatEffectSensible100) {
423 0 : ShowWarningError(state,
424 0 : format("{} \"{}\" sensible heating effectiveness at 75% rated flow is less than at 100% rated flow.",
425 : cCurrentModuleObject,
426 0 : thisExchanger.Name));
427 0 : ShowContinueError(state, "Sensible heating effectiveness at 75% rated flow is usually greater than at 100% rated flow.");
428 : }
429 137 : if (thisExchanger.HeatEffectLatent75 < thisExchanger.HeatEffectLatent100) {
430 0 : ShowWarningError(state,
431 0 : format("{} \"{}\" latent heating effectiveness at 75% rated flow is less than at 100% rated flow.",
432 : cCurrentModuleObject,
433 0 : thisExchanger.Name));
434 0 : ShowContinueError(state, "Latent heating effectiveness at 75% rated flow is usually greater than at 100% rated flow.");
435 : }
436 137 : thisExchanger.CoolEffectSensible100 = state.dataIPShortCut->rNumericArgs(6);
437 137 : thisExchanger.CoolEffectLatent100 = state.dataIPShortCut->rNumericArgs(7);
438 137 : thisExchanger.CoolEffectSensible75 = state.dataIPShortCut->rNumericArgs(8);
439 137 : thisExchanger.CoolEffectLatent75 = state.dataIPShortCut->rNumericArgs(9);
440 137 : if (thisExchanger.CoolEffectSensible75 < thisExchanger.CoolEffectSensible100) {
441 0 : ShowWarningError(state,
442 0 : format("{} \"{}\" sensible cooling effectiveness at 75% rated flow is less than at 100% rated flow.",
443 : cCurrentModuleObject,
444 0 : thisExchanger.Name));
445 0 : ShowContinueError(state, "Sensible cooling effectiveness at 75% rated flow is usually greater than at 100% rated flow.");
446 : }
447 137 : if (thisExchanger.CoolEffectLatent75 < thisExchanger.CoolEffectLatent100) {
448 0 : ShowWarningError(state,
449 0 : format("{} \"{}\" latent cooling effectiveness at 75% rated flow is less than at 100% rated flow.",
450 : cCurrentModuleObject,
451 0 : thisExchanger.Name));
452 0 : ShowContinueError(state, "Latent cooling effectiveness at 75% rated flow is usually greater than at 100% rated flow.");
453 : }
454 274 : thisExchanger.SupInletNode = GetOnlySingleNode(state,
455 137 : state.dataIPShortCut->cAlphaArgs(3),
456 : ErrorsFound,
457 : DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirSensibleAndLatent,
458 : thisExchanger.Name,
459 : DataLoopNode::NodeFluidType::Air,
460 : DataLoopNode::ConnectionType::Inlet,
461 : NodeInputManager::CompFluidStream::Primary,
462 137 : DataLoopNode::ObjectIsNotParent);
463 274 : thisExchanger.SupOutletNode = GetOnlySingleNode(state,
464 137 : state.dataIPShortCut->cAlphaArgs(4),
465 : ErrorsFound,
466 : DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirSensibleAndLatent,
467 : thisExchanger.Name,
468 : DataLoopNode::NodeFluidType::Air,
469 : DataLoopNode::ConnectionType::Outlet,
470 : NodeInputManager::CompFluidStream::Primary,
471 137 : DataLoopNode::ObjectIsNotParent);
472 274 : thisExchanger.SecInletNode = GetOnlySingleNode(state,
473 137 : state.dataIPShortCut->cAlphaArgs(5),
474 : ErrorsFound,
475 : DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirSensibleAndLatent,
476 : thisExchanger.Name,
477 : DataLoopNode::NodeFluidType::Air,
478 : DataLoopNode::ConnectionType::Inlet,
479 : NodeInputManager::CompFluidStream::Secondary,
480 137 : DataLoopNode::ObjectIsNotParent);
481 274 : thisExchanger.SecOutletNode = GetOnlySingleNode(state,
482 137 : state.dataIPShortCut->cAlphaArgs(6),
483 : ErrorsFound,
484 : DataLoopNode::ConnectionObjectType::HeatExchangerAirToAirSensibleAndLatent,
485 : thisExchanger.Name,
486 : DataLoopNode::NodeFluidType::Air,
487 : DataLoopNode::ConnectionType::Outlet,
488 : NodeInputManager::CompFluidStream::Secondary,
489 137 : DataLoopNode::ObjectIsNotParent);
490 :
491 137 : thisExchanger.NomElecPower = state.dataIPShortCut->rNumericArgs(10);
492 :
493 137 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(7), "Yes")) {
494 18 : thisExchanger.ControlToTemperatureSetPoint = true;
495 : } else {
496 119 : if (!UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(7), "No")) {
497 0 : ShowSevereError(state, "Rotary HX Speed Modulation or Plate Bypass for Temperature Control for ");
498 0 : ShowContinueError(state, thisExchanger.Name + " must be set to Yes or No");
499 0 : ErrorsFound = true;
500 : }
501 : }
502 :
503 137 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(8), "Plate")) {
504 27 : thisExchanger.ExchConfig = HXConfigurationType::Plate;
505 110 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(8), "Rotary")) {
506 110 : thisExchanger.ExchConfig = HXConfigurationType::Rotary;
507 : } else {
508 0 : ShowSevereError(state, format("{} configuration not found= {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(8)));
509 0 : ShowContinueError(state, "HX configuration must be either Plate or Rotary");
510 0 : ErrorsFound = true;
511 : }
512 :
513 : // Added additional inputs for frost control
514 137 : thisExchanger.FrostControlType =
515 274 : static_cast<FrostControlOption>(getEnumerationValue(frostControlNamesUC, state.dataIPShortCut->cAlphaArgs(9)));
516 137 : if (thisExchanger.FrostControlType == FrostControlOption::Invalid) {
517 0 : ShowSevereError(state, format("Invalid Frost Control method for {} = {}", thisExchanger.Name, state.dataIPShortCut->cAlphaArgs(9)));
518 0 : ErrorsFound = true;
519 : }
520 :
521 137 : if (!UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(9), "None")) {
522 126 : thisExchanger.ThresholdTemperature = state.dataIPShortCut->rNumericArgs(11);
523 126 : thisExchanger.InitialDefrostTime = state.dataIPShortCut->rNumericArgs(12);
524 126 : thisExchanger.RateofDefrostTimeIncrease = state.dataIPShortCut->rNumericArgs(13);
525 : }
526 :
527 137 : if (state.dataIPShortCut->lAlphaFieldBlanks(10)) {
528 113 : thisExchanger.EconoLockOut = true;
529 : } else {
530 24 : BooleanSwitch toggle = getYesNoValue(state.dataIPShortCut->cAlphaArgs(10));
531 24 : if (toggle == BooleanSwitch::Invalid) {
532 0 : ShowSevereError(state, format("{}: incorrect econo lockout: {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(10)));
533 : }
534 24 : thisExchanger.EconoLockOut = static_cast<bool>(toggle);
535 : }
536 :
537 411 : BranchNodeConnections::TestCompSet(state,
538 137 : DataHVACGlobals::cHXTypes(thisExchanger.ExchType),
539 : thisExchanger.Name,
540 137 : state.dataIPShortCut->cAlphaArgs(3),
541 137 : state.dataIPShortCut->cAlphaArgs(4),
542 : "Process Air Nodes");
543 : } // end of input loop over air to air generic heat exchangers
544 :
545 : // loop over the desiccant balanced heat exchangers and load their input data
546 48 : for (int ExchIndex = 1; ExchIndex <= NumDesiccantBalancedExchs; ++ExchIndex) {
547 7 : cCurrentModuleObject = "HeatExchanger:Desiccant:BalancedFlow";
548 49 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
549 : cCurrentModuleObject,
550 : ExchIndex,
551 7 : state.dataIPShortCut->cAlphaArgs,
552 : NumAlphas,
553 7 : state.dataIPShortCut->rNumericArgs,
554 : NumNumbers,
555 : IOStatus,
556 7 : state.dataIPShortCut->lNumericFieldBlanks,
557 7 : state.dataIPShortCut->lAlphaFieldBlanks,
558 7 : state.dataIPShortCut->cAlphaFieldNames,
559 7 : state.dataIPShortCut->cNumericFieldNames);
560 7 : int const ExchNum = ExchIndex + NumAirToAirPlateExchs + NumAirToAirGenericExchs;
561 7 : auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
562 7 : thisExchanger.NumericFieldNames.allocate(NumNumbers);
563 7 : thisExchanger.NumericFieldNames = "";
564 7 : thisExchanger.NumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
565 :
566 14 : GlobalNames::VerifyUniqueInterObjectName(state,
567 7 : state.dataHeatRecovery->HeatExchangerUniqueNames,
568 7 : state.dataIPShortCut->cAlphaArgs(1),
569 : cCurrentModuleObject,
570 7 : state.dataIPShortCut->cAlphaFieldNames(1),
571 : ErrorsFound);
572 :
573 7 : thisExchanger.Name = state.dataIPShortCut->cAlphaArgs(1);
574 7 : thisExchanger.ExchType = DataHVACGlobals::HX_DESICCANT_BALANCED;
575 7 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
576 0 : thisExchanger.SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
577 : } else {
578 7 : thisExchanger.SchedPtr = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
579 7 : if (thisExchanger.SchedPtr == 0) {
580 0 : ShowSevereError(state,
581 0 : format("{}{}: invalid {} entered ={} for {}={}",
582 : RoutineName,
583 : cCurrentModuleObject,
584 0 : state.dataIPShortCut->cAlphaFieldNames(2),
585 0 : state.dataIPShortCut->cAlphaArgs(2),
586 0 : state.dataIPShortCut->cAlphaFieldNames(1),
587 0 : thisExchanger.Name));
588 0 : ErrorsFound = true;
589 : }
590 : }
591 : // desiccant HX's usually refer to process and regeneration air streams
592 : // In this module, Sup = Regeneration nodes and Sec = Process nodes
593 : // regeneration air inlet and outlet nodes
594 14 : thisExchanger.SupInletNode = GetOnlySingleNode(state,
595 7 : state.dataIPShortCut->cAlphaArgs(3),
596 : ErrorsFound,
597 : DataLoopNode::ConnectionObjectType::HeatExchangerDesiccantBalancedFlow,
598 : thisExchanger.Name,
599 : DataLoopNode::NodeFluidType::Air,
600 : DataLoopNode::ConnectionType::Inlet,
601 : NodeInputManager::CompFluidStream::Primary,
602 7 : DataLoopNode::ObjectIsNotParent);
603 14 : thisExchanger.SupOutletNode = GetOnlySingleNode(state,
604 7 : state.dataIPShortCut->cAlphaArgs(4),
605 : ErrorsFound,
606 : DataLoopNode::ConnectionObjectType::HeatExchangerDesiccantBalancedFlow,
607 : thisExchanger.Name,
608 : DataLoopNode::NodeFluidType::Air,
609 : DataLoopNode::ConnectionType::Outlet,
610 : NodeInputManager::CompFluidStream::Primary,
611 7 : DataLoopNode::ObjectIsNotParent);
612 : // process air inlet and outlet nodes
613 14 : thisExchanger.SecInletNode = GetOnlySingleNode(state,
614 7 : state.dataIPShortCut->cAlphaArgs(5),
615 : ErrorsFound,
616 : DataLoopNode::ConnectionObjectType::HeatExchangerDesiccantBalancedFlow,
617 : thisExchanger.Name,
618 : DataLoopNode::NodeFluidType::Air,
619 : DataLoopNode::ConnectionType::Inlet,
620 : NodeInputManager::CompFluidStream::Secondary,
621 7 : DataLoopNode::ObjectIsNotParent);
622 14 : thisExchanger.SecOutletNode = GetOnlySingleNode(state,
623 7 : state.dataIPShortCut->cAlphaArgs(6),
624 : ErrorsFound,
625 : DataLoopNode::ConnectionObjectType::HeatExchangerDesiccantBalancedFlow,
626 : thisExchanger.Name,
627 : DataLoopNode::NodeFluidType::Air,
628 : DataLoopNode::ConnectionType::Outlet,
629 : NodeInputManager::CompFluidStream::Secondary,
630 7 : DataLoopNode::ObjectIsNotParent);
631 :
632 : // Set up the component set for the process side of the HX (Sec = Process)
633 21 : BranchNodeConnections::TestCompSet(state,
634 7 : DataHVACGlobals::cHXTypes(thisExchanger.ExchType),
635 : thisExchanger.Name,
636 7 : state.dataLoopNodes->NodeID(thisExchanger.SecInletNode),
637 7 : state.dataLoopNodes->NodeID(thisExchanger.SecOutletNode),
638 : "Process Air Nodes");
639 :
640 : // A7 is the heat exchanger performance object type
641 : // It currently only has one choice key, with a default value, so currently no logic is needed
642 : // In the future if someone added another performance type, the logic could be added back here
643 : // HeatExchPerfType = state.dataIPShortCut->cAlphaArgs(7);
644 :
645 7 : thisExchanger.HeatExchPerfName = state.dataIPShortCut->cAlphaArgs(8);
646 :
647 7 : if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
648 7 : thisExchanger.EconoLockOut = true;
649 : } else {
650 0 : BooleanSwitch toggle = getYesNoValue(state.dataIPShortCut->cAlphaArgs(9));
651 0 : if (toggle == BooleanSwitch::Invalid) {
652 0 : ShowSevereError(state, format("{}: incorrect econo lockout: {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(9)));
653 : }
654 0 : thisExchanger.EconoLockOut = static_cast<bool>(toggle);
655 : }
656 :
657 : } // end of input loop over desiccant balanced heat exchangers
658 :
659 : // get performance data set for balanced desiccant heat exchanger
660 :
661 48 : for (int PerfDataIndex = 1; PerfDataIndex <= NumDesBalExchsPerfDataType1; ++PerfDataIndex) {
662 7 : cCurrentModuleObject = "HeatExchanger:Desiccant:BalancedFlow:PerformanceDataType1";
663 49 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
664 : cCurrentModuleObject,
665 : PerfDataIndex,
666 7 : state.dataIPShortCut->cAlphaArgs,
667 : NumAlphas,
668 7 : state.dataIPShortCut->rNumericArgs,
669 : NumNumbers,
670 : IOStatus,
671 7 : state.dataIPShortCut->lNumericFieldBlanks,
672 7 : state.dataIPShortCut->lAlphaFieldBlanks,
673 7 : state.dataIPShortCut->cAlphaFieldNames,
674 7 : state.dataIPShortCut->cNumericFieldNames);
675 7 : int const PerfDataNum = PerfDataIndex;
676 7 : auto &thisPerfData = state.dataHeatRecovery->BalDesDehumPerfData(PerfDataNum);
677 7 : thisPerfData.NumericFieldNames.allocate(NumNumbers);
678 7 : thisPerfData.NumericFieldNames = "";
679 7 : thisPerfData.NumericFieldNames = state.dataIPShortCut->cNumericFieldNames;
680 :
681 7 : UtilityRoutines::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound);
682 :
683 7 : thisPerfData.Name = state.dataIPShortCut->cAlphaArgs(1);
684 7 : thisPerfData.PerfType = cCurrentModuleObject;
685 7 : thisPerfData.NomSupAirVolFlow = state.dataIPShortCut->rNumericArgs(1);
686 : // check validity
687 7 : if (thisPerfData.NomSupAirVolFlow <= 0.0 && thisPerfData.NomSupAirVolFlow != DataSizing::AutoSize) {
688 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
689 0 : ShowContinueError(state, "Nominal air flow rate must be greater than zero.");
690 0 : ShowContinueError(state, format("... value entered = {:.6R}", thisPerfData.NomSupAirVolFlow));
691 0 : ErrorsFound = true;
692 : }
693 :
694 7 : thisPerfData.NomProcAirFaceVel = state.dataIPShortCut->rNumericArgs(2);
695 : // check validity
696 14 : if ((thisPerfData.NomProcAirFaceVel <= 0.0 && thisPerfData.NomProcAirFaceVel != DataSizing::AutoSize) ||
697 7 : thisPerfData.NomProcAirFaceVel > 6.0) {
698 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
699 0 : ShowContinueError(state, "Nominal air face velocity cannot be less than or equal to zero or greater than 6 m/s.");
700 0 : ShowContinueError(state, format("... value entered = {:.6R}", thisPerfData.NomProcAirFaceVel));
701 0 : ErrorsFound = true;
702 : }
703 7 : thisPerfData.NomElecPower = state.dataIPShortCut->rNumericArgs(3);
704 : // check validity
705 7 : if (thisPerfData.NomElecPower < 0.0) {
706 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
707 0 : ShowContinueError(state, "Nominal electric power cannot be less than zero.");
708 0 : ShowContinueError(state, format("... value entered = {:.6R}", thisPerfData.NomElecPower));
709 0 : ErrorsFound = true;
710 : }
711 :
712 : // regen outlet temp variables
713 63 : for (int i = 0; i < 8; ++i)
714 56 : thisPerfData.B[i] = state.dataIPShortCut->rNumericArgs(i + 4);
715 :
716 : // Check that the minimum is not greater than or equal to the maximum for each of the following model boundaries
717 7 : thisPerfData.T_MinRegenAirInHumRat = state.dataIPShortCut->rNumericArgs(12);
718 7 : thisPerfData.T_MaxRegenAirInHumRat = state.dataIPShortCut->rNumericArgs(13);
719 7 : if (thisPerfData.T_MinRegenAirInHumRat >= thisPerfData.T_MaxRegenAirInHumRat) {
720 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
721 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
722 0 : ShowContinueError(state, "... the minimum value of regeneration inlet air humidity ratio must be less than the maximum.");
723 0 : ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.T_MinRegenAirInHumRat));
724 0 : ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.T_MaxRegenAirInHumRat));
725 0 : ErrorsFound = true;
726 : }
727 7 : if (thisPerfData.T_MinRegenAirInHumRat < 0.0) {
728 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
729 0 : ShowContinueError(state, "Error found in min boundary for the regen outlet air temperature equation.");
730 0 : ShowContinueError(state, "... the minimum value of regeneration inlet air humidity ratio must be greater than or equal to 0.");
731 0 : ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.T_MinRegenAirInHumRat));
732 0 : ErrorsFound = true;
733 : }
734 7 : if (thisPerfData.T_MaxRegenAirInHumRat > 1.0) {
735 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
736 0 : ShowContinueError(state, "Error found in max boundary for the regen outlet air temperature equation.");
737 0 : ShowContinueError(state, "... the maximum value of regeneration inlet air humidity ratio must be less than or equal to 1.");
738 0 : ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.T_MaxRegenAirInHumRat));
739 0 : ErrorsFound = true;
740 : }
741 :
742 7 : thisPerfData.T_MinRegenAirInTemp = state.dataIPShortCut->rNumericArgs(14);
743 7 : thisPerfData.T_MaxRegenAirInTemp = state.dataIPShortCut->rNumericArgs(15);
744 7 : if (thisPerfData.T_MinRegenAirInTemp >= thisPerfData.T_MaxRegenAirInTemp) {
745 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
746 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
747 0 : ShowContinueError(state, "... the minimum value of regeneration inlet air temperature must be less than the maximum.");
748 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinRegenAirInTemp));
749 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxRegenAirInTemp));
750 0 : ErrorsFound = true;
751 : }
752 :
753 7 : thisPerfData.T_MinProcAirInHumRat = state.dataIPShortCut->rNumericArgs(16);
754 7 : thisPerfData.T_MaxProcAirInHumRat = state.dataIPShortCut->rNumericArgs(17);
755 7 : if (thisPerfData.T_MinProcAirInHumRat >= thisPerfData.T_MaxProcAirInHumRat) {
756 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
757 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
758 0 : ShowContinueError(state, "... the minimum value of process inlet air humidity ratio must be less than the maximum.");
759 0 : ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.T_MinProcAirInHumRat));
760 0 : ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.T_MaxProcAirInHumRat));
761 0 : ErrorsFound = true;
762 : }
763 7 : if (thisPerfData.T_MinProcAirInHumRat < 0.0) {
764 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
765 0 : ShowContinueError(state, "Error found in min boundary for the regen outlet air temperature equation.");
766 0 : ShowContinueError(state, "... the minimum value of process inlet air humidity ratio must be greater than or equal to 0.");
767 0 : ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.T_MinProcAirInHumRat));
768 0 : ErrorsFound = true;
769 : }
770 7 : if (thisPerfData.T_MaxProcAirInHumRat > 1.0) {
771 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
772 0 : ShowContinueError(state, "Error found in max boundary for the regen outlet air temperature equation.");
773 0 : ShowContinueError(state, "... the maximum value of process inlet air humidity ratio must be less than or equal to 1.");
774 0 : ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.T_MaxProcAirInHumRat));
775 0 : ErrorsFound = true;
776 : }
777 :
778 7 : thisPerfData.T_MinProcAirInTemp = state.dataIPShortCut->rNumericArgs(18);
779 7 : thisPerfData.T_MaxProcAirInTemp = state.dataIPShortCut->rNumericArgs(19);
780 7 : if (thisPerfData.T_MinProcAirInTemp >= thisPerfData.T_MaxProcAirInTemp) {
781 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
782 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
783 0 : ShowContinueError(state, "... the minimum value of process inlet air temperature must be less than the maximum.");
784 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinProcAirInTemp));
785 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxProcAirInTemp));
786 0 : ErrorsFound = true;
787 : }
788 :
789 7 : thisPerfData.T_MinFaceVel = state.dataIPShortCut->rNumericArgs(20);
790 7 : thisPerfData.T_MaxFaceVel = state.dataIPShortCut->rNumericArgs(21);
791 7 : if (thisPerfData.T_MinFaceVel >= thisPerfData.T_MaxFaceVel) {
792 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
793 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
794 0 : ShowContinueError(state, "... the minimum value of regen air velocity must be less than the maximum.");
795 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinFaceVel));
796 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxFaceVel));
797 0 : ErrorsFound = true;
798 : }
799 :
800 7 : thisPerfData.MinRegenAirOutTemp = state.dataIPShortCut->rNumericArgs(22);
801 7 : thisPerfData.MaxRegenAirOutTemp = state.dataIPShortCut->rNumericArgs(23);
802 7 : if (thisPerfData.MinRegenAirOutTemp >= thisPerfData.MaxRegenAirOutTemp) {
803 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
804 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
805 0 : ShowContinueError(state, "... the minimum value of regen outlet air temperature must be less than the maximum.");
806 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.MinRegenAirOutTemp));
807 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.MaxRegenAirOutTemp));
808 0 : ErrorsFound = true;
809 : }
810 :
811 7 : thisPerfData.T_MinRegenAirInRelHum = state.dataIPShortCut->rNumericArgs(24) / 100.0;
812 7 : thisPerfData.T_MaxRegenAirInRelHum = state.dataIPShortCut->rNumericArgs(25) / 100.0;
813 7 : if (thisPerfData.T_MinRegenAirInRelHum >= thisPerfData.T_MaxRegenAirInRelHum) {
814 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
815 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
816 0 : ShowContinueError(state, "... the minimum value of regen inlet air relative humidity must be less than the maximum.");
817 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinRegenAirInRelHum * 100.0));
818 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxRegenAirInRelHum * 100.0));
819 0 : ErrorsFound = true;
820 : }
821 7 : if (thisPerfData.T_MinRegenAirInRelHum < 0.0) {
822 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
823 0 : ShowContinueError(state, "Error found in min boundary for the regen outlet air temperature equation.");
824 0 : ShowContinueError(state, "... the minimum value of regen inlet air relative humidity must be greater than or equal to 0.");
825 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinRegenAirInRelHum * 100.0));
826 0 : ErrorsFound = true;
827 : }
828 7 : if (thisPerfData.T_MaxRegenAirInRelHum > 1.0) {
829 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
830 0 : ShowContinueError(state, "Error found in max boundary for the regen outlet air temperature equation.");
831 0 : ShowContinueError(state, "... the maximum value of regen inlet air relative humidity must be less than or equal to 100.");
832 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxRegenAirInRelHum * 100.0));
833 0 : ErrorsFound = true;
834 : }
835 :
836 7 : thisPerfData.T_MinProcAirInRelHum = state.dataIPShortCut->rNumericArgs(26) / 100.0;
837 7 : thisPerfData.T_MaxProcAirInRelHum = state.dataIPShortCut->rNumericArgs(27) / 100.0;
838 7 : if (thisPerfData.T_MinProcAirInRelHum >= thisPerfData.T_MaxProcAirInRelHum) {
839 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
840 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air temperature equation.");
841 0 : ShowContinueError(state, "... the minimum value of process inlet air relative humidity must be less than the maximum.");
842 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinProcAirInRelHum * 100.0));
843 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxProcAirInRelHum * 100.0));
844 0 : ErrorsFound = true;
845 : }
846 7 : if (thisPerfData.T_MinProcAirInRelHum < 0.0) {
847 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
848 0 : ShowContinueError(state, "Error found in min boundary for the regen outlet air temperature equation.");
849 0 : ShowContinueError(state, "... the minimum value of process inlet air relative humidity must be greater than or equal to 0.");
850 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.T_MinProcAirInRelHum * 100.0));
851 0 : ErrorsFound = true;
852 : }
853 7 : if (thisPerfData.T_MaxProcAirInRelHum > 1.0) {
854 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
855 0 : ShowContinueError(state, "Error found in max boundary for the regen outlet air temperature equation.");
856 0 : ShowContinueError(state, "... the maximum value of process inlet air relative humidity must be less than or equal to 100.");
857 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.T_MaxProcAirInRelHum * 100.0));
858 0 : ErrorsFound = true;
859 : }
860 :
861 : // regen outlet humidity ratio variables
862 63 : for (int i = 0; i < 8; ++i)
863 56 : thisPerfData.C[i] = state.dataIPShortCut->rNumericArgs(i + 28);
864 :
865 : // Check that the minimum is not greater than or equal to the maximum for each of the following model boundaries
866 7 : thisPerfData.H_MinRegenAirInHumRat = state.dataIPShortCut->rNumericArgs(36);
867 7 : thisPerfData.H_MaxRegenAirInHumRat = state.dataIPShortCut->rNumericArgs(37);
868 7 : if (thisPerfData.H_MinRegenAirInHumRat >= thisPerfData.H_MaxRegenAirInHumRat) {
869 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
870 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
871 0 : ShowContinueError(state, "... the minimum value of regeneration inlet air humidity ratio must be less than the maximum.");
872 0 : ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.H_MinRegenAirInHumRat));
873 0 : ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.H_MaxRegenAirInHumRat));
874 0 : ErrorsFound = true;
875 : }
876 7 : if (thisPerfData.H_MinRegenAirInHumRat < 0.0) {
877 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
878 0 : ShowContinueError(state, "Error found in min boundary for the regen outlet air humidity ratio equation.");
879 0 : ShowContinueError(state, "... the minimum value of regeneration inlet air humidity ratio must be greater than or equal to 0.");
880 0 : ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.H_MinRegenAirInHumRat));
881 0 : ErrorsFound = true;
882 : }
883 7 : if (thisPerfData.H_MaxRegenAirInHumRat > 1.0) {
884 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
885 0 : ShowContinueError(state, "Error found in max boundary for the regen outlet air humidity ratio equation.");
886 0 : ShowContinueError(state, "... the maximum value of regeneration inlet air humidity ratio must be less than or equal to 1.");
887 0 : ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.H_MaxRegenAirInHumRat));
888 0 : ErrorsFound = true;
889 : }
890 :
891 7 : thisPerfData.H_MinRegenAirInTemp = state.dataIPShortCut->rNumericArgs(38);
892 7 : thisPerfData.H_MaxRegenAirInTemp = state.dataIPShortCut->rNumericArgs(39);
893 7 : if (thisPerfData.H_MinRegenAirInTemp >= thisPerfData.H_MaxRegenAirInTemp) {
894 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
895 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
896 0 : ShowContinueError(state, "... the minimum value of regeneration inlet air temperature must be less than the maximum.");
897 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinRegenAirInTemp));
898 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxRegenAirInTemp));
899 0 : ErrorsFound = true;
900 : }
901 :
902 7 : thisPerfData.H_MinProcAirInHumRat = state.dataIPShortCut->rNumericArgs(40);
903 7 : thisPerfData.H_MaxProcAirInHumRat = state.dataIPShortCut->rNumericArgs(41);
904 7 : if (thisPerfData.H_MinProcAirInHumRat >= thisPerfData.H_MaxProcAirInHumRat) {
905 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
906 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
907 0 : ShowContinueError(state, "... the minimum value of process inlet air humidity ratio must be less than the maximum.");
908 0 : ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.H_MinProcAirInHumRat));
909 0 : ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.H_MaxProcAirInHumRat));
910 0 : ErrorsFound = true;
911 : }
912 7 : if (thisPerfData.H_MinProcAirInHumRat < 0.0) {
913 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
914 0 : ShowContinueError(state, "Error found in min boundary for the regen outlet air humidity ratio equation.");
915 0 : ShowContinueError(state, "... the minimum value of process inlet air humidity ratio must be greater than or equal to 0.");
916 0 : ShowContinueError(state, format("... minimum value entered by user = {:.6R}", thisPerfData.H_MinProcAirInHumRat));
917 0 : ErrorsFound = true;
918 : }
919 7 : if (thisPerfData.H_MaxProcAirInHumRat > 1.0) {
920 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
921 0 : ShowContinueError(state, "Error found in max boundary for the regen outlet air humidity ratio equation.");
922 0 : ShowContinueError(state, "... the maximum value of process inlet air humidity ratio must be less than or equal to 1.");
923 0 : ShowContinueError(state, format("... maximum value entered by user = {:.6R}", thisPerfData.H_MaxProcAirInHumRat));
924 0 : ErrorsFound = true;
925 : }
926 :
927 7 : thisPerfData.H_MinProcAirInTemp = state.dataIPShortCut->rNumericArgs(42);
928 7 : thisPerfData.H_MaxProcAirInTemp = state.dataIPShortCut->rNumericArgs(43);
929 7 : if (thisPerfData.H_MinProcAirInTemp >= thisPerfData.H_MaxProcAirInTemp) {
930 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
931 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
932 0 : ShowContinueError(state, "... the minimum value of process inlet air temperature must be less than the maximum.");
933 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinProcAirInTemp));
934 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxProcAirInTemp));
935 0 : ErrorsFound = true;
936 : }
937 :
938 7 : thisPerfData.H_MinFaceVel = state.dataIPShortCut->rNumericArgs(44);
939 7 : thisPerfData.H_MaxFaceVel = state.dataIPShortCut->rNumericArgs(45);
940 7 : if (thisPerfData.H_MinFaceVel >= thisPerfData.H_MaxFaceVel) {
941 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
942 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
943 0 : ShowContinueError(state, "... the minimum value of regen air velocity must be less than the maximum.");
944 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinFaceVel));
945 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxFaceVel));
946 0 : ErrorsFound = true;
947 : }
948 :
949 7 : thisPerfData.MinRegenAirOutHumRat = state.dataIPShortCut->rNumericArgs(46);
950 7 : thisPerfData.MaxRegenAirOutHumRat = state.dataIPShortCut->rNumericArgs(47);
951 7 : if (thisPerfData.MinRegenAirOutHumRat >= thisPerfData.MaxRegenAirOutHumRat) {
952 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
953 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
954 0 : ShowContinueError(state, "... the minimum value of regen outlet air humidity ratio must be less than the maximum.");
955 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.MinRegenAirOutHumRat));
956 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.MaxRegenAirOutHumRat));
957 0 : ErrorsFound = true;
958 : }
959 7 : if (thisPerfData.MinRegenAirOutHumRat < 0.0) {
960 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
961 0 : ShowContinueError(state, "Error found in min boundary for the regen outlet air humidity ratio equation.");
962 0 : ShowContinueError(state, "... the minimum value of regen outlet air humidity ratio must be greater than or equal to 0.");
963 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.MinRegenAirOutHumRat));
964 0 : ErrorsFound = true;
965 : }
966 7 : if (thisPerfData.MaxRegenAirOutHumRat > 1.0) {
967 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
968 0 : ShowContinueError(state, "Error found in max boundary for the regen outlet air humidity ratio equation.");
969 0 : ShowContinueError(state, "... the maximum value of regen outlet air humidity ratio must be less or equal to 1.");
970 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.MaxRegenAirOutHumRat));
971 0 : ErrorsFound = true;
972 : }
973 :
974 7 : thisPerfData.H_MinRegenAirInRelHum = state.dataIPShortCut->rNumericArgs(48) / 100.0;
975 7 : thisPerfData.H_MaxRegenAirInRelHum = state.dataIPShortCut->rNumericArgs(49) / 100.0;
976 7 : if (thisPerfData.H_MinRegenAirInRelHum >= thisPerfData.H_MaxRegenAirInRelHum) {
977 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
978 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
979 0 : ShowContinueError(state, "... the minimum value of regen inlet air relative humidity must be less than the maximum.");
980 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinRegenAirInRelHum * 100.0));
981 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxRegenAirInRelHum * 100.0));
982 0 : ErrorsFound = true;
983 : }
984 7 : if (thisPerfData.H_MinRegenAirInRelHum < 0.0) {
985 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
986 0 : ShowContinueError(state, "Error found in min boundary for the regen outlet air humidity ratio equation.");
987 0 : ShowContinueError(state, "... the minimum value of regen inlet air relative humidity must be greater than or equal to 0.");
988 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinRegenAirInRelHum * 100.0));
989 0 : ErrorsFound = true;
990 : }
991 7 : if (thisPerfData.H_MaxRegenAirInRelHum > 1.0) {
992 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
993 0 : ShowContinueError(state, "Error found in max boundary for the regen outlet air humidity ratio equation.");
994 0 : ShowContinueError(state, "... the maximum value of regen inlet air relative humidity must be less or equal to 100.");
995 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxRegenAirInRelHum * 100.0));
996 0 : ErrorsFound = true;
997 : }
998 :
999 7 : thisPerfData.H_MinProcAirInRelHum = state.dataIPShortCut->rNumericArgs(50) / 100.0;
1000 7 : thisPerfData.H_MaxProcAirInRelHum = state.dataIPShortCut->rNumericArgs(51) / 100.0;
1001 7 : if (thisPerfData.H_MinProcAirInRelHum >= thisPerfData.H_MaxProcAirInRelHum) {
1002 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
1003 0 : ShowContinueError(state, "Error found in min/max boundary for the regen outlet air humidity ratio equation.");
1004 0 : ShowContinueError(state, "... the minimum value of process inlet air relative humidity must be less than the maximum.");
1005 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinProcAirInRelHum * 100.0));
1006 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxProcAirInRelHum * 100.0));
1007 0 : ErrorsFound = true;
1008 : }
1009 7 : if (thisPerfData.H_MinProcAirInRelHum < 0.0) {
1010 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
1011 0 : ShowContinueError(state, "Error found in min boundary for the regen outlet air humidity ratio equation.");
1012 0 : ShowContinueError(state, "... the minimum value of process inlet air relative humidity must be greater than or equal to 0.");
1013 0 : ShowContinueError(state, format("... minimum value entered = {:.6R}", thisPerfData.H_MinProcAirInRelHum * 100.0));
1014 0 : ErrorsFound = true;
1015 : }
1016 7 : if (thisPerfData.H_MaxProcAirInRelHum > 1.0) {
1017 0 : ShowSevereError(state, format("{} \"{}\"", cCurrentModuleObject, thisPerfData.Name));
1018 0 : ShowContinueError(state, "Error found in max boundary for the regen outlet air humidity ratio equation.");
1019 0 : ShowContinueError(state, "... the maximum value of process inlet air relative humidity must be less than or equal to 100.");
1020 0 : ShowContinueError(state, format("... maximum value entered = {:.6R}", thisPerfData.H_MaxProcAirInRelHum * 100.0));
1021 0 : ErrorsFound = true;
1022 : }
1023 : }
1024 : // getting performance data set for balanced desiccant heat exchanger ends
1025 :
1026 : // match desiccant heat exchanger index to performance data index
1027 48 : for (int ExchIndex = 1; ExchIndex <= NumDesiccantBalancedExchs; ++ExchIndex) {
1028 7 : int const ExchNum = ExchIndex + NumAirToAirPlateExchs + NumAirToAirGenericExchs;
1029 7 : auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
1030 9 : for (int PerfDataNum = 1; PerfDataNum <= NumDesBalExchsPerfDataType1; ++PerfDataNum) {
1031 9 : if (UtilityRoutines::SameString(thisExchanger.HeatExchPerfName, state.dataHeatRecovery->BalDesDehumPerfData(PerfDataNum).Name)) {
1032 7 : thisExchanger.PerfDataIndex = PerfDataNum;
1033 7 : break;
1034 : }
1035 : }
1036 7 : if (thisExchanger.PerfDataIndex == 0) {
1037 0 : ShowSevereError(state, format("{} \"{}\"", DataHVACGlobals::cHXTypes(thisExchanger.ExchType), thisExchanger.Name));
1038 0 : ShowContinueError(state, format("... Performance data set not found = {}", thisExchanger.HeatExchPerfName));
1039 0 : ErrorsFound = true;
1040 : } else {
1041 7 : if (!ErrorsFound) {
1042 14 : thisExchanger.FaceArea = state.dataHeatRecovery->BalDesDehumPerfData(thisExchanger.PerfDataIndex).NomSupAirVolFlow /
1043 7 : (state.dataHeatRecovery->BalDesDehumPerfData(thisExchanger.PerfDataIndex).NomProcAirFaceVel);
1044 : }
1045 : }
1046 : }
1047 : // matching done
1048 :
1049 : // setup common report variables for heat exchangers
1050 199 : for (int ExchIndex = 1; ExchIndex <= state.dataHeatRecovery->NumHeatExchangers; ++ExchIndex) {
1051 158 : int const ExchNum = ExchIndex;
1052 158 : auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
1053 : // CurrentModuleObject='HeatExchanger:AirToAir:FlatPlate/AirToAir:SensibleAndLatent/Desiccant:BalancedFlow')
1054 316 : SetupOutputVariable(state,
1055 : "Heat Exchanger Sensible Heating Rate",
1056 : OutputProcessor::Unit::W,
1057 : thisExchanger.SensHeatingRate,
1058 : OutputProcessor::SOVTimeStepType::System,
1059 : OutputProcessor::SOVStoreType::Average,
1060 158 : thisExchanger.Name);
1061 316 : SetupOutputVariable(state,
1062 : "Heat Exchanger Sensible Heating Energy",
1063 : OutputProcessor::Unit::J,
1064 : thisExchanger.SensHeatingEnergy,
1065 : OutputProcessor::SOVTimeStepType::System,
1066 : OutputProcessor::SOVStoreType::Summed,
1067 158 : thisExchanger.Name);
1068 316 : SetupOutputVariable(state,
1069 : "Heat Exchanger Latent Gain Rate",
1070 : OutputProcessor::Unit::W,
1071 : thisExchanger.LatHeatingRate,
1072 : OutputProcessor::SOVTimeStepType::System,
1073 : OutputProcessor::SOVStoreType::Average,
1074 158 : thisExchanger.Name);
1075 316 : SetupOutputVariable(state,
1076 : "Heat Exchanger Latent Gain Energy",
1077 : OutputProcessor::Unit::J,
1078 : thisExchanger.LatHeatingEnergy,
1079 : OutputProcessor::SOVTimeStepType::System,
1080 : OutputProcessor::SOVStoreType::Summed,
1081 158 : thisExchanger.Name);
1082 316 : SetupOutputVariable(state,
1083 : "Heat Exchanger Total Heating Rate",
1084 : OutputProcessor::Unit::W,
1085 : thisExchanger.TotHeatingRate,
1086 : OutputProcessor::SOVTimeStepType::System,
1087 : OutputProcessor::SOVStoreType::Average,
1088 158 : thisExchanger.Name);
1089 316 : SetupOutputVariable(state,
1090 : "Heat Exchanger Total Heating Energy",
1091 : OutputProcessor::Unit::J,
1092 : thisExchanger.TotHeatingEnergy,
1093 : OutputProcessor::SOVTimeStepType::System,
1094 : OutputProcessor::SOVStoreType::Summed,
1095 : thisExchanger.Name,
1096 : _,
1097 : "ENERGYTRANSFER",
1098 : "HEAT RECOVERY FOR HEATING",
1099 : _,
1100 158 : "System");
1101 316 : SetupOutputVariable(state,
1102 : "Heat Exchanger Sensible Cooling Rate",
1103 : OutputProcessor::Unit::W,
1104 : thisExchanger.SensCoolingRate,
1105 : OutputProcessor::SOVTimeStepType::System,
1106 : OutputProcessor::SOVStoreType::Average,
1107 158 : thisExchanger.Name);
1108 316 : SetupOutputVariable(state,
1109 : "Heat Exchanger Sensible Cooling Energy",
1110 : OutputProcessor::Unit::J,
1111 : thisExchanger.SensCoolingEnergy,
1112 : OutputProcessor::SOVTimeStepType::System,
1113 : OutputProcessor::SOVStoreType::Summed,
1114 158 : thisExchanger.Name);
1115 316 : SetupOutputVariable(state,
1116 : "Heat Exchanger Latent Cooling Rate",
1117 : OutputProcessor::Unit::W,
1118 : thisExchanger.LatCoolingRate,
1119 : OutputProcessor::SOVTimeStepType::System,
1120 : OutputProcessor::SOVStoreType::Average,
1121 158 : thisExchanger.Name);
1122 316 : SetupOutputVariable(state,
1123 : "Heat Exchanger Latent Cooling Energy",
1124 : OutputProcessor::Unit::J,
1125 : thisExchanger.LatCoolingEnergy,
1126 : OutputProcessor::SOVTimeStepType::System,
1127 : OutputProcessor::SOVStoreType::Summed,
1128 158 : thisExchanger.Name);
1129 316 : SetupOutputVariable(state,
1130 : "Heat Exchanger Total Cooling Rate",
1131 : OutputProcessor::Unit::W,
1132 : thisExchanger.TotCoolingRate,
1133 : OutputProcessor::SOVTimeStepType::System,
1134 : OutputProcessor::SOVStoreType::Average,
1135 158 : thisExchanger.Name);
1136 316 : SetupOutputVariable(state,
1137 : "Heat Exchanger Total Cooling Energy",
1138 : OutputProcessor::Unit::J,
1139 : thisExchanger.TotCoolingEnergy,
1140 : OutputProcessor::SOVTimeStepType::System,
1141 : OutputProcessor::SOVStoreType::Summed,
1142 : thisExchanger.Name,
1143 : _,
1144 : "ENERGYTRANSFER",
1145 : "HEAT RECOVERY FOR COOLING",
1146 : _,
1147 158 : "System");
1148 :
1149 316 : SetupOutputVariable(state,
1150 : "Heat Exchanger Electricity Rate",
1151 : OutputProcessor::Unit::W,
1152 : thisExchanger.ElecUseRate,
1153 : OutputProcessor::SOVTimeStepType::System,
1154 : OutputProcessor::SOVStoreType::Average,
1155 158 : thisExchanger.Name);
1156 316 : SetupOutputVariable(state,
1157 : "Heat Exchanger Electricity Energy",
1158 : OutputProcessor::Unit::J,
1159 : thisExchanger.ElecUseEnergy,
1160 : OutputProcessor::SOVTimeStepType::System,
1161 : OutputProcessor::SOVStoreType::Summed,
1162 : thisExchanger.Name,
1163 : _,
1164 : "ELECTRICITY",
1165 : "HEATRECOVERY",
1166 : _,
1167 158 : "System");
1168 : }
1169 :
1170 : // setup additional report variables for generic heat exchangers
1171 178 : for (int ExchIndex = 1; ExchIndex <= NumAirToAirGenericExchs; ++ExchIndex) {
1172 : // generic heat exchangers are read in after flat plate heat exchanger objects (index needs to be set correctly)
1173 : // CurrentModuleObject=HeatExchanger:AirToAir:SensibleAndLatent
1174 137 : int const ExchNum = ExchIndex + NumAirToAirPlateExchs;
1175 137 : auto &thisExchanger = state.dataHeatRecovery->ExchCond(ExchNum);
1176 274 : SetupOutputVariable(state,
1177 : "Heat Exchanger Sensible Effectiveness",
1178 : OutputProcessor::Unit::None,
1179 : thisExchanger.SensEffectiveness,
1180 : OutputProcessor::SOVTimeStepType::System,
1181 : OutputProcessor::SOVStoreType::Average,
1182 137 : thisExchanger.Name);
1183 274 : SetupOutputVariable(state,
1184 : "Heat Exchanger Latent Effectiveness",
1185 : OutputProcessor::Unit::None,
1186 : thisExchanger.LatEffectiveness,
1187 : OutputProcessor::SOVTimeStepType::System,
1188 : OutputProcessor::SOVStoreType::Average,
1189 137 : thisExchanger.Name);
1190 274 : SetupOutputVariable(state,
1191 : "Heat Exchanger Supply Air Bypass Mass Flow Rate",
1192 : OutputProcessor::Unit::kg_s,
1193 : thisExchanger.SupBypassMassFlow,
1194 : OutputProcessor::SOVTimeStepType::System,
1195 : OutputProcessor::SOVStoreType::Average,
1196 137 : thisExchanger.Name);
1197 274 : SetupOutputVariable(state,
1198 : "Heat Exchanger Exhaust Air Bypass Mass Flow Rate",
1199 : OutputProcessor::Unit::kg_s,
1200 : thisExchanger.SecBypassMassFlow,
1201 : OutputProcessor::SOVTimeStepType::System,
1202 : OutputProcessor::SOVStoreType::Average,
1203 137 : thisExchanger.Name);
1204 274 : SetupOutputVariable(state,
1205 : "Heat Exchanger Defrost Time Fraction",
1206 : OutputProcessor::Unit::None,
1207 : thisExchanger.DefrostFraction,
1208 : OutputProcessor::SOVTimeStepType::System,
1209 : OutputProcessor::SOVStoreType::Average,
1210 137 : thisExchanger.Name);
1211 : }
1212 :
1213 41 : if (ErrorsFound) {
1214 0 : ShowFatalError(state, format("{}Errors found in input. Program terminates.", RoutineName));
1215 : }
1216 41 : }
1217 :
1218 3964330 : void HeatExchCond::initialize(EnergyPlusData &state, int const CompanionCoilIndex, int const CompanionCoilType_Num)
1219 : {
1220 :
1221 : // SUBROUTINE INFORMATION:
1222 : // AUTHOR Michael Wetter
1223 : // DATE WRITTEN March 1999
1224 : // MODIFIED F Buhl Nov 2000, D Shirey Feb 2003
1225 : // B Griffith May 2009, EMS setpoint check
1226 : // RE-ENGINEERED na
1227 :
1228 : // PURPOSE OF THIS SUBROUTINE:
1229 : // This subroutine is for initializations of the Heat Recovery Components.
1230 :
1231 : // METHODOLOGY EMPLOYED:
1232 : // Uses the status flags to trigger initializations.
1233 :
1234 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1235 : Real64 CMin0; // minimum capacity flow
1236 : Real64 CMax0; // maximum capacity flow
1237 : Real64 Eps0; // effectiveness at rated conditions
1238 : Real64 NTU0; // NTU at rated conditions
1239 : Real64 RhoAir; // air density at outside pressure & standard temperature and humidity
1240 : Real64 CpAir; // heat capacity of air
1241 : // of humidity ratio and temperature
1242 : Real64 Z; // Min/max flow ratio
1243 :
1244 3964330 : if (!state.dataGlobal->SysSizingCalc && this->MySizeFlag) {
1245 158 : this->size(state);
1246 158 : this->MySizeFlag = false;
1247 : }
1248 :
1249 3964330 : bool FatalError = false;
1250 3964330 : bool LocalWarningError = false;
1251 :
1252 : // Do the Begin Environment initializations
1253 3964330 : if (state.dataGlobal->BeginEnvrnFlag && this->myEnvrnFlag) {
1254 : // I believe that all of these initializations should be taking place at the SCFM conditions
1255 1040 : RhoAir = state.dataEnvrn->StdRhoAir;
1256 : // RhoAir = PsyRhoAirFnPbTdbW(101325.0,20.0,0.0) do we want standard air density at sea level for generic ERVs per ARI 1060?
1257 1040 : CpAir = Psychrometrics::PsyCpAirFnW(0.0);
1258 :
1259 1040 : CalculateNTUBoundsErrors ErrStat = CalculateNTUBoundsErrors::NoError;
1260 1040 : switch (this->ExchType) {
1261 81 : case DataHVACGlobals::HX_AIRTOAIR_FLATPLATE:
1262 81 : this->NomSupAirMassFlow = RhoAir * this->NomSupAirVolFlow;
1263 81 : this->NomSecAirMassFlow = RhoAir * this->NomSecAirVolFlow;
1264 : // Note: the capacity stream is here simply the mass flow
1265 : // since the thermal capacity can be assumed to be
1266 : // equal for both streams
1267 81 : if (this->NomSupAirMassFlow > this->NomSecAirMassFlow) {
1268 6 : CMin0 = this->NomSecAirMassFlow;
1269 6 : CMax0 = this->NomSupAirMassFlow;
1270 : } else {
1271 75 : CMin0 = this->NomSupAirMassFlow;
1272 75 : CMax0 = this->NomSecAirMassFlow;
1273 : }
1274 :
1275 162 : Eps0 = this->NomSupAirMassFlow *
1276 81 : SafeDiv(this->NomSupAirOutTemp - this->NomSupAirInTemp, CMin0 * (this->NomSecAirInTemp - this->NomSupAirInTemp));
1277 81 : Z = CMin0 / CMax0;
1278 :
1279 81 : CalculateNTUfromEpsAndZ(state, NTU0, ErrStat, Z, this->FlowArr, Eps0);
1280 :
1281 81 : switch (ErrStat) {
1282 81 : case CalculateNTUBoundsErrors::NoError:
1283 81 : break; // great!
1284 0 : case CalculateNTUBoundsErrors::MassFlowRatio:
1285 0 : FatalError = true;
1286 0 : ShowSevereError(state, format("In the HeatExchanger:AirToAir:FlatPlate component {}", this->Name));
1287 0 : ShowContinueError(state, " the mass flow ratio is out of bounds");
1288 0 : ShowContinueError(state, format("The mass flow ratio is (Min_Mass_Flow_Rate / Max_Mass_Flow_Rate) = {:.2R}", Z));
1289 0 : ShowContinueError(state, "The mass flow ratio should be >= 0.0 and <= 1.0");
1290 0 : ShowContinueError(state,
1291 0 : format("Min_Mass_Flow_Rate = {:.2R} [air density] * {:.1R} [Min_Vol_Flow_Rate]",
1292 : RhoAir,
1293 0 : min(this->NomSupAirVolFlow, this->NomSecAirVolFlow)));
1294 0 : ShowContinueError(state,
1295 0 : format("Max_Mass_Flow_Rate = {:.2R} [air density] * {:.1R} [Max_Vol_Flow_Rate]",
1296 : RhoAir,
1297 0 : max(this->NomSupAirVolFlow, this->NomSecAirVolFlow)));
1298 0 : break;
1299 0 : case CalculateNTUBoundsErrors::NominalEffectiveness1:
1300 0 : FatalError = true;
1301 0 : ShowSevereError(state, format("In the HeatExchanger:AirToAir:FlatPlate component {}", this->Name));
1302 0 : ShowContinueError(state, " the calculated nominal effectiveness is out of bounds");
1303 0 : ShowContinueError(state, format("The effectiveness is {:.3R}", Eps0));
1304 0 : ShowContinueError(state, format("The effectiveness should be >= 0.0 and <= {:.3R}", 1.0 / (1.0 + Z)));
1305 0 : ShowContinueError(state,
1306 : "Eff = (Nom_Sup_Mass_Flow_Rate/Min_Mass_Flow_Rate)*(T_nom_sup_out-T_nom_sup_in)/(T_nom_sec_in-T_nom_sup_in)");
1307 0 : ShowContinueError(state, "The temperatures are user inputs. The mass flow rates are user input volume flow rates");
1308 0 : ShowContinueError(state, format(" times the density of air [{:.2R} kg/m3]", RhoAir));
1309 0 : ShowContinueError(state, "Change these inputs to obtain a physically realizable heat exchanger effectiveness");
1310 0 : break;
1311 0 : case CalculateNTUBoundsErrors::NominalEffectiveness2:
1312 0 : FatalError = true;
1313 0 : ShowSevereError(state, format("In the HeatExchanger:AirToAir:FlatPlate component {}", this->Name));
1314 0 : ShowContinueError(state, " the calculated nominal effectiveness is out of bounds");
1315 0 : ShowContinueError(state, format("The effectiveness is {:.3R}", Eps0));
1316 0 : ShowContinueError(state, format("The effectiveness should be >= 0.0 and <= {:.3R}", (1.0 - std::exp(-Z)) / Z));
1317 0 : ShowContinueError(state,
1318 : "Eff = (Nom_Sup_Mass_Flow_Rate/Min_Mass_Flow_Rate)*(T_nom_sup_out-T_nom_sup_in)/(T_nom_sec_in-T_nom_sup_in)");
1319 0 : ShowContinueError(state, "The temperatures are user inputs. The mass flow rates are user input volume flow rates");
1320 0 : ShowContinueError(state, format(" times the density of air [{:.2R} kg/m3]", RhoAir));
1321 0 : ShowContinueError(state, "Change these inputs to obtain a physically realizable heat exchanger effectiveness");
1322 0 : break;
1323 0 : case CalculateNTUBoundsErrors::Quantity:
1324 0 : FatalError = true;
1325 0 : ShowSevereError(state, format("In the HeatExchanger:AirToAir:FlatPlate component {}", this->Name));
1326 0 : ShowContinueError(state, " the quantity Eff_nom*(Min_Mass_Flow_Rate / Max_Mass_Flow_Rate) is out of bounds");
1327 0 : ShowContinueError(state, format("The value is {:.3R}", Eps0 * Z));
1328 0 : ShowContinueError(state, format("The value should be >= 0.0 and <= {:.3R}", 1.0 - std::exp(Z * (SMALL - 1.0))));
1329 0 : ShowContinueError(
1330 : state,
1331 : "Eff_nom = (Nom_Sup_Mass_Flow_Rate/Min_Mass_Flow_Rate) * (T_nom_sup_out - T_nom_sup_in)/(T_nom_sec_in - T_nom_sup_in)");
1332 0 : ShowContinueError(state, "The temperatures are user inputs. The mass flow rates are user input volume flow rates");
1333 0 : ShowContinueError(state, format(" times the density of air [{:.2R} kg/m3]", RhoAir));
1334 0 : ShowContinueError(state,
1335 : "Change these inputs to obtain a physically realizable product of effectiveness times min/max mass ratio "
1336 : "for this heat exchanger");
1337 0 : break;
1338 0 : case CalculateNTUBoundsErrors::NominalEffectiveness3:
1339 0 : FatalError = true;
1340 0 : ShowSevereError(state, format("In the HeatExchanger:AirToAir:FlatPlate component {}", this->Name));
1341 0 : ShowContinueError(state, " the calculated nominal effectiveness is out of bounds");
1342 0 : ShowContinueError(state, format("The effectiveness is {:.3R}", Eps0));
1343 0 : ShowContinueError(state, "The effectiveness should be >= 0.0 and <= 1.0");
1344 0 : ShowContinueError(state,
1345 : "Eff = (Nom_Sup_Mass_Flow_Rate/Min_Mass_Flow_Rate)*(T_nom_sup_out-T_nom_sup_in)/(T_nom_sec_in-T_nom_sup_in)");
1346 0 : ShowContinueError(state, "The temperatures are user inputs. The mass flow rates are user input volume flow rates");
1347 0 : ShowContinueError(state, format(" times the density of air [{:.2R} kg/m3]", RhoAir));
1348 0 : ShowContinueError(state, "Change these inputs to obtain a physically realizable heat exchanger effectiveness");
1349 0 : break;
1350 0 : case CalculateNTUBoundsErrors::Invalid:
1351 : case CalculateNTUBoundsErrors::Num:
1352 0 : break; // function won't actually return ::Invalid or ::Num, this is just so the compiler doesn't complain about the missing cases
1353 : }
1354 :
1355 81 : if (FatalError) {
1356 0 : ShowFatalError(state, "Heat exchanger design calculation caused fatal error: program terminated.");
1357 : }
1358 :
1359 81 : this->UA0 = NTU0 * CMin0 * CpAir;
1360 81 : this->mTSup0 = this->NomSupAirMassFlow * (this->NomSupAirInTemp + KELVZERO);
1361 81 : this->mTSec0 = this->NomSecAirMassFlow * (this->NomSecAirInTemp + KELVZERO);
1362 :
1363 : // check validity
1364 81 : if (this->NomSupAirMassFlow * this->NomSecAirMassFlow < DataHVACGlobals::SmallMassFlow * DataHVACGlobals::SmallMassFlow) {
1365 0 : ShowFatalError(state, "Mass flow in HeatExchanger:AirToAir:FlatPlate too small in initialization.");
1366 : }
1367 :
1368 81 : if (this->mTSup0 < DataHVACGlobals::SmallMassFlow) {
1369 0 : ShowFatalError(state, "(m*T)Sup,in in HeatExchanger:AirToAir:FlatPlate too small in initialization.");
1370 : }
1371 :
1372 81 : if (this->mTSec0 < DataHVACGlobals::SmallMassFlow) {
1373 0 : ShowFatalError(state, "(m*T)Sec,in in HeatExchanger:AirToAir:FlatPlate too small in initialization.");
1374 : }
1375 :
1376 81 : if (CMin0 < DataHVACGlobals::SmallMassFlow) {
1377 0 : ShowFatalError(state, "CMin0 in HeatExchanger:AirToAir:FlatPlate too small in initialization.");
1378 : }
1379 81 : break;
1380 :
1381 923 : case DataHVACGlobals::HX_AIRTOAIR_GENERIC:
1382 923 : if (this->SupOutletNode > 0 && this->ControlToTemperatureSetPoint) {
1383 110 : if (state.dataLoopNodes->Node(this->SupOutletNode).TempSetPoint == DataLoopNode::SensedNodeFlagValue) {
1384 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
1385 0 : ShowSevereError(
1386 0 : state, format("Missing temperature setpoint for {} \"{}\" :", DataHVACGlobals::cHXTypes(this->ExchType), this->Name));
1387 0 : ShowContinueError(
1388 : state, " use a Setpoint Manager to establish a setpoint at the supply air outlet node of the Heat Exchanger.");
1389 0 : ShowFatalError(state, " Previous condition causes program termination.");
1390 : } else {
1391 : // need call to EMS to check node
1392 0 : CheckIfNodeSetPointManagedByEMS(state, this->SupOutletNode, EMSManager::SPControlType::TemperatureSetPoint, FatalError);
1393 0 : if (FatalError) {
1394 0 : ShowSevereError(
1395 : state,
1396 0 : format("Missing temperature setpoint for {} \"{}\" :", DataHVACGlobals::cHXTypes(this->ExchType), this->Name));
1397 0 : ShowContinueError(
1398 : state, " use a Setpoint Manager to establish a setpoint at the supply air outlet node of the Heat Exchanger.");
1399 0 : ShowContinueError(
1400 : state, " or use an EMS actuator to establish a setpoint at the supply air outlet node of the Heat Exchanger.");
1401 0 : ShowFatalError(state, " Previous condition causes program termination.");
1402 : }
1403 : }
1404 : }
1405 : }
1406 923 : break;
1407 :
1408 36 : default:
1409 : // nothing
1410 36 : break;
1411 : }
1412 :
1413 1040 : this->myEnvrnFlag = false;
1414 : }
1415 :
1416 3964330 : if (!state.dataGlobal->BeginEnvrnFlag) {
1417 3947996 : this->myEnvrnFlag = true;
1418 : }
1419 :
1420 : // Do these initializations every time step
1421 3964330 : int const SupInNode = this->SupInletNode;
1422 3964330 : int const SecInNode = this->SecInletNode;
1423 :
1424 : // Get information from inlet nodes
1425 :
1426 3964330 : this->SupInTemp = state.dataLoopNodes->Node(SupInNode).Temp;
1427 3964330 : this->SupInHumRat = state.dataLoopNodes->Node(SupInNode).HumRat;
1428 3964330 : this->SupInEnth = state.dataLoopNodes->Node(SupInNode).Enthalpy;
1429 3964330 : this->SupInMassFlow = state.dataLoopNodes->Node(SupInNode).MassFlowRate;
1430 3964330 : this->SecInTemp = state.dataLoopNodes->Node(SecInNode).Temp;
1431 3964330 : this->SecInHumRat = state.dataLoopNodes->Node(SecInNode).HumRat;
1432 3964330 : this->SecInEnth = state.dataLoopNodes->Node(SecInNode).Enthalpy;
1433 3964330 : this->SecInMassFlow = state.dataLoopNodes->Node(SecInNode).MassFlowRate;
1434 :
1435 : // initialize the output variables
1436 3964330 : this->SensHeatingRate = 0.0;
1437 3964330 : this->SensHeatingEnergy = 0.0;
1438 3964330 : this->LatHeatingRate = 0.0;
1439 3964330 : this->LatHeatingEnergy = 0.0;
1440 3964330 : this->TotHeatingRate = 0.0;
1441 3964330 : this->TotHeatingEnergy = 0.0;
1442 3964330 : this->SensCoolingRate = 0.0;
1443 3964330 : this->SensCoolingEnergy = 0.0;
1444 3964330 : this->LatCoolingRate = 0.0;
1445 3964330 : this->LatCoolingEnergy = 0.0;
1446 3964330 : this->TotCoolingRate = 0.0;
1447 3964330 : this->TotCoolingEnergy = 0.0;
1448 3964330 : this->ElecUseRate = 0.0;
1449 3964330 : this->ElecUseEnergy = 0.0;
1450 3964330 : this->SensEffectiveness = 0.0;
1451 3964330 : this->LatEffectiveness = 0.0;
1452 3964330 : this->SupBypassMassFlow = 0.0;
1453 3964330 : this->SecBypassMassFlow = 0.0;
1454 :
1455 : // Initialize inlet conditions
1456 :
1457 3964330 : switch (this->ExchType) {
1458 3292335 : case DataHVACGlobals::HX_AIRTOAIR_FLATPLATE:
1459 : case DataHVACGlobals::HX_AIRTOAIR_GENERIC:
1460 3292335 : break;
1461 :
1462 671995 : case DataHVACGlobals::HX_DESICCANT_BALANCED:
1463 671995 : if (this->MySetPointTest) {
1464 61 : if (!state.dataGlobal->SysSizingCalc && state.dataHVACGlobal->DoSetPointTest) {
1465 7 : if (!state.dataHeatRecovery->CalledFromParentObject) {
1466 0 : if (state.dataLoopNodes->Node(this->SecOutletNode).HumRatMax == DataLoopNode::SensedNodeFlagValue) {
1467 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
1468 0 : ShowWarningError(state,
1469 0 : format("Missing optional HumRatMax setpoint for {} \"{}\"",
1470 : DataHVACGlobals::cHXTypes(this->ExchType),
1471 0 : this->Name));
1472 0 : ShowContinueError(state,
1473 : "...the simulation will continue without control of the desiccant heat exchanger to a maximum "
1474 : "humidity ratio setpoint.");
1475 0 : ShowContinueError(state,
1476 : "...use a Setpoint Manager to establish a setpoint at the process air outlet node of the "
1477 : "desiccant Heat Exchanger if control is desired.");
1478 : } else {
1479 : // need call to EMS to check node
1480 0 : CheckIfNodeSetPointManagedByEMS(
1481 : state, this->SecOutletNode, EMSManager::SPControlType::HumidityRatioMaxSetPoint, LocalWarningError);
1482 0 : state.dataLoopNodes->NodeSetpointCheck(this->SecOutletNode).needsSetpointChecking = false;
1483 0 : if (LocalWarningError) {
1484 0 : ShowWarningError(state,
1485 0 : format("Missing optional HumRatMax setpoint for {} \"{}\"",
1486 : DataHVACGlobals::cHXTypes(this->ExchType),
1487 0 : this->Name));
1488 0 : ShowContinueError(state,
1489 : "...the simulation will continue without control of the desiccant heat exchanger to a "
1490 : "maximum humidity ratio setpoint.");
1491 0 : ShowContinueError(state,
1492 : "...use a Setpoint Manager to establish a setpoint at the process air outlet node of the "
1493 : "desiccant Heat Exchanger if control is desired.");
1494 0 : ShowContinueError(state,
1495 : "...or use an EMS Actuator to establish a maximum humidity ratio setpoint at the process "
1496 : "air outlet node of the desiccant Heat Exchanger if control is desired.");
1497 : }
1498 : }
1499 : }
1500 : }
1501 7 : this->MySetPointTest = false;
1502 : }
1503 : }
1504 :
1505 671995 : if ((((CompanionCoilType_Num == DataHVACGlobals::CoilDX_CoolingSingleSpeed) ||
1506 446766 : (CompanionCoilType_Num == DataHVACGlobals::Coil_CoolingAirToAirVariableSpeed)) &&
1507 225229 : (CompanionCoilIndex > 0)) ||
1508 59860 : ((CompanionCoilType_Num == DataHVACGlobals::CoilDX_Cooling) && (CompanionCoilIndex > -1))) {
1509 :
1510 1013252 : if (CompanionCoilType_Num == DataHVACGlobals::CoilDX_CoolingSingleSpeed ||
1511 : CompanionCoilType_Num == DataHVACGlobals::CoilDX_CoolingTwoStageWHumControl) {
1512 997297 : if (state.dataDXCoils->DXCoilFullLoadOutAirTemp(CompanionCoilIndex) == 0.0 ||
1513 117205 : state.dataDXCoils->DXCoilFullLoadOutAirHumRat(CompanionCoilIndex) == 0.0) {
1514 : // DX Coil is OFF, read actual inlet conditions
1515 322841 : state.dataHeatRecovery->FullLoadOutAirTemp = this->SecInTemp;
1516 322841 : state.dataHeatRecovery->FullLoadOutAirHumRat = this->SecInHumRat;
1517 : } else {
1518 : // DX Coil is ON, read full load DX coil outlet conditions (conditions HX sees when ON)
1519 117205 : state.dataHeatRecovery->FullLoadOutAirTemp = state.dataDXCoils->DXCoilFullLoadOutAirTemp(CompanionCoilIndex);
1520 117205 : state.dataHeatRecovery->FullLoadOutAirHumRat = state.dataDXCoils->DXCoilFullLoadOutAirHumRat(CompanionCoilIndex);
1521 : }
1522 66580 : } else if (CompanionCoilType_Num == DataHVACGlobals::Coil_CoolingAirToAirVariableSpeed) {
1523 : // how to support VS dx coil here?
1524 6720 : state.dataHeatRecovery->FullLoadOutAirTemp = state.dataVariableSpeedCoils->VarSpeedCoil(CompanionCoilIndex).OutletAirDBTemp;
1525 6720 : state.dataHeatRecovery->FullLoadOutAirHumRat = state.dataVariableSpeedCoils->VarSpeedCoil(CompanionCoilIndex).OutletAirHumRat;
1526 59860 : } else if (CompanionCoilType_Num == DataHVACGlobals::CoilDX_Cooling) {
1527 : // Use the new coil option:
1528 59860 : state.dataHeatRecovery->FullLoadOutAirTemp = state.dataCoilCooingDX->coilCoolingDXs[CompanionCoilIndex].outletAirDryBulbTemp;
1529 59860 : state.dataHeatRecovery->FullLoadOutAirHumRat = state.dataCoilCooingDX->coilCoolingDXs[CompanionCoilIndex].outletAirHumRat;
1530 : } else {
1531 : //
1532 : }
1533 :
1534 : } else {
1535 :
1536 : // HX only (not used in conjunction with DX coil), read inlet conditions
1537 165369 : state.dataHeatRecovery->FullLoadOutAirTemp = this->SecInTemp;
1538 165369 : state.dataHeatRecovery->FullLoadOutAirHumRat = this->SecInHumRat;
1539 : }
1540 671995 : break;
1541 :
1542 0 : default:
1543 : // Will never get here
1544 0 : break;
1545 : }
1546 3964330 : }
1547 :
1548 158 : void HeatExchCond::size(EnergyPlusData &state)
1549 : {
1550 :
1551 : // SUBROUTINE INFORMATION:
1552 : // AUTHOR Richard Raustad
1553 : // DATE WRITTEN October 2007
1554 : // MODIFIED February 2014 Daeho Kang, enable sizing multiple HX types and add additional sizing fields
1555 : // RE-ENGINEERED na
1556 :
1557 : // PURPOSE OF THIS SUBROUTINE:
1558 : // This subroutine is for sizing Heat Exchanger components for which flow rates have not been
1559 : // specified in the input. Currently, only nominal supply air flow rate for the generic HX can be autosized.
1560 :
1561 : // METHODOLOGY EMPLOYED:
1562 : // Obtains flow rates from the system or OA system sizing arrays
1563 :
1564 : // SUBROUTINE PARAMETER DEFINITIONS:
1565 158 : constexpr const char *RoutineName("SizeHeatRecovery");
1566 :
1567 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1568 316 : std::string SizingString; // input field sizing description
1569 :
1570 158 : auto &ZoneEqSizing(state.dataSize->ZoneEqSizing);
1571 :
1572 158 : state.dataSize->HRFlowSizingFlag = true;
1573 158 : bool PrintFlag = true; // true when sizing information is reported in the eio file
1574 158 : int FieldNum = 0; // IDD numeric field index where input field description is found
1575 158 : switch (this->ExchType) {
1576 7 : case DataHVACGlobals::HX_DESICCANT_BALANCED:
1577 7 : PrintFlag = false;
1578 7 : break;
1579 137 : case DataHVACGlobals::HX_AIRTOAIR_GENERIC:
1580 137 : FieldNum = 1;
1581 137 : break;
1582 14 : case DataHVACGlobals::HX_AIRTOAIR_FLATPLATE:
1583 14 : FieldNum = 2;
1584 14 : break;
1585 0 : default:
1586 0 : assert(0);
1587 : }
1588 :
1589 316 : std::string CompName = this->Name;
1590 316 : std::string CompType = DataHVACGlobals::cHXTypes(this->ExchType);
1591 158 : if (FieldNum > 0) {
1592 151 : SizingString = this->NumericFieldNames(FieldNum) + " [m3/s]";
1593 : } else {
1594 7 : SizingString = "Nominal Supply Air Flow Rate [m3/s]"; // desiccant balanced flow does not have an input for air volume flow rate
1595 : }
1596 158 : if (state.dataSize->CurZoneEqNum > 0) {
1597 118 : if (this->NomSupAirVolFlow == DataSizing::AutoSize) {
1598 104 : if (ZoneEqSizing(state.dataSize->CurZoneEqNum).DesignSizeFromParent) {
1599 : // Heat recovery heat exchanger in zoneHVAC equipment should have been sized to OA flow in the parent equipment
1600 102 : state.dataSize->DataConstantUsedForSizing = ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow;
1601 : } else {
1602 2 : state.dataSize->DataConstantUsedForSizing =
1603 4 : std::max(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow,
1604 4 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow);
1605 : }
1606 104 : state.dataSize->DataFractionUsedForSizing = 1.0;
1607 : } else {
1608 14 : if (state.dataSize->ZoneSizingRunDone) {
1609 11 : if (ZoneEqSizing(state.dataSize->CurZoneEqNum).DesignSizeFromParent) {
1610 : // Heat recovery heat exchanger in zoneHVAC equipment should have been sized to OA flow in the parent equipment
1611 2 : state.dataSize->DataConstantUsedForSizing = ZoneEqSizing(state.dataSize->CurZoneEqNum).AirVolFlow;
1612 : } else {
1613 9 : state.dataSize->DataConstantUsedForSizing =
1614 18 : std::max(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow,
1615 18 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow);
1616 : }
1617 11 : state.dataSize->DataFractionUsedForSizing = 1.0;
1618 : }
1619 : }
1620 : }
1621 158 : Real64 TempSize = this->NomSupAirVolFlow;
1622 158 : bool errorsFound = false;
1623 316 : SystemAirFlowSizer sizerSystemAirFlow;
1624 158 : sizerSystemAirFlow.overrideSizingString(SizingString);
1625 : // sizerSystemAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1626 158 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1627 158 : this->NomSupAirVolFlow = sizerSystemAirFlow.size(state, TempSize, errorsFound);
1628 158 : state.dataSize->DataConstantUsedForSizing = 0.0;
1629 158 : state.dataSize->DataFractionUsedForSizing = 0.0;
1630 158 : if (this->ExchType == DataHVACGlobals::HX_AIRTOAIR_FLATPLATE) {
1631 14 : PrintFlag = true;
1632 14 : FieldNum = 5;
1633 14 : CompName = this->Name;
1634 14 : CompType = DataHVACGlobals::cHXTypes(this->ExchType);
1635 14 : SizingString = this->NumericFieldNames(FieldNum) + " [m3/s]";
1636 14 : if (this->NomSecAirVolFlow == DataSizing::AutoSize) {
1637 0 : state.dataSize->DataConstantUsedForSizing = this->NomSupAirVolFlow;
1638 0 : state.dataSize->DataFractionUsedForSizing = 1.0;
1639 : } else {
1640 14 : if (state.dataSize->ZoneSizingRunDone || state.dataSize->SysSizingRunDone) {
1641 9 : state.dataSize->DataConstantUsedForSizing = this->NomSupAirVolFlow;
1642 9 : state.dataSize->DataFractionUsedForSizing = 1.0;
1643 : }
1644 : }
1645 14 : TempSize = this->NomSecAirVolFlow;
1646 14 : bool errorsFound2 = false;
1647 28 : SystemAirFlowSizer sizerSystemAirFlow2;
1648 14 : sizerSystemAirFlow2.overrideSizingString(SizingString);
1649 : // sizerSystemAirFlow2.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1650 14 : sizerSystemAirFlow2.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1651 14 : this->NomSecAirVolFlow = sizerSystemAirFlow2.size(state, TempSize, errorsFound2);
1652 14 : state.dataSize->DataConstantUsedForSizing = 0.0;
1653 14 : state.dataSize->DataFractionUsedForSizing = 0.0;
1654 : }
1655 158 : state.dataSize->HRFlowSizingFlag = false;
1656 158 : if (this->ExchType == DataHVACGlobals::HX_DESICCANT_BALANCED) {
1657 :
1658 7 : int const BalDesDehumPerfIndex = this->PerfDataIndex; // index of dehum performance data1 object
1659 :
1660 7 : FieldNum = 1;
1661 7 : PrintFlag = true;
1662 7 : CompName = state.dataHeatRecovery->BalDesDehumPerfData(BalDesDehumPerfIndex).Name;
1663 7 : CompType = state.dataHeatRecovery->BalDesDehumPerfData(BalDesDehumPerfIndex).PerfType;
1664 7 : SizingString = state.dataHeatRecovery->BalDesDehumPerfData(BalDesDehumPerfIndex).NumericFieldNames(FieldNum) + " [m3/s]";
1665 7 : TempSize = state.dataHeatRecovery->BalDesDehumPerfData(BalDesDehumPerfIndex).NomSupAirVolFlow;
1666 7 : bool errorsFound2 = false;
1667 14 : SystemAirFlowSizer sizerSystemAirFlow3;
1668 7 : sizerSystemAirFlow3.overrideSizingString(SizingString);
1669 : // sizerSystemAirFlow3.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
1670 7 : sizerSystemAirFlow3.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1671 7 : state.dataHeatRecovery->BalDesDehumPerfData(BalDesDehumPerfIndex).NomSupAirVolFlow =
1672 7 : sizerSystemAirFlow3.size(state, TempSize, errorsFound2);
1673 :
1674 7 : state.dataSize->DataAirFlowUsedForSizing = state.dataHeatRecovery->BalDesDehumPerfData(BalDesDehumPerfIndex).NomSupAirVolFlow;
1675 7 : TempSize = state.dataHeatRecovery->BalDesDehumPerfData(BalDesDehumPerfIndex).NomProcAirFaceVel;
1676 7 : bool errorsFound3 = false;
1677 14 : DesiccantDehumidifierBFPerfDataFaceVelocitySizer sizerDesDehumBFFaceVel;
1678 7 : sizerDesDehumBFFaceVel.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1679 7 : state.dataHeatRecovery->BalDesDehumPerfData(BalDesDehumPerfIndex).NomProcAirFaceVel =
1680 7 : sizerDesDehumBFFaceVel.size(state, TempSize, errorsFound3);
1681 :
1682 7 : state.dataSize->DataAirFlowUsedForSizing = 0.0;
1683 : }
1684 158 : }
1685 :
1686 758449 : void HeatExchCond::CalcAirToAirPlateHeatExch(EnergyPlusData &state,
1687 : bool const HXUnitOn, // flag to simulate heat exchager heat recovery
1688 : Optional_bool_const EconomizerFlag, // economizer flag pass by air loop or OA sys
1689 : Optional_bool_const HighHumCtrlFlag // high humidity control flag passed by airloop or OA sys
1690 : )
1691 : {
1692 :
1693 : // SUBROUTINE INFORMATION:
1694 : // AUTHOR Michael Wetter
1695 : // DATE WRITTEN March 1999
1696 : // MODIFIED F. Buhl Nov 2000, R. Raustad - FSEC, Feb 2009 - added economizer flags
1697 : // Both the economizer and high humidity control flags can disable the HX
1698 : // RE-ENGINEERED na
1699 :
1700 : // PURPOSE OF THIS SUBROUTINE:
1701 : // Calculate the outlet conditions for an air to air plate heat
1702 : // exchanger given the inlet conditions.
1703 :
1704 : // METHODOLOGY EMPLOYED:
1705 : // This is a static heat exchanger model. No geometrical input data
1706 : // is needed. No knowledge of h*A values is needed except the ratio
1707 : // of the primary side to the secondary side convective heat transfer
1708 : // coefficient times the exchanger surface area. Effectiveness - NTU
1709 : // heat exchanger formulas are used.
1710 :
1711 : // The time varying load is calculated based on the variation of the
1712 : // convective heat transfer coefficient.The variation is a function of
1713 : // mass flow rate and inlet temperature. An iterative solution is only
1714 : // required during initialization in one specific flow arrangement. During
1715 : // the time steps the solution is explicit. The iteration is done with
1716 : // the Regula Falsi algorithm. Convergence is always achieved.
1717 :
1718 : // REFERENCES:
1719 : // M. Wetter, Simulation Model Air-to-Air Plate Heat Exchanger
1720 : // LBNL Report 42354, 1999.
1721 :
1722 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1723 758449 : bool UnitOn = true; // unit on flag
1724 758449 : Real64 QTrans = 0.0; // heat transferred in the heat exchanger [W]
1725 758449 : Real64 ElecCons = 0.0; // electricity consumption rate [W]
1726 :
1727 758449 : bool EconomizerActiveFlag = present(EconomizerFlag) && bool(EconomizerFlag); // local representing the economizer status when PRESENT
1728 758449 : bool HighHumCtrlActiveFlag = present(HighHumCtrlFlag) && bool(HighHumCtrlFlag); // local representing high humidity control when PRESENT
1729 :
1730 : Real64 UnitSupMassFlow; // supply air mass flow rate passing through the unit [kg/s]
1731 : Real64 UnitSecMassFlow; // secondary air mass flow rate passing through the unit [kg/s]
1732 758449 : if ((EconomizerActiveFlag || HighHumCtrlActiveFlag) && this->EconoLockOut) {
1733 109827 : UnitSupMassFlow = 0.0; // set HX supply flow to 0, all supply air will go through supply bypass
1734 109827 : UnitSecMassFlow = 0.0; // set HX secondary flow to 0, all secondary air will got through secondary bypass
1735 109827 : UnitOn = false; // turn off HX calculations when in economizer mode
1736 : } else {
1737 : // if economizer operation is not allowed, air always passes through HX
1738 : // if CompanionCoilNum > 0, air always passes through HX (no economizer operation allowed)
1739 648622 : UnitSupMassFlow = min(this->NomSupAirMassFlow, this->SupInMassFlow);
1740 648622 : UnitSecMassFlow = min(this->NomSecAirMassFlow, this->SecInMassFlow);
1741 : }
1742 :
1743 758449 : if (ScheduleManager::GetCurrentScheduleValue(state, this->SchedPtr) <= 0.0) UnitOn = false;
1744 758449 : if (this->SupInMassFlow <= DataHVACGlobals::SmallMassFlow) UnitOn = false;
1745 758449 : if (this->SecInMassFlow <= DataHVACGlobals::SmallMassFlow) UnitOn = false;
1746 758449 : if (!HXUnitOn) UnitOn = false;
1747 :
1748 758449 : if (UnitOn) {
1749 : // unit is on
1750 : // calculate the UA for this time step
1751 : // ratio of supply nominal m*T to actual m*T
1752 576994 : Real64 const QuotSup = SafeDiv(this->mTSup0, UnitSupMassFlow * (this->SupInTemp + KELVZERO));
1753 : // ratio of secondary nominal m*T to actual m*T
1754 576994 : Real64 const QuotExh = SafeDiv(this->mTSec0, UnitSecMassFlow * (this->SecInTemp + KELVZERO));
1755 : // denominator of UA calculation
1756 576994 : Real64 const Deno = std::pow(QuotSup, 0.78) + this->hARatio * std::pow(QuotExh, 0.78);
1757 : // present UA
1758 576994 : Real64 const UA = this->UA0 * (this->hARatio + 1.0) / Deno;
1759 : // calculate the NTU
1760 576994 : Real64 const CSup = UnitSupMassFlow * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
1761 : // secondary air capacitance rate [J/C/s]
1762 576994 : Real64 const CSec = UnitSecMassFlow * Psychrometrics::PsyCpAirFnW(this->SecInHumRat);
1763 : // note: no C can be zero since otherwise we wouldn't be here
1764 : Real64 Z; // Ratio of minimum air capacitance rate to maximum air capacitance rate
1765 : Real64 CMin; // minimum air capacitance rate [J/C/s]
1766 576994 : if (CSup < CSec) {
1767 85524 : CMin = CSup;
1768 85524 : Z = CMin / CSec;
1769 : } else {
1770 491470 : CMin = CSec;
1771 491470 : Z = CMin / CSup;
1772 : }
1773 : // Number of heat transfer units
1774 576994 : Real64 const NTU = UA / CMin;
1775 : // Get the effectiveness
1776 576994 : Real64 Eps = CalculateEpsFromNTUandZ(state, NTU, Z, this->FlowArr);
1777 : // use the effectiveness to calculate the unit outlet conditions
1778 576994 : Real64 TempSupOut = this->SupInTemp + Eps * CMin / CSup * (this->SecInTemp - this->SupInTemp);
1779 576994 : QTrans = CSup * (TempSupOut - this->SupInTemp);
1780 : // unit secondary outlet temperature [C]
1781 576994 : Real64 TempSecOut = this->SecInTemp - QTrans / CSec;
1782 : // unit supply outlet humidity ratio [kg water / kg dry air]
1783 576994 : Real64 HumRatSupOut = this->SupInHumRat;
1784 : // unit supply outlet enthalpy [J/kg]
1785 576994 : Real64 const EnthSupOut = Psychrometrics::PsyHFnTdbW(TempSupOut, HumRatSupOut);
1786 : // check for saturation in supply outlet
1787 : // unit supply outlet temperature at saturation (at EnthSupOut) [C]
1788 576994 : Real64 const TempSupOutSat = Psychrometrics::PsyTsatFnHPb(state, EnthSupOut, state.dataEnvrn->OutBaroPress);
1789 576994 : if (TempSupOutSat > TempSupOut) {
1790 10134 : TempSupOut = TempSupOutSat;
1791 10134 : HumRatSupOut = Psychrometrics::PsyWFnTdbH(state, TempSupOut, EnthSupOut);
1792 : }
1793 : // unit secondary outlet humidity ratio [kg water / kg dry air]
1794 576994 : Real64 HumRatSecOut = this->SecInHumRat;
1795 : // unit secondary outlet enthalpy [J/kgC]
1796 576994 : Real64 const EnthSecOut = Psychrometrics::PsyHFnTdbW(TempSecOut, HumRatSecOut);
1797 : // check for saturation in secondary outlet
1798 : // unit secondary outlet temperature at saturation (at EnthsSecOut) [C]
1799 576994 : Real64 const TempSecOutSat = Psychrometrics::PsyTsatFnHPb(state, EnthSecOut, state.dataEnvrn->OutBaroPress);
1800 576994 : if (TempSecOutSat > TempSecOut) {
1801 20927 : TempSecOut = TempSecOutSat;
1802 20927 : HumRatSecOut = Psychrometrics::PsyWFnTdbH(state, TempSecOut, EnthSecOut);
1803 : }
1804 : // calculate outlet conditions by mixing bypass air stream with air that went through the
1805 : // heat exchanger core.
1806 576994 : Real64 local_SupBypassMassFlow = max(0.0, this->SupInMassFlow - UnitSupMassFlow); // supply air mass flow rate bypassing unit [kg/s]
1807 576994 : Real64 local_SecBypassMassFlow = max(0.0, this->SecInMassFlow - UnitSecMassFlow); // secondary air mass flow rate bypassing unit [kg/s]
1808 :
1809 576994 : this->SupOutEnth = (UnitSupMassFlow * EnthSupOut + local_SupBypassMassFlow * this->SupInEnth) / this->SupInMassFlow;
1810 576994 : this->SupOutHumRat = (UnitSupMassFlow * HumRatSupOut + local_SupBypassMassFlow * this->SupInHumRat) / this->SupInMassFlow;
1811 576994 : this->SupOutTemp = Psychrometrics::PsyTdbFnHW(this->SupOutEnth, this->SupOutHumRat);
1812 576994 : this->SupOutMassFlow = this->SupInMassFlow;
1813 576994 : this->SecOutEnth = (UnitSecMassFlow * EnthSecOut + local_SecBypassMassFlow * this->SecInEnth) / this->SecInMassFlow;
1814 576994 : this->SecOutHumRat = (UnitSecMassFlow * HumRatSecOut + local_SecBypassMassFlow * this->SecInHumRat) / this->SecInMassFlow;
1815 576994 : this->SecOutTemp = Psychrometrics::PsyTdbFnHW(this->SecOutEnth, this->SecOutHumRat);
1816 576994 : this->SecOutMassFlow = this->SecInMassFlow;
1817 576994 : ElecCons = this->NomElecPower;
1818 :
1819 : } else {
1820 : // the unit is off. Pass through the air streams with no change
1821 181455 : this->SupOutEnth = this->SupInEnth;
1822 181455 : this->SupOutHumRat = this->SupInHumRat;
1823 181455 : this->SupOutTemp = this->SupInTemp;
1824 181455 : this->SupOutMassFlow = this->SupInMassFlow;
1825 181455 : this->SecOutEnth = this->SecInEnth;
1826 181455 : this->SecOutHumRat = this->SecInHumRat;
1827 181455 : this->SecOutTemp = this->SecInTemp;
1828 181455 : this->SecOutMassFlow = this->SecInMassFlow;
1829 : }
1830 : // supply air capacitance rate [J/C/s]
1831 758449 : Real64 const CSup = this->SupInMassFlow * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
1832 : // sensible heat recovery rate to supply air (heating +, cooling -)
1833 758449 : Real64 const SensHeatRecRate = CSup * (this->SupOutTemp - this->SupInTemp);
1834 : // total heat recovery rate to supply air (heating +, cooling -)
1835 758449 : Real64 const TotHeatRecRate = this->SupOutMassFlow * (this->SupOutEnth - this->SupInEnth);
1836 : // latent heat recovery rate to supply air (heating [humidify] +, cooling [dehumidify] -)
1837 758449 : Real64 const LatHeatRecRate = TotHeatRecRate - SensHeatRecRate;
1838 :
1839 758449 : if (SensHeatRecRate > 0.0) {
1840 57575 : this->SensHeatingRate = SensHeatRecRate;
1841 57575 : this->SensCoolingRate = 0.0;
1842 : } else {
1843 700874 : this->SensHeatingRate = 0.0;
1844 700874 : this->SensCoolingRate = std::abs(SensHeatRecRate);
1845 : }
1846 758449 : if (LatHeatRecRate > 0.0) {
1847 214730 : this->LatHeatingRate = LatHeatRecRate;
1848 214730 : this->LatCoolingRate = 0.0;
1849 : } else {
1850 543719 : this->LatHeatingRate = 0.0;
1851 543719 : this->LatCoolingRate = std::abs(LatHeatRecRate);
1852 : }
1853 758449 : if (TotHeatRecRate > 0.0) {
1854 55622 : this->TotHeatingRate = TotHeatRecRate;
1855 55622 : this->TotCoolingRate = 0.0;
1856 : } else {
1857 702827 : this->TotHeatingRate = 0.0;
1858 702827 : this->TotCoolingRate = std::abs(TotHeatRecRate);
1859 : }
1860 :
1861 758449 : this->ElecUseRate = ElecCons;
1862 758449 : }
1863 :
1864 2533886 : void HeatExchCond::CalcAirToAirGenericHeatExch(EnergyPlusData &state,
1865 : bool const HXUnitOn, // flag to simulate heat exchanger heat recovery
1866 : bool const FirstHVACIteration, // first HVAC iteration flag
1867 : int const FanOpMode, // Supply air fan operating mode (1=cycling, 2=constant)
1868 : Optional_bool_const EconomizerFlag, // economizer flag pass by air loop or OA sys
1869 : Optional_bool_const HighHumCtrlFlag, // high humidity control flag passed by airloop or OA sys
1870 : Optional<Real64 const> HXPartLoadRatio //
1871 : )
1872 : {
1873 :
1874 : // SUBROUTINE INFORMATION:
1875 : // AUTHOR Don Shirey
1876 : // DATE WRITTEN February 2003
1877 : // MODIFIED R. Raustad - FSEC, Feb 2009 - added economizer flags
1878 : // Both the economizer and high humidity control flags can disable the HX
1879 : // RE-ENGINEERED Richard Raustad, June 2003
1880 :
1881 : // PURPOSE OF THIS SUBROUTINE:
1882 : // Calculate the outlet conditions for an air to air generic heat
1883 : // exchanger given the inlet conditions.
1884 :
1885 : // METHODOLOGY EMPLOYED:
1886 : // This is a standard heat exchanger effectiveness model. No geometrical input data
1887 : // is needed. The model uses heat exchanger effectiveness performance data
1888 : // to calculate the air temperature and humidity ratio of the leaving
1889 : // supply and secondary air streams. Linear interpolation (or extrapolation)
1890 : // is assumed to obtain heat exchanger effectiveness at off-rated conditions.
1891 : // Economizer operation is allowed through the use of a Controller: Outside Air
1892 : // object.
1893 :
1894 : // REFERENCES:
1895 : // ARI Standard 1060-2001,Rating Air-to-Air Heat Exchangers for Energy Recovery Ventilation Equipment, www.ari.org
1896 : // ASHRAE Standard 84, Method of Testing Air-To-Air Heat Exchangers, www.ashrae.org
1897 : // U.S. Environmental Protection Agency software "SAVES" -
1898 : // School Advanced Ventilation Engineering Software http://www.epa.gov/iaq/schooldesign/saves.html
1899 :
1900 : // SUBROUTINE PARAMETER DEFINITIONS:
1901 2533886 : Real64 constexpr ErrorTol(0.001); // error tolerence
1902 :
1903 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1904 : int SupOutNode;
1905 : Real64 Error; // iteration loop error variable
1906 : Real64 Iter; // iteration counter
1907 : Real64 ControlFraction; // fraction of effectiveness when rotary HX speed or plate bypass modulation is used for
1908 : // temperature control
1909 : Real64 RhoSup; // supply air density at actual pressure, temperature and humidity conditions [kg/m3]
1910 : Real64 RhoSec; // secondary air density at actual pressure, temperature and humidity conditions [kg/m3]
1911 : Real64 RhoStd; // standard air density at actual pressure, 20C dry-bulb temp and 0.0 absolute humidity [kg/m3]
1912 : Real64 CSup; // supply air heat capacity rate [W/K]
1913 : Real64 CSec; // secondary air heat capacity rate [W/K]
1914 : Real64 CMin; // minimum air heat capacity rate [W/K]
1915 : Real64 TempSecOutSat; // secondary air outlet temperature at saturation (at EnthsSecOut) [C]
1916 : Real64 HXSecAirVolFlowRate; // air volume flow rate of the secondary air stream through the heat exchanger [m3/sec]
1917 : Real64 HXSupAirVolFlowRate; // air volume flow rate of the supply air stream through the heat exchanger [m3/sec]
1918 : Real64 HXAvgAirVolFlowRate; // average air volume flow rate through the heat exchanger [m3/sec]
1919 : Real64 HXAirVolFlowRatio; // ratio of avg actual air volume flow through HX to nominal HX air volume flow [-]
1920 : Real64 HXTempSetPoint; // setpoint temperature at supply outlet node of HX when ControlToTemperatureSetPoint = Yes
1921 : Real64 MassFlowSecIn; // secondary air mass flow rate at HX inlet
1922 : // REAL(r64) :: MassFlowSecOut ! secondary air mass flow rate at HX outlet
1923 : Real64 MassFlowSupIn; // supply air mass flow rate at HX inlet
1924 : Real64 MassFlowSupOut; // supply air mass flow rate through HX core outlet
1925 : Real64 MassFlowSupBypass; // supply air bypass mass flow rate around HX core
1926 : Real64 TempSupIn; // supply side temperature of air entering HX
1927 : Real64 TempSupOut; // supply side temperature of air leaving HX core
1928 : Real64 HumRatSupIn; // supply side humidity ratio of air entering HX
1929 : Real64 TempSecIn; // secondary side temperature of air entering HX
1930 : Real64 SensHeatRecRate; // sensible heat recovery rate to supply air (heating +, cooling -)
1931 : Real64 LatHeatRecRate; // latent heat recovery rate to supply air (heating [humidify] +, cooling [dehumidify] -)
1932 : Real64 TotHeatRecRate; // total heat recovery rate to supply air (heating +, cooling -)
1933 : Real64 AirSidePLR;
1934 :
1935 : // Initialize local variables
1936 2533886 : bool UnitOn = true; // unit on flag
1937 2533886 : bool FrostControlFlag = false; // unit is in frost control mode when TRUE
1938 2533886 : Real64 QSensTrans = 0.0; // sensible heat transferred by the heat exchanger [W]
1939 2533886 : Real64 QTotTrans = 0.0; // total heat (sensible + latent) transferred by the heat exchanger [W]
1940 :
1941 2533886 : this->DefrostFraction = 0.0;
1942 2533886 : this->SensEffectiveness = 0.0;
1943 2533886 : this->LatEffectiveness = 0.0;
1944 2533886 : this->ElecUseRate = 0.0;
1945 2533886 : this->SupOutTemp = this->SupInTemp;
1946 2533886 : this->SecOutTemp = this->SecInTemp;
1947 2533886 : this->SupOutHumRat = this->SupInHumRat;
1948 2533886 : this->SecOutHumRat = this->SecInHumRat;
1949 2533886 : this->SupOutEnth = this->SupInEnth;
1950 2533886 : this->SecOutEnth = this->SecInEnth;
1951 2533886 : SupOutNode = this->SupOutletNode;
1952 2533886 : HXTempSetPoint = state.dataLoopNodes->Node(SupOutNode).TempSetPoint;
1953 :
1954 2533886 : bool EconomizerActiveFlag = present(EconomizerFlag) && bool(EconomizerFlag); // local representing the economizer status when PRESENT
1955 2533886 : bool HighHumCtrlActiveFlag = present(HighHumCtrlFlag) && bool(HighHumCtrlFlag); // local representing high humidity control when PRESENT
1956 :
1957 : // Determine mass flow through heat exchanger and mass flow being bypassed (only flat plate bypasses flow)
1958 2533886 : if (((EconomizerActiveFlag || HighHumCtrlActiveFlag) && this->EconoLockOut) && this->ExchConfig == HXConfigurationType::Plate) {
1959 2403 : this->SupBypassMassFlow = this->SupInMassFlow;
1960 2403 : this->SupOutMassFlow = this->SupInMassFlow;
1961 2403 : this->SecBypassMassFlow = this->SecInMassFlow;
1962 2403 : this->SecOutMassFlow = this->SecInMassFlow;
1963 : } else { // No bypass mass flow
1964 2531483 : this->SupOutMassFlow = this->SupInMassFlow;
1965 2531483 : this->SecOutMassFlow = this->SecInMassFlow;
1966 2531483 : this->SupBypassMassFlow = 0.0;
1967 2531483 : this->SecBypassMassFlow = 0.0;
1968 : }
1969 : // Unit is scheduled OFF, so bypass heat exchange calcs
1970 2533886 : if (ScheduleManager::GetCurrentScheduleValue(state, this->SchedPtr) <= 0.0) UnitOn = false;
1971 : //! Economizer is active, so bypass heat exchange calcs. This applies to both flat plate and rotary HX's
1972 2533886 : if ((EconomizerActiveFlag || HighHumCtrlActiveFlag) && this->EconoLockOut) {
1973 229763 : UnitOn = false;
1974 : }
1975 : // Determine if unit is ON or OFF based on air mass flow through the supply and secondary airstreams and operation flag
1976 2533886 : if (this->SupInMassFlow <= DataHVACGlobals::SmallMassFlow) UnitOn = false;
1977 2533886 : if (this->SecInMassFlow <= DataHVACGlobals::SmallMassFlow) UnitOn = false;
1978 2533886 : if (!HXUnitOn) UnitOn = false;
1979 2533886 : if (this->NomSupAirVolFlow == 0.0) UnitOn = false;
1980 :
1981 2533886 : if (UnitOn) {
1982 : // Unit is on.
1983 1658489 : if (present(HXPartLoadRatio) && FanOpMode == DataHVACGlobals::CycFanCycCoil) {
1984 0 : if (HXPartLoadRatio > 0) {
1985 0 : AirSidePLR = HXPartLoadRatio;
1986 : } else {
1987 0 : AirSidePLR = 1.0;
1988 : }
1989 : } else {
1990 1658489 : AirSidePLR = 1.0;
1991 : }
1992 :
1993 1658489 : if (FanOpMode == DataHVACGlobals::CycFanCycCoil) {
1994 0 : this->SupInMassFlow /= AirSidePLR;
1995 0 : this->SupOutMassFlow /= AirSidePLR;
1996 0 : this->SecInMassFlow /= AirSidePLR;
1997 0 : this->SecOutMassFlow /= AirSidePLR;
1998 0 : this->SupBypassMassFlow /= AirSidePLR;
1999 0 : this->SecBypassMassFlow /= AirSidePLR;
2000 : }
2001 :
2002 : // In the future, use actual node pressures in the following air density calls
2003 1658489 : RhoStd = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, 20.0, 0.0);
2004 1658489 : HXSupAirVolFlowRate = this->SupOutMassFlow / RhoStd; // volume flow using standard density
2005 1658489 : HXSecAirVolFlowRate = this->SecOutMassFlow / RhoStd;
2006 : // Limit unbalanced volumetric flow ratio to 2:1
2007 1658489 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
2008 108753 : if (HXSupAirVolFlowRate != 0.0 && HXSecAirVolFlowRate != 0.0) {
2009 108753 : if (((HXSupAirVolFlowRate / HXSecAirVolFlowRate) > 2.0) || ((HXSecAirVolFlowRate / HXSupAirVolFlowRate) > 2.0)) {
2010 0 : ++this->UnBalancedErrCount;
2011 0 : if (this->UnBalancedErrCount <= 2) {
2012 0 : ShowSevereError(state,
2013 0 : format("{}: \"{}\" unbalanced air volume flow ratio through the heat exchanger is greater than 2:1.",
2014 : DataHVACGlobals::cHXTypes(this->ExchType),
2015 0 : this->Name));
2016 0 : ShowContinueErrorTimeStamp(
2017 0 : state, format("...HX Supply air to Exhaust air flow ratio = {:.5R}.", HXSupAirVolFlowRate / HXSecAirVolFlowRate));
2018 : } else {
2019 0 : ShowRecurringWarningErrorAtEnd(
2020 : state,
2021 0 : format("{} \"{}\": Unbalanced air volume flow ratio exceeds 2:1 warning continues. HX flow ratio statistics follow.",
2022 : DataHVACGlobals::cHXTypes(this->ExchType),
2023 0 : this->Name),
2024 : this->UnBalancedErrIndex,
2025 0 : HXSupAirVolFlowRate / HXSecAirVolFlowRate,
2026 0 : HXSupAirVolFlowRate / HXSecAirVolFlowRate);
2027 : }
2028 : }
2029 : }
2030 : }
2031 : // Calculate average volumetric flow rate of the two air streams
2032 1658489 : HXAvgAirVolFlowRate = (HXSecAirVolFlowRate + HXSupAirVolFlowRate) / 2.0;
2033 1658489 : HXAirVolFlowRatio = HXAvgAirVolFlowRate / this->NomSupAirVolFlow;
2034 : // Average air volume flow rate must be between 50% and 130% of nominal supply air volume flow
2035 1658489 : if (HXAirVolFlowRatio > 1.3 || HXAirVolFlowRatio < 0.5) {
2036 93825 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
2037 13194 : ++this->LowFlowErrCount;
2038 13194 : if (this->LowFlowErrCount == 1) {
2039 8 : ShowWarningError(state, format("{} \"{}\"", DataHVACGlobals::cHXTypes(this->ExchType), this->Name));
2040 8 : ShowContinueError(state, "Average air volume flow rate is <50% or >130% of the nominal HX supply air volume flow rate.");
2041 8 : ShowContinueErrorTimeStamp(state, format("Air volume flow rate ratio = {:.3R}.", HXAirVolFlowRatio));
2042 : } else {
2043 39558 : ShowRecurringWarningErrorAtEnd(
2044 : state,
2045 39558 : format(
2046 : "{} \"{}\": Average air volume flow rate is <50% or >130% warning continues. Air flow rate ratio statistics follow.",
2047 : DataHVACGlobals::cHXTypes(this->ExchType),
2048 13186 : this->Name),
2049 : this->LowFlowErrIndex,
2050 : HXAirVolFlowRatio,
2051 : HXAirVolFlowRatio);
2052 : }
2053 : }
2054 : }
2055 :
2056 : // Determine heat exchanger effectiveness using avg air volume flow rate based on actual inlet air density
2057 : // Linearly interpolate and extrapolate (within limits) from effectiveness input values
2058 1658489 : RhoSup = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->SupInTemp, this->SupInHumRat);
2059 1658489 : RhoSec = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->SecInTemp, this->SecInHumRat);
2060 1658489 : HXSupAirVolFlowRate = this->SupOutMassFlow / RhoSup;
2061 1658489 : HXSecAirVolFlowRate = this->SecOutMassFlow / RhoSec;
2062 1658489 : HXAvgAirVolFlowRate = (HXSecAirVolFlowRate + HXSupAirVolFlowRate) / 2.0;
2063 1658489 : HXAirVolFlowRatio = HXAvgAirVolFlowRate / this->NomSupAirVolFlow;
2064 :
2065 1658489 : if (this->SupInTemp < this->SecInTemp) {
2066 : // Use heating effectiveness values
2067 1602520 : this->SensEffectiveness = this->HeatEffectSensible75 +
2068 801260 : (this->HeatEffectSensible100 - this->HeatEffectSensible75) * (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2069 801260 : this->LatEffectiveness =
2070 801260 : this->HeatEffectLatent75 + (this->HeatEffectLatent100 - this->HeatEffectLatent75) * (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2071 : } else {
2072 : // Use cooling effectiveness values
2073 1714458 : this->SensEffectiveness = this->CoolEffectSensible75 +
2074 857229 : (this->CoolEffectSensible100 - this->CoolEffectSensible75) * (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2075 857229 : this->LatEffectiveness =
2076 857229 : this->CoolEffectLatent75 + (this->CoolEffectLatent100 - this->CoolEffectLatent75) * (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2077 : }
2078 :
2079 : // Keep effectiveness between 0 and 1.0 ??
2080 : // HXOpSensEffect = MAX(MIN(HXOpSensEffect,1.0),0.0)
2081 : // HXOpLatEffect = MAX(MIN(HXOpLatEffect,1.0),0.0)
2082 1658489 : if (this->SensEffectiveness < 0.0) {
2083 : // The model should at least guard against negative numbers
2084 0 : this->SensEffectiveness = 0.0;
2085 0 : if (!this->SensEffectivenessFlag) {
2086 0 : ShowWarningError(
2087 : state,
2088 0 : format(
2089 : "HeatExchanger:AirToAir:SensibleAndLatent =\"{}\" sensible effectiveness is less than zero. Check the following inputs.",
2090 0 : this->Name));
2091 0 : if (this->SupInTemp < this->SecInTemp) {
2092 0 : ShowContinueError(state, format("...Sensible Effectiveness at 100% Heating Air Flow = {:.2R}", this->HeatEffectSensible100));
2093 0 : ShowContinueError(state, format("...Sensible Effectiveness at 75% Heating Air Flow = {:.2R}", this->HeatEffectSensible75));
2094 0 : ShowContinueError(state, "...Sensible effectiveness reset to zero and the simulation continues.");
2095 : } else {
2096 0 : ShowContinueError(state, format("...Sensible Effectiveness at 100% Cooling Air Flow = {:.2R}", this->CoolEffectSensible100));
2097 0 : ShowContinueError(state, format("...Sensible Effectiveness at 75% Cooling Air Flow = {:.2R}", this->CoolEffectSensible75));
2098 0 : ShowContinueError(state, "...Sensible effectiveness reset to zero and the simulation continues.");
2099 : }
2100 0 : ShowContinueError(state, format("...Heat Exchanger Air Volume Flow Ratio = {:.2R}", HXAirVolFlowRatio));
2101 0 : this->SensEffectivenessFlag = true;
2102 : }
2103 : }
2104 1658489 : if (this->LatEffectiveness < 0.0) {
2105 : // The model should at least guard against negative numbers
2106 0 : this->LatEffectiveness = 0.0;
2107 0 : if (!this->LatEffectivenessFlag) {
2108 0 : ShowWarningError(
2109 : state,
2110 0 : format("HeatExchanger:AirToAir:SensibleAndLatent =\"{}\" latent effectiveness is less than zero. Check the following inputs.",
2111 0 : this->Name));
2112 0 : if (this->SupInTemp < this->SecInTemp) {
2113 0 : ShowContinueError(state, format("...Latent Effectiveness at 100% Heating Air Flow = {:.2R}", this->HeatEffectLatent100));
2114 0 : ShowContinueError(state, format("...Latent Effectiveness at 75% Heating Air Flow = {:.2R}", this->HeatEffectLatent75));
2115 0 : ShowContinueError(state, "...Latent effectiveness reset to zero and the simulation continues.");
2116 : } else {
2117 0 : ShowContinueError(state, format("...Latent Effectiveness at 100% Cooling Air Flow = {:.2R}", this->CoolEffectLatent100));
2118 0 : ShowContinueError(state, format("...Latent Effectiveness at 75% Cooling Air Flow = {:.2R}", this->CoolEffectLatent75));
2119 0 : ShowContinueError(state, "...Latent effectiveness reset to zero and the simulation continues.");
2120 : }
2121 0 : ShowContinueError(state, format("...Heat Exchanger Air Volume Flow Ratio = {:.2R}", HXAirVolFlowRatio));
2122 0 : this->LatEffectivenessFlag = true;
2123 : }
2124 : }
2125 : // Use the effectiveness to calculate the air conditions exiting the heat exchanger (all air flow through the HX)
2126 : // Include EATR and OACF in the following calculations at some point
2127 :
2128 1658489 : CSup = this->SupOutMassFlow * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
2129 1658489 : CSec = this->SecOutMassFlow * Psychrometrics::PsyCpAirFnW(this->SecInHumRat);
2130 1658489 : CMin = min(CSup, CSec);
2131 :
2132 1658489 : this->SupOutTemp = this->SupInTemp + this->SensEffectiveness * CMin / CSup * (this->SecInTemp - this->SupInTemp);
2133 1658489 : this->SupOutHumRat = this->SupInHumRat + this->LatEffectiveness * CMin / CSup * (this->SecInHumRat - this->SupInHumRat);
2134 1658489 : this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
2135 :
2136 : // Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy
2137 1658489 : if (Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress) > this->SupOutTemp) {
2138 100877 : this->SupOutTemp = Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress);
2139 100877 : this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
2140 : }
2141 1658489 : QSensTrans = CSup * (this->SupInTemp - this->SupOutTemp);
2142 1658489 : this->SecOutTemp = this->SecInTemp + QSensTrans / CSec;
2143 1658489 : QTotTrans = this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
2144 1658489 : this->SecOutEnth = this->SecInEnth + QTotTrans / this->SecOutMassFlow;
2145 1658489 : this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
2146 : // Control the supply air outlet temperature to a setpoint for Heating Mode only
2147 : // (ControlFraction = 0 HX fully bypassed, ControlFraction = 1 air passed entirely through HX)
2148 : // (supply air stream bypass mass flow rate proportional to ControlFraction except when frost control is active)
2149 1658489 : if (this->ControlToTemperatureSetPoint) {
2150 1312112 : if ((this->SupInTemp - this->SupOutTemp) != 0.0) {
2151 2359445 : if ((this->SupInTemp < HXTempSetPoint && this->SupOutTemp > HXTempSetPoint) ||
2152 1825349 : (this->SupInTemp > HXTempSetPoint && this->SupOutTemp < HXTempSetPoint)) {
2153 333559 : ControlFraction = max(0.0, min(1.0, std::abs((this->SupInTemp - HXTempSetPoint) / (this->SupInTemp - this->SupOutTemp))));
2154 1532795 : } else if ((this->SupInTemp < this->SupOutTemp && this->SupOutTemp < HXTempSetPoint) ||
2155 1119658 : (this->SupInTemp > this->SupOutTemp && this->SupOutTemp > HXTempSetPoint)) {
2156 872526 : ControlFraction = 1.0;
2157 : } else {
2158 67100 : ControlFraction = 0.0;
2159 : }
2160 : } else {
2161 : // ELSE fully bypass HX to maintain supply outlet temp as high as possible
2162 38927 : ControlFraction = 0.0;
2163 : }
2164 1312112 : if (this->ExchConfig == HXConfigurationType::Rotary) {
2165 : // Rotory HX's never get bypassed, rotational speed is modulated
2166 737077 : this->SensEffectiveness *= ControlFraction;
2167 737077 : this->LatEffectiveness *= ControlFraction;
2168 : } else { // HX is a plate heat exchanger, bypass air to control SA temperature
2169 575035 : Error = 1.0;
2170 575035 : Iter = 0.0;
2171 575035 : MassFlowSupIn = this->SupInMassFlow;
2172 575035 : MassFlowSupOut = this->SupOutMassFlow;
2173 575035 : MassFlowSupBypass = this->SupBypassMassFlow;
2174 575035 : MassFlowSecIn = this->SecInMassFlow;
2175 575035 : TempSupIn = this->SupInTemp;
2176 575035 : TempSupOut = this->SupOutTemp;
2177 575035 : HumRatSupIn = this->SupInHumRat;
2178 575035 : TempSecIn = this->SecInTemp;
2179 1272921 : while ((std::abs(Error) > ErrorTol && Iter < 10 && ControlFraction < 1.0) || Iter == 1) {
2180 404836 : MassFlowSupOut = MassFlowSupIn * ControlFraction;
2181 404836 : MassFlowSupBypass = MassFlowSupIn * (1.0 - ControlFraction);
2182 404836 : HXSupAirVolFlowRate = MassFlowSupOut / RhoSup;
2183 404836 : HXAvgAirVolFlowRate = (HXSecAirVolFlowRate + HXSupAirVolFlowRate) / 2.0;
2184 404836 : HXAirVolFlowRatio = HXAvgAirVolFlowRate / this->NomSupAirVolFlow;
2185 404836 : CSup = MassFlowSupOut * Psychrometrics::PsyCpAirFnW(HumRatSupIn);
2186 404836 : CMin = min(CSup, CSec);
2187 404836 : if (TempSupIn < TempSecIn) {
2188 : // Use heating effectiveness values
2189 191844 : this->SensEffectiveness = this->HeatEffectSensible75 + (this->HeatEffectSensible100 - this->HeatEffectSensible75) *
2190 127896 : (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2191 191844 : this->LatEffectiveness = this->HeatEffectLatent75 + (this->HeatEffectLatent100 - this->HeatEffectLatent75) *
2192 127896 : (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2193 : } else {
2194 : // Use cooling effectiveness values
2195 1022664 : this->SensEffectiveness = this->CoolEffectSensible75 + (this->CoolEffectSensible100 - this->CoolEffectSensible75) *
2196 681776 : (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2197 1022664 : this->LatEffectiveness = this->CoolEffectLatent75 + (this->CoolEffectLatent100 - this->CoolEffectLatent75) *
2198 681776 : (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2199 : }
2200 :
2201 404836 : if (this->SensEffectiveness < 0.0) {
2202 : // The model should at least guard against negative numbers
2203 0 : this->SensEffectiveness = 0.0;
2204 0 : if (!this->SensEffectivenessFlag) {
2205 0 : ShowWarningError(state,
2206 0 : format("HeatExchanger:AirToAir:SensibleAndLatent =\"{}\" sensible effectiveness is less than zero. "
2207 : "Check the following inputs.",
2208 0 : this->Name));
2209 0 : if (this->SupInTemp < this->SecInTemp) {
2210 0 : ShowContinueError(
2211 0 : state, format("...Sensible Effectiveness at 100% Heating Air Flow = {:.2R}", this->HeatEffectSensible100));
2212 0 : ShowContinueError(
2213 0 : state, format("...Sensible Effectiveness at 75% Heating Air Flow = {:.2R}", this->HeatEffectSensible75));
2214 0 : ShowContinueError(state, "...Sensible effectiveness reset to zero and the simulation continues.");
2215 : } else {
2216 0 : ShowContinueError(
2217 0 : state, format("...Sensible Effectiveness at 100% Cooling Air Flow = {:.2R}", this->CoolEffectSensible100));
2218 0 : ShowContinueError(
2219 0 : state, format("...Sensible Effectiveness at 75% Cooling Air Flow = {:.2R}", this->CoolEffectSensible75));
2220 0 : ShowContinueError(state, "...Sensible effectiveness reset to zero and the simulation continues.");
2221 : }
2222 0 : ShowContinueError(state, format("...Heat Exchanger Air Volume Flow Ratio = {:.2R}", HXAirVolFlowRatio));
2223 0 : this->SensEffectivenessFlag = true;
2224 : }
2225 : }
2226 404836 : if (this->LatEffectiveness < 0.0) {
2227 : // The model should at least guard against negative numbers
2228 0 : this->LatEffectiveness = 0.0;
2229 0 : if (!this->LatEffectivenessFlag) {
2230 0 : ShowWarningError(state,
2231 0 : format("HeatExchanger:AirToAir:SensibleAndLatent =\"{}\" latent effectiveness is less than zero. "
2232 : "Check the following inputs.",
2233 0 : this->Name));
2234 0 : if (this->SupInTemp < this->SecInTemp) {
2235 0 : ShowContinueError(state,
2236 0 : format("...Latent Effectiveness at 100% Heating Air Flow = {:.2R}", this->HeatEffectLatent100));
2237 0 : ShowContinueError(state,
2238 0 : format("...Latent Effectiveness at 75% Heating Air Flow = {:.2R}", this->HeatEffectLatent75));
2239 0 : ShowContinueError(state, "...Latent effectiveness reset to zero and the simulation continues.");
2240 : } else {
2241 0 : ShowContinueError(state,
2242 0 : format("...Latent Effectiveness at 100% Cooling Air Flow = {:.2R}", this->CoolEffectLatent100));
2243 0 : ShowContinueError(state,
2244 0 : format("...Latent Effectiveness at 75% Cooling Air Flow = {:.2R}", this->CoolEffectLatent75));
2245 0 : ShowContinueError(state, "...Latent effectiveness reset to zero and the simulation continues.");
2246 : }
2247 0 : ShowContinueError(state, format("...Heat Exchanger Air Volume Flow Ratio = {:.2R}", HXAirVolFlowRatio));
2248 0 : this->LatEffectivenessFlag = true;
2249 : }
2250 : }
2251 :
2252 404836 : if (CSup == 0.0) {
2253 : // IF CSup = 0, then supply air mass flow rate = 0 and HX is fully bypassed. Fix divide by 0 error below DO loop.
2254 55893 : CSup = 1.0;
2255 55893 : CMin = 0.0;
2256 55893 : break;
2257 : }
2258 697886 : TempSupOut = (MassFlowSupOut * (TempSupIn + this->SensEffectiveness * CMin / CSup * (TempSecIn - TempSupIn)) +
2259 348943 : MassFlowSupBypass * TempSupIn) /
2260 : MassFlowSupIn;
2261 348943 : Error = (TempSupOut - HXTempSetPoint);
2262 : // IF supply inlet temp = supply outlet temp, fully bypass HX - ELSE control to SP
2263 348943 : if (TempSupIn != TempSupOut) {
2264 348943 : ControlFraction = max(0.0, min(1.0, std::abs(ControlFraction * (TempSupIn - HXTempSetPoint) / (TempSupIn - TempSupOut))));
2265 0 : } else if (std::abs(TempSupOut - HXTempSetPoint) < ErrorTol) {
2266 : // IF TempSupIn = TempSupOut then TempSecIn = TempSupIn (ControlFraction = ?)
2267 : // Do nothing, variables in ELSE below have already been calculated
2268 0 : break;
2269 : } else {
2270 : // or HX is fully bypassed (ControlFraction = 0) which actually should be caught in IF(CSup .EQ. 0.0)THEN above.
2271 0 : ControlFraction = 0.0;
2272 0 : MassFlowSupOut = MassFlowSupIn * ControlFraction;
2273 0 : MassFlowSupBypass = MassFlowSupIn * (1.0 - ControlFraction);
2274 0 : CSup = 1.0;
2275 0 : CMin = 0.0;
2276 0 : break;
2277 : }
2278 348943 : ++Iter;
2279 : }
2280 :
2281 575035 : this->SupInMassFlow = MassFlowSupIn;
2282 575035 : this->SupOutMassFlow = MassFlowSupOut;
2283 575035 : this->SupBypassMassFlow = MassFlowSupBypass;
2284 575035 : this->SecInMassFlow = MassFlowSecIn;
2285 575035 : this->SupInTemp = TempSupIn;
2286 575035 : this->SupOutTemp = TempSupOut;
2287 575035 : this->SupInHumRat = HumRatSupIn;
2288 575035 : this->SecInTemp = TempSecIn;
2289 :
2290 : } // ENDIF for "IF (thisExch%ExchConfig == 'ROTARY') THEN"
2291 1312112 : this->SupOutTemp = this->SupInTemp + this->SensEffectiveness * CMin / CSup * (this->SecInTemp - this->SupInTemp);
2292 1312112 : this->SupOutHumRat = this->SupInHumRat + this->LatEffectiveness * CMin / CSup * (this->SecInHumRat - this->SupInHumRat);
2293 1312112 : this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
2294 :
2295 : // Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy
2296 1312112 : if (Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress) > this->SupOutTemp) {
2297 173477 : this->SupOutTemp = Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress);
2298 173477 : this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
2299 : }
2300 :
2301 1312112 : QSensTrans = CSup * (this->SupInTemp - this->SupOutTemp);
2302 1312112 : this->SecOutTemp = this->SecInTemp + QSensTrans / CSec;
2303 1312112 : QTotTrans = this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
2304 1312112 : this->SecOutEnth = this->SecInEnth + QTotTrans / this->SecOutMassFlow;
2305 1312112 : this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
2306 :
2307 : } // ENDIF for "IF(thisExch%ControlToTemperatureSetPoint .AND... THEN, ELSE"
2308 :
2309 1658489 : if (FanOpMode == DataHVACGlobals::CycFanCycCoil) {
2310 0 : this->SupInMassFlow *= AirSidePLR;
2311 0 : this->SupOutMassFlow *= AirSidePLR;
2312 0 : this->SecInMassFlow *= AirSidePLR;
2313 0 : this->SecOutMassFlow *= AirSidePLR;
2314 0 : this->SupBypassMassFlow *= AirSidePLR;
2315 0 : this->SecBypassMassFlow *= AirSidePLR;
2316 1658489 : } else if (FanOpMode == DataHVACGlobals::ContFanCycCoil) {
2317 1658489 : this->SupOutTemp = this->SupOutTemp * AirSidePLR + this->SupInTemp * (1.0 - AirSidePLR);
2318 1658489 : this->SupOutHumRat = this->SupOutHumRat * AirSidePLR + this->SupInHumRat * (1.0 - AirSidePLR);
2319 1658489 : this->SupOutEnth = this->SupOutEnth * AirSidePLR + this->SupOutEnth * (1.0 - AirSidePLR);
2320 1658489 : this->SecOutTemp = this->SecOutTemp * AirSidePLR + this->SecInTemp * (1.0 - AirSidePLR);
2321 1658489 : this->SecOutHumRat = this->SecOutHumRat * AirSidePLR + this->SecInHumRat * (1.0 - AirSidePLR);
2322 1658489 : this->SecOutEnth = this->SecOutEnth * AirSidePLR + this->SecOutEnth * (1.0 - AirSidePLR);
2323 : }
2324 :
2325 3237182 : if ((this->FrostControlType == FrostControlOption::MinimumExhaustTemperature && this->SecOutTemp < this->ThresholdTemperature) ||
2326 3157386 : (this->FrostControlType == FrostControlOption::ExhaustAirRecirculation && this->SupInTemp <= this->ThresholdTemperature) ||
2327 2309569 : (this->FrostControlType == FrostControlOption::ExhaustOnly && this->SupInTemp <= this->ThresholdTemperature)) {
2328 79796 : this->FrostControl(state);
2329 79796 : FrostControlFlag = true;
2330 : }
2331 :
2332 : // check for saturation in secondary outlet
2333 1658489 : TempSecOutSat = Psychrometrics::PsyTsatFnHPb(state, this->SecOutEnth, state.dataEnvrn->OutBaroPress);
2334 1658489 : if (TempSecOutSat > this->SecOutTemp) {
2335 80593 : this->SecOutTemp = TempSecOutSat;
2336 80593 : this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
2337 : }
2338 :
2339 : // calculate outlet conditions by mixing bypass air stream with air that went through the
2340 : // heat exchanger core. Perform this mixing only when no frost control is used or
2341 : // heat exchanger is not in frost control mode. Mixing similar to this is performed
2342 : // in the frost control subroutine when in frost control mode.
2343 1658489 : if (!FrostControlFlag) {
2344 1578693 : this->SupOutEnth = (this->SupOutMassFlow * this->SupOutEnth + this->SupBypassMassFlow * this->SupInEnth) / this->SupInMassFlow;
2345 1578693 : this->SupOutHumRat = (this->SupOutMassFlow * this->SupOutHumRat + this->SupBypassMassFlow * this->SupInHumRat) / this->SupInMassFlow;
2346 1578693 : this->SupOutTemp = Psychrometrics::PsyTdbFnHW(this->SupOutEnth, this->SupOutHumRat);
2347 1578693 : this->SupOutMassFlow = this->SupInMassFlow;
2348 1578693 : this->SecOutEnth = (this->SecOutMassFlow * this->SecOutEnth + this->SecBypassMassFlow * this->SecInEnth) / this->SecInMassFlow;
2349 1578693 : this->SecOutHumRat = (this->SecOutMassFlow * this->SecOutHumRat + this->SecBypassMassFlow * this->SecInHumRat) / this->SecInMassFlow;
2350 1578693 : this->SecOutTemp = Psychrometrics::PsyTdbFnHW(this->SecOutEnth, this->SecOutHumRat);
2351 1578693 : this->SecOutMassFlow = this->SecInMassFlow;
2352 : }
2353 :
2354 1658489 : this->ElecUseRate = this->NomElecPower;
2355 :
2356 : } // ENDIF for "IF (UnitOn) THEN"
2357 :
2358 : // Calculate heat transfer from the unit using the final supply inlet and supply outlet air conditions
2359 2533886 : CSup = this->SupOutMassFlow * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
2360 2533886 : SensHeatRecRate = CSup * (this->SupOutTemp - this->SupInTemp);
2361 2533886 : TotHeatRecRate = this->SupOutMassFlow * (this->SupOutEnth - this->SupInEnth);
2362 2533886 : LatHeatRecRate = TotHeatRecRate - SensHeatRecRate;
2363 :
2364 : // Set report variables based on sign of recovery rate
2365 2533886 : if (SensHeatRecRate > 0.0) {
2366 760390 : this->SensHeatingRate = SensHeatRecRate;
2367 760390 : this->SensCoolingRate = 0.0;
2368 : } else {
2369 1773496 : this->SensHeatingRate = 0.0;
2370 1773496 : this->SensCoolingRate = std::abs(SensHeatRecRate);
2371 : }
2372 2533886 : if (LatHeatRecRate > 0.0) {
2373 792383 : this->LatHeatingRate = LatHeatRecRate;
2374 792383 : this->LatCoolingRate = 0.0;
2375 : } else {
2376 1741503 : this->LatHeatingRate = 0.0;
2377 1741503 : this->LatCoolingRate = std::abs(LatHeatRecRate);
2378 : }
2379 2533886 : if (TotHeatRecRate > 0.0) {
2380 817846 : this->TotHeatingRate = TotHeatRecRate;
2381 817846 : this->TotCoolingRate = 0.0;
2382 : } else {
2383 1716040 : this->TotHeatingRate = 0.0;
2384 1716040 : this->TotCoolingRate = std::abs(TotHeatRecRate);
2385 : }
2386 2533886 : }
2387 :
2388 671995 : void HeatExchCond::CalcDesiccantBalancedHeatExch(
2389 : EnergyPlusData &state,
2390 : bool const HXUnitOn, // flag to simulate heat exchager heat recovery
2391 : bool const FirstHVACIteration, // First HVAC iteration flag
2392 : int const FanOpMode, // Supply air fan operating mode (1=cycling, 2=constant)
2393 : Real64 const PartLoadRatio, // Part load ratio requested of DX compressor
2394 : int const CompanionCoilIndex, // index of companion cooling coil
2395 : bool const RegenInletIsOANode, // Flag to determine if regen side inlet is OANode, if so this air stream cycles
2396 : Optional_bool_const EconomizerFlag, // economizer flag pass by air loop or OA sys
2397 : Optional_bool_const HighHumCtrlFlag // high humidity control flag passed by airloop or OA sys
2398 : )
2399 : {
2400 :
2401 : // SUBROUTINE INFORMATION:
2402 : // AUTHOR Mangesh Basarkar, FSEC
2403 : // DATE WRITTEN January 2007
2404 : // MODIFIED R. Raustad - FSEC, Feb 2009 - added economizer flags
2405 : // Both the economizer and high humidity control flags can disable the HX
2406 : // RE-ENGINEERED na
2407 :
2408 : // PURPOSE OF THIS SUBROUTINE:
2409 : // Calculate the outlet conditions for a balanced air-to-air desiccant heat exchanger
2410 : // given the inlet conditions and face velocity. Performance map is provided by user.
2411 :
2412 : // METHODOLOGY EMPLOYED:
2413 : // This is an empirical heat exchanger model. The model uses heat exchanger performance data to
2414 : // calculate the air temperature and humidity ratio of the leaving upply and secondary air streams.
2415 : // Humidity control can enable/disable heat recovery through the use of the HXUnitOn Subroutine argument.
2416 :
2417 : // Using/Aliasing
2418 : using DataLoopNode::SensedNodeFlagValue;
2419 :
2420 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2421 : bool UnitOn; // unit on flag
2422 : Real64 RhoStd; // standard air density at actual pressure, 20C dry-bulb temp and 0.0 absolute humidity [kg/m3]
2423 : Real64 CSup; // supply air heat capacity rate [W/K]
2424 : Real64 CSec; // secondary air heat capacity rate [W/K]
2425 : Real64 TempSecOutSat; // secondary air outlet temperature at saturation (at EnthsSecOut) [C]
2426 : Real64 SensHeatRecRate; // sensible heat recovery rate to supply air (heating +, cooling -)
2427 : Real64 TotHeatRecRate; // total heat recovery rate to supply air (heating +, cooling -)
2428 : Real64 ProcessSensHeatRecRate; // process sensible heat recovery rate (heating +, cooling -)
2429 : Real64 ProcessTotHeatRecRate; // process total heat recovery rate (heating +, cooling -)
2430 : Real64 ProcessLatHeatRecRate; // process latent heat recovery rate (heating [humidify] +, cooling [dehumidify] -)
2431 :
2432 : Real64 BalFaceVelActual; // operating face velocity [m/s]
2433 671995 : Real64 FullLoadSupOutTemp(0); // empirical model supply outlet temperature [C]
2434 671995 : Real64 FullLoadSupOutHumRat(0); // empirical model supply outlet humidity ratio [kg/kg]
2435 : Real64 FullLoadDeltaT; // empirical model heat exchanger delta temperature [C]
2436 : Real64 FullLoadDeltaW; // empirical model heat exchanger delta humidity ratio [kg/kg]
2437 : Real64 T_RegenInTemp; // empirical model supply (regen) inlet temperature for temperature equation [C]
2438 : Real64 T_RegenInHumRat; // empirical model supply (regen) inlet humidity ratio for temperature equation [kg/kg]
2439 : Real64 T_ProcInTemp; // empirical model secondary (process) inlet temperature for temperature equation [C]
2440 : Real64 T_ProcInHumRat; // empirical model secondary (process) inlet humidity ratio for temperature equation [kg/kg]
2441 : Real64 T_FaceVel; // empirical model face velocity for temperature equation [m/s]
2442 : Real64 H_RegenInTemp; // empirical model supply (regen) inlet temperature for humidity ratio equation [C]
2443 : Real64 H_RegenInHumRat; // empirical model supply (regen) inlet humidity ratio for humidity ratio equation [kg/kg]
2444 : Real64 H_ProcInTemp; // empirical model secondary (process) inlet temperature for humidity ratio equation [C]
2445 : Real64 H_ProcInHumRat; // empirical model secondary (process) inlet humidity ratio for humidity ratio equation [kg/kg]
2446 : Real64 H_FaceVel; // empirical model face velocity for humidity ratio equation [m/s]
2447 : Real64 MaxHumRatNeeded; // maximum humidity ratio setpoint for balanced desiccant HX [kg/kg]
2448 : Real64 MinHumRatNeeded; // minimum humidity ratio setpoint for balanced desiccant HX [kg/kg]
2449 : Real64 HXPartLoadRatio; // local heat exchanger part-load ratio
2450 : Real64 TestSaturationEnthalpy; // enthalpy used to test for regeneration outlet condition over saturation curve (J/kg)
2451 671995 : constexpr const char *ThisSubTSat("CalcDesiccantBalancedHeatExch: TSat");
2452 671995 : constexpr const char *ThisSubTSatFullLoadOutTemp("CalcDesiccantBalancedHeatExch: TSat-FullLoadOutTemp");
2453 671995 : constexpr const char *ThisSubTSatFullLoadOutHumRat("CalcDesiccantBalancedHeatExch: TSat-FullLoadOutHumRat");
2454 671995 : constexpr const char *ThisSubSecOutHumRat("CalcDesiccantBalancedHeatExch: SecOutHumRat");
2455 671995 : constexpr const char *ThisSubTestSatSec("CalcDesiccantBalancedHeatExch: TestSatSec");
2456 671995 : constexpr const char *ThisSubTSatSecOutHumRat("CalcDesiccantBalancedHeatExch: TSat-SecOutHumRat");
2457 :
2458 : Real64 AverageMassFlowRate; // average of supply (regen) and secondary (process) mass flow rates [kg/s]
2459 : bool EconomizerActiveFlag; // local representing the economizer status when PRESENT
2460 : bool HighHumCtrlActiveFlag; // local representing high humidity control when PRESENT
2461 :
2462 : // Initialize local variables
2463 671995 : UnitOn = true;
2464 671995 : SensHeatRecRate = 0.0;
2465 671995 : TotHeatRecRate = 0.0;
2466 671995 : HXPartLoadRatio = PartLoadRatio;
2467 671995 : this->DefrostFraction = 0.0;
2468 671995 : this->ElecUseRate = 0.0;
2469 671995 : this->SupOutTemp = this->SupInTemp;
2470 671995 : this->SecOutTemp = this->SecInTemp;
2471 671995 : this->SupOutHumRat = this->SupInHumRat;
2472 671995 : this->SecOutHumRat = this->SecInHumRat;
2473 671995 : this->SupOutEnth = this->SupInEnth;
2474 671995 : this->SecOutEnth = this->SecInEnth;
2475 671995 : this->SupOutMassFlow = this->SupInMassFlow;
2476 671995 : this->SecOutMassFlow = this->SecInMassFlow;
2477 671995 : AverageMassFlowRate = (this->SupOutMassFlow + this->SecOutMassFlow) / 2.0;
2478 :
2479 671995 : if (present(EconomizerFlag)) {
2480 489222 : EconomizerActiveFlag = EconomizerFlag;
2481 : } else {
2482 182773 : EconomizerActiveFlag = false;
2483 : }
2484 :
2485 671995 : if (present(HighHumCtrlFlag)) {
2486 0 : HighHumCtrlActiveFlag = HighHumCtrlFlag;
2487 : } else {
2488 671995 : HighHumCtrlActiveFlag = false;
2489 : }
2490 :
2491 : // Unit is scheduled OFF, so bypass heat exchange calcs
2492 671995 : if (ScheduleManager::GetCurrentScheduleValue(state, this->SchedPtr) <= 0.0) UnitOn = false;
2493 : // Determine if unit is ON or OFF based on air mass flow through the supply and secondary airstreams and operation flag
2494 671995 : if (this->SupInMassFlow <= DataHVACGlobals::SmallMassFlow) UnitOn = false;
2495 671995 : if (this->SecInMassFlow <= DataHVACGlobals::SmallMassFlow) UnitOn = false;
2496 671995 : if (HXPartLoadRatio == 0.0) UnitOn = false;
2497 671995 : if (!HXUnitOn) UnitOn = false;
2498 671995 : if ((EconomizerActiveFlag || HighHumCtrlActiveFlag) && this->EconoLockOut) UnitOn = false;
2499 :
2500 671995 : if (UnitOn) {
2501 : Real64 local_SupInMassFlow; // Supply side HX mass flow rate
2502 : Real64 local_SecInMassFlow; // Secondary side HX mass flow rate
2503 :
2504 : // Use local variables to perform checks
2505 103147 : local_SecInMassFlow = this->SecInMassFlow;
2506 103147 : local_SupInMassFlow = this->SupInMassFlow;
2507 :
2508 : // In constant fan mode, process air mass flow rate is full flow and supply (regen) air cycles based on PLR.
2509 : // If supply (regen) inlet is OA node, regen mass flow rate is proportional to PLR.
2510 : // If both of the above is true then boost local variable up to full flow
2511 103147 : if ((FanOpMode == DataHVACGlobals::ContFanCycCoil) && RegenInletIsOANode) {
2512 2219 : local_SupInMassFlow /= HXPartLoadRatio;
2513 : }
2514 : // for cycling fan case, boost both local variables up to full flow
2515 103147 : if (FanOpMode == DataHVACGlobals::CycFanCycCoil) {
2516 7232 : local_SupInMassFlow /= HXPartLoadRatio; // supply = regen
2517 7232 : local_SecInMassFlow /= HXPartLoadRatio; // secondary = process
2518 : }
2519 :
2520 : // Check for balanced flow condition
2521 103147 : this->CheckForBalancedFlow(state, local_SecInMassFlow, local_SupInMassFlow, FirstHVACIteration);
2522 :
2523 103147 : auto &perf = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex);
2524 :
2525 103147 : T_ProcInTemp = state.dataHeatRecovery->FullLoadOutAirTemp;
2526 103147 : T_ProcInHumRat = state.dataHeatRecovery->FullLoadOutAirHumRat;
2527 103147 : T_RegenInTemp = this->SupInTemp;
2528 103147 : T_RegenInHumRat = this->SupInHumRat;
2529 :
2530 : // Must use the same density used to convert volumetric flow rate to mass flow rate to get back to velocity
2531 103147 : RhoStd = state.dataEnvrn->StdRhoAir; // PsyRhoAirFnPbTdbW(StdBaroPress,20.0d0, 0.0d0)
2532 103147 : BalFaceVelActual = local_SupInMassFlow / (RhoStd * this->FaceArea);
2533 :
2534 103147 : T_FaceVel = BalFaceVelActual;
2535 :
2536 : // Call model check routines only when HX is active, if coil is off these checks do not apply (no potential for heat transfer)
2537 : // Check RH limits and warn user if out of bounds (T_* not modified in subroutine)
2538 :
2539 103147 : this->CheckModelBoundsRH_TempEq(state, T_RegenInTemp, T_RegenInHumRat, T_ProcInTemp, T_ProcInHumRat, FirstHVACIteration);
2540 : // Check model boundaries and cap empirical model independent variables as needed (T_* may be modified on return from sub)
2541 103147 : this->CheckModelBoundsTempEq(state, T_RegenInTemp, T_RegenInHumRat, T_ProcInTemp, T_ProcInHumRat, T_FaceVel, FirstHVACIteration);
2542 :
2543 103147 : if (T_ProcInTemp != 0.0 && T_RegenInTemp != 0.0) {
2544 309441 : FullLoadSupOutTemp = perf.B[0] + perf.B[1] * T_RegenInHumRat + perf.B[2] * T_RegenInTemp +
2545 309441 : perf.B[3] * (T_RegenInHumRat / T_RegenInTemp) + perf.B[4] * T_ProcInHumRat + perf.B[5] * T_ProcInTemp +
2546 206294 : perf.B[6] * (T_ProcInHumRat / T_ProcInTemp) + perf.B[7] * T_FaceVel;
2547 :
2548 : // Check model boundary for supply (regen) temp and do not cap value if out of bounds, check that supply in temp > out temp
2549 103147 : this->CheckModelBoundOutput_Temp(state, this->SupInTemp, FullLoadSupOutTemp, FirstHVACIteration);
2550 103147 : FullLoadDeltaT = FullLoadSupOutTemp - this->SupInTemp;
2551 : } else {
2552 0 : FullLoadDeltaT = 0.0;
2553 : }
2554 :
2555 103147 : H_ProcInTemp = state.dataHeatRecovery->FullLoadOutAirTemp;
2556 103147 : H_ProcInHumRat = state.dataHeatRecovery->FullLoadOutAirHumRat;
2557 103147 : H_RegenInTemp = this->SupInTemp;
2558 103147 : H_RegenInHumRat = this->SupInHumRat;
2559 103147 : H_FaceVel = BalFaceVelActual;
2560 :
2561 : // Call model check routines only when HX is active, if coil is off these checks do not apply (no potential for heat transfer)
2562 : // Check RH limits and warn user if out of bounds (H_* not modified in subroutine)
2563 :
2564 103147 : this->CheckModelBoundsRH_HumRatEq(state, H_RegenInTemp, H_RegenInHumRat, H_ProcInTemp, H_ProcInHumRat, FirstHVACIteration);
2565 : // Check model boundaries and cap empirical model independent variables as needed (H_* may be modified on return from sub)
2566 103147 : this->CheckModelBoundsHumRatEq(state, H_RegenInTemp, H_RegenInHumRat, H_ProcInTemp, H_ProcInHumRat, H_FaceVel, FirstHVACIteration);
2567 :
2568 : // Calc curve
2569 103147 : if (H_ProcInTemp != 0.0 && H_RegenInTemp != 0.0) {
2570 309441 : FullLoadSupOutHumRat = perf.C[0] + perf.C[1] * H_RegenInHumRat + perf.C[2] * H_RegenInTemp +
2571 309441 : perf.C[3] * (H_RegenInHumRat / H_RegenInTemp) + perf.C[4] * H_ProcInHumRat + perf.C[5] * H_ProcInTemp +
2572 206294 : perf.C[6] * (H_ProcInHumRat / H_ProcInTemp) + perf.C[7] * H_FaceVel;
2573 :
2574 : // Check model boundary for supply (regen) hum rat and do not cap value if out of bounds, check that supply in HR < out HR
2575 103147 : this->CheckModelBoundOutput_HumRat(state, this->SupInHumRat, FullLoadSupOutHumRat, FirstHVACIteration);
2576 103147 : FullLoadDeltaW = FullLoadSupOutHumRat - this->SupInHumRat;
2577 : } else {
2578 0 : FullLoadDeltaW = 0.0;
2579 : }
2580 :
2581 : // Check for saturation in the model's calculated supply outlet and reset temp, then humidity ratio at constant enthalpy
2582 : // Reset delta T and delta W such that the model does not allow an outlet condition over saturation
2583 103147 : TestSaturationEnthalpy = Psychrometrics::PsyHFnTdbW(FullLoadSupOutTemp, FullLoadSupOutHumRat);
2584 103147 : if (Psychrometrics::PsyTsatFnHPb(state, TestSaturationEnthalpy, state.dataEnvrn->OutBaroPress, ThisSubTSat) > FullLoadSupOutTemp) {
2585 60 : FullLoadSupOutTemp =
2586 120 : Psychrometrics::PsyTsatFnHPb(state, TestSaturationEnthalpy, state.dataEnvrn->OutBaroPress, ThisSubTSatFullLoadOutTemp);
2587 60 : FullLoadSupOutHumRat = Psychrometrics::PsyWFnTdbH(state, FullLoadSupOutTemp, TestSaturationEnthalpy, ThisSubTSatFullLoadOutHumRat);
2588 60 : FullLoadDeltaT = FullLoadSupOutTemp - this->SupInTemp;
2589 60 : FullLoadDeltaW = FullLoadSupOutHumRat - this->SupInHumRat;
2590 : }
2591 :
2592 103147 : if (!state.dataHeatRecovery->CalledFromParentObject) {
2593 : // calculate part-load ratio for HX
2594 0 : MaxHumRatNeeded = state.dataLoopNodes->Node(this->SecOutletNode).HumRatMax;
2595 0 : MinHumRatNeeded = state.dataLoopNodes->Node(this->SecOutletNode).HumRatMin;
2596 : // Calculate partload fraction of dehumidification capacity required to meet setpoint
2597 :
2598 : // check the model output, if the regen delta W is positive, the process air stream is dehumidified
2599 0 : if (FullLoadDeltaW > 0) {
2600 : // check for a setpoint, if no setpoint then PLR remains at 1
2601 0 : if (MaxHumRatNeeded != SensedNodeFlagValue) {
2602 0 : if (this->SecInHumRat > MaxHumRatNeeded && MaxHumRatNeeded > 0.0) {
2603 0 : HXPartLoadRatio = (this->SecInHumRat - MaxHumRatNeeded) / FullLoadDeltaW;
2604 : } else {
2605 0 : HXPartLoadRatio = 0.0;
2606 : }
2607 : }
2608 : // check the model output, if the regen delta W is negative, the process air stream is humidified
2609 0 : } else if (FullLoadDeltaW < 0) {
2610 : // check for a setpoint, if no setpoint then PLR remains at 1
2611 0 : if (MinHumRatNeeded != SensedNodeFlagValue) {
2612 0 : if (this->SecInHumRat < MinHumRatNeeded && MinHumRatNeeded > 0.0) {
2613 0 : HXPartLoadRatio = (this->SecInHumRat - MinHumRatNeeded) / FullLoadDeltaW;
2614 : } else {
2615 0 : HXPartLoadRatio = 0.0;
2616 : }
2617 : }
2618 : }
2619 :
2620 0 : HXPartLoadRatio = max(0.0, HXPartLoadRatio);
2621 0 : HXPartLoadRatio = min(1.0, HXPartLoadRatio);
2622 :
2623 103147 : } else if (CompanionCoilIndex > 0) {
2624 : // VS coil issue here?
2625 96507 : HXPartLoadRatio = state.dataDXCoils->DXCoilPartLoadRatio(CompanionCoilIndex);
2626 : }
2627 :
2628 103147 : Real64 constexpr lowerLimit = 1.e-5;
2629 103147 : if (FanOpMode == DataHVACGlobals::CycFanCycCoil || RegenInletIsOANode) {
2630 : // Supply (regen) air stream mass flow rate is cycling and proportional to PLR, outlet conditions are full load
2631 : // conditions
2632 9451 : this->SupOutTemp = this->SupInTemp + FullLoadDeltaT;
2633 9451 : this->SupOutHumRat = min(1.0, max(lowerLimit, this->SupInHumRat + FullLoadDeltaW));
2634 : } else {
2635 : // Supply (regen) air stream mass flow rate is constant and outlet conditions are averaged
2636 93696 : this->SupOutTemp = this->SupInTemp + (FullLoadDeltaT * HXPartLoadRatio);
2637 93696 : this->SupOutHumRat = min(1.0, max(lowerLimit, this->SupInHumRat + (FullLoadDeltaW * HXPartLoadRatio)));
2638 : }
2639 :
2640 : // for a balanced flow HX, use average mass flow rate and actual node conditions to calculate CSup and CSec
2641 : // the mass flow rate on the process and secondary side of HX may be imbalanced when the HX is used in the OA branch
2642 : // use the average mass flow rate to avoid psych warnings, mass flow rates will converge at the end of the iteration
2643 : // if the air mass flow rates do not converge, this model should not be used
2644 103147 : CSup = AverageMassFlowRate * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
2645 103147 : CSec = AverageMassFlowRate * Psychrometrics::PsyCpAirFnW(this->SecInHumRat);
2646 :
2647 103147 : this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
2648 :
2649 103147 : SensHeatRecRate = CSup * (this->SupOutTemp - this->SupInTemp);
2650 :
2651 103147 : TotHeatRecRate = AverageMassFlowRate * (this->SupOutEnth - this->SupInEnth);
2652 :
2653 : // now calculate process side heat transfer
2654 :
2655 103147 : this->SecOutEnth = this->SecInEnth - TotHeatRecRate / AverageMassFlowRate;
2656 :
2657 103147 : this->SecOutTemp = this->SecInTemp - SensHeatRecRate / CSec;
2658 :
2659 103147 : this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth, ThisSubSecOutHumRat);
2660 :
2661 : // check for saturation in process (secondary) outlet
2662 : // The process outlet conditions should never be over the saturation curve for the balanced desiccant model
2663 : // although this may occur during warmup. This check is included here for consistency.
2664 103147 : TempSecOutSat = Psychrometrics::PsyTsatFnHPb(state, this->SecOutEnth, state.dataEnvrn->OutBaroPress, ThisSubTestSatSec);
2665 103147 : if (TempSecOutSat > this->SecOutTemp) {
2666 83 : this->SecOutTemp = TempSecOutSat;
2667 83 : this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth, ThisSubTSatSecOutHumRat);
2668 : }
2669 :
2670 103147 : this->ElecUseRate = perf.NomElecPower * HXPartLoadRatio;
2671 :
2672 : } // ENDIF for "IF (UnitOn) THEN"
2673 :
2674 : // Report the process side heat transfer
2675 671995 : CSec = AverageMassFlowRate * Psychrometrics::PsyCpAirFnW(this->SecInHumRat);
2676 671995 : ProcessSensHeatRecRate = CSec * (this->SecOutTemp - this->SecInTemp);
2677 :
2678 671995 : ProcessTotHeatRecRate = this->SecOutMassFlow * (this->SecOutEnth - this->SecInEnth);
2679 :
2680 671995 : ProcessLatHeatRecRate = ProcessTotHeatRecRate - ProcessSensHeatRecRate;
2681 :
2682 : // Set report variables based on sign of recovery rate
2683 671995 : if (ProcessSensHeatRecRate > 0.0) {
2684 101819 : this->SensHeatingRate = ProcessSensHeatRecRate;
2685 101819 : this->SensCoolingRate = 0.0;
2686 : } else {
2687 570176 : this->SensHeatingRate = 0.0;
2688 570176 : this->SensCoolingRate = std::abs(ProcessSensHeatRecRate);
2689 : }
2690 671995 : if (ProcessLatHeatRecRate > 0.0) {
2691 118 : this->LatHeatingRate = ProcessLatHeatRecRate;
2692 118 : this->LatCoolingRate = 0.0;
2693 : } else {
2694 671877 : this->LatHeatingRate = 0.0;
2695 671877 : this->LatCoolingRate = std::abs(ProcessLatHeatRecRate);
2696 : }
2697 671995 : if (ProcessTotHeatRecRate > 0.0) {
2698 63994 : this->TotHeatingRate = ProcessTotHeatRecRate;
2699 63994 : this->TotCoolingRate = 0.0;
2700 : } else {
2701 608001 : this->TotHeatingRate = 0.0;
2702 608001 : this->TotCoolingRate = std::abs(ProcessTotHeatRecRate);
2703 : }
2704 671995 : }
2705 :
2706 79796 : void HeatExchCond::FrostControl(EnergyPlusData &state)
2707 : {
2708 :
2709 : // SUBROUTINE INFORMATION:
2710 : // AUTHOR Richard Raustad, FSEC
2711 : // DATE WRITTEN June 2003
2712 : // MODIFIED na
2713 : // RE-ENGINEERED na
2714 :
2715 : // PURPOSE OF THIS SUBROUTINE:
2716 : // Calculates fraction of timestep necessary to eliminate frost on ERV surface
2717 : // by comparing secondary outlet or outdoor temperature to a frost control threshold
2718 : // temperature. Supply air and secondary air outlet conditions are calculated
2719 : // based on frost control method selected.
2720 :
2721 : // SUBROUTINE PARAMETER DEFINITIONS:
2722 79796 : Real64 constexpr ErrorTol(0.001); // error tolerance for iteration loop
2723 :
2724 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2725 79796 : Real64 DFFraction = 0.0; // fraction of timestep ERV is in frost control mode
2726 : Real64 Error; // iteration loop error variable
2727 : Real64 Iter; // iteration counter
2728 : Real64 QTotTrans; // total heat transfer by ERV [W]
2729 : Real64 QSensTrans; // sensible heat transfer by ERV [W]
2730 : Real64 HXSecAirVolFlowRate; // air volume flow rate of the secondary air stream through the heat exchanger [m3/sec]
2731 : Real64 HXSupAirVolFlowRate; // air volume flow rate of the supply air stream through the heat exchanger [m3/sec]
2732 : Real64 HXAvgAirVolFlowRate; // average air volume flow rate through the heat exchanger [m3/sec]
2733 : Real64 HXAirVolFlowRatio; // nominal to actual air volume flow ratio
2734 : Real64 MassFlowSupIn; // supply air mass flow rate at HX inlet
2735 : Real64 MassFlowSupOut; // supply air mass flow rate through HX core outlet
2736 : Real64 MassFlowSupBypass; // supply air bypass mass flow rate around HX core
2737 : Real64 TempSupIn; // supply side temperature of air entering HX
2738 : Real64 TempSupOut; // supply side temperature of air leaving HX core
2739 : Real64 HumRatSupIn; // supply side humidity ratio of air entering HX
2740 : Real64 TempSecIn; // secondary side temperature of air entering HX
2741 : Real64 TempSecOut; // secondary side temperature of air leaving HX core
2742 :
2743 79796 : this->SupOutMassFlow = this->SupInMassFlow;
2744 79796 : this->SecOutMassFlow = this->SecInMassFlow;
2745 79796 : this->SupBypassMassFlow = 0.0;
2746 79796 : this->SecBypassMassFlow = 0.0;
2747 : // density of supply air [kg/m3]
2748 79796 : Real64 const RhoSup = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->SupInTemp, this->SupInHumRat);
2749 : // density of secondary air [kg/m3]
2750 79796 : Real64 const RhoSec = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, this->SecInTemp, this->SecInHumRat);
2751 : // mdot Cp of supply air [W/K]
2752 79796 : Real64 CSup = this->SupOutMassFlow * Psychrometrics::PsyCpAirFnW(this->SupInHumRat);
2753 : // mdot Cp of secondary air [W/K]
2754 79796 : Real64 const CSec = this->SecOutMassFlow * Psychrometrics::PsyCpAirFnW(this->SecInHumRat);
2755 : // minimum mdot Cp of supply or secondary air [W/K]
2756 79796 : Real64 CMin = min(CSup, CSec);
2757 : // threshold temperature below which frost control is active
2758 79796 : Real64 const TempThreshold = this->ThresholdTemperature;
2759 :
2760 79796 : if (this->ControlToTemperatureSetPoint) {
2761 : // Recalculate HX outlet conditions as if control to temperature setpoint was not activated,
2762 : // because defrost will override those results
2763 :
2764 62546 : HXSupAirVolFlowRate = this->SupOutMassFlow / RhoSup;
2765 62546 : HXSecAirVolFlowRate = this->SecOutMassFlow / RhoSec;
2766 62546 : HXAvgAirVolFlowRate = (HXSecAirVolFlowRate + HXSupAirVolFlowRate) / 2.0;
2767 62546 : HXAirVolFlowRatio = HXAvgAirVolFlowRate / this->NomSupAirVolFlow;
2768 62546 : this->SensEffectiveness =
2769 62546 : this->HeatEffectSensible75 + (this->HeatEffectSensible100 - this->HeatEffectSensible75) * (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2770 62546 : this->LatEffectiveness =
2771 62546 : this->HeatEffectLatent75 + (this->HeatEffectLatent100 - this->HeatEffectLatent75) * (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2772 62546 : this->SupOutTemp = this->SupInTemp + this->SensEffectiveness * CMin / CSup * (this->SecInTemp - this->SupInTemp);
2773 62546 : this->SupOutHumRat = this->SupInHumRat + this->LatEffectiveness * CMin / CSup * (this->SecInHumRat - this->SupInHumRat);
2774 62546 : this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
2775 :
2776 : // Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy
2777 62546 : if (Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress) > this->SupOutTemp) {
2778 123 : this->SupOutTemp = Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress);
2779 123 : this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
2780 : }
2781 :
2782 62546 : QSensTrans = CSup * (this->SupInTemp - this->SupOutTemp);
2783 62546 : this->SecOutTemp = this->SecInTemp + QSensTrans / CSec;
2784 62546 : QTotTrans = this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
2785 62546 : this->SecOutEnth = this->SecInEnth + QTotTrans / this->SecOutMassFlow;
2786 62546 : this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
2787 : }
2788 :
2789 : // Check frost control by type
2790 :
2791 79796 : switch (this->FrostControlType) {
2792 79796 : case FrostControlOption::MinimumExhaustTemperature:
2793 : // A plate HX will bypass air on the supply side to keep exhaust temp above a
2794 : // threshold temperature and requires recalculating effectiveness based on
2795 : // the reduced air flow rate. A rotary HX modulates rotational speed to try to keep the
2796 : // exhaust air temperature above the threshold temperature. Assume that
2797 : // sensible and latent effectiveness decrease proportionally with rotary HX speed.
2798 :
2799 79796 : DFFraction = max(0.0, min(1.0, SafeDiv((TempThreshold - this->SecOutTemp), (this->SecInTemp - this->SecOutTemp))));
2800 79796 : if (this->ExchConfig == HXConfigurationType::Rotary) {
2801 6946 : this->SensEffectiveness *= (1.0 - DFFraction);
2802 6946 : this->LatEffectiveness *= (1.0 - DFFraction);
2803 : } else { // HX is a plate heat exchanger, bypass air to eliminate frost
2804 72850 : Error = 1.0;
2805 72850 : Iter = 0.0;
2806 72850 : MassFlowSupIn = this->SupInMassFlow;
2807 72850 : MassFlowSupOut = this->SupOutMassFlow;
2808 72850 : MassFlowSupBypass = this->SupBypassMassFlow;
2809 72850 : TempSupIn = this->SupInTemp;
2810 72850 : HumRatSupIn = this->SupInHumRat;
2811 72850 : TempSecIn = this->SecInTemp;
2812 :
2813 1393600 : while (std::abs(Error) > ErrorTol && Iter < 10) {
2814 660375 : MassFlowSupOut = MassFlowSupIn * (1.0 - DFFraction);
2815 660375 : MassFlowSupBypass = MassFlowSupIn * DFFraction;
2816 660375 : HXSupAirVolFlowRate = MassFlowSupOut / RhoSup;
2817 660375 : HXSecAirVolFlowRate = this->SecOutMassFlow / RhoSec;
2818 660375 : HXAvgAirVolFlowRate = (HXSecAirVolFlowRate + HXSupAirVolFlowRate) / 2.0;
2819 660375 : HXAirVolFlowRatio = HXAvgAirVolFlowRate / this->NomSupAirVolFlow;
2820 660375 : CSup = MassFlowSupOut * Psychrometrics::PsyCpAirFnW(HumRatSupIn);
2821 660375 : CMin = min(CSup, CSec);
2822 660375 : if (TempSupIn < TempSecIn) {
2823 : // Use heating effectiveness values
2824 1963554 : this->SensEffectiveness = this->HeatEffectSensible75 + (this->HeatEffectSensible100 - this->HeatEffectSensible75) *
2825 1309036 : (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2826 1309036 : this->LatEffectiveness = this->HeatEffectLatent75 +
2827 654518 : (this->HeatEffectLatent100 - this->HeatEffectLatent75) * (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2828 : } else {
2829 : // Use cooling effectiveness values
2830 17571 : this->SensEffectiveness = this->CoolEffectSensible75 + (this->CoolEffectSensible100 - this->CoolEffectSensible75) *
2831 11714 : (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2832 11714 : this->LatEffectiveness = this->CoolEffectLatent75 +
2833 5857 : (this->CoolEffectLatent100 - this->CoolEffectLatent75) * (HXAirVolFlowRatio - 0.75) / (1.0 - 0.75);
2834 : }
2835 : // calculation of local variable Csup can be 0, gaurd against divide by 0.
2836 660375 : TempSupOut = TempSupIn + this->SensEffectiveness * SafeDiv(CMin, CSup) * (TempSecIn - TempSupIn);
2837 660375 : QSensTrans = CSup * (TempSupIn - TempSupOut);
2838 : // Csec cannot be 0 in this subroutine
2839 660375 : TempSecOut = TempSecIn + QSensTrans / CSec;
2840 660375 : Error = (TempSecOut - TempThreshold);
2841 : // recalculate DFFraction until convergence, gaurd against divide by 0 (unlikely).
2842 660375 : DFFraction = max(0.0, min(1.0, DFFraction * SafeDiv((TempSecIn - TempSecOut), (TempSecIn - TempThreshold))));
2843 660375 : ++Iter;
2844 : }
2845 72850 : this->SupInMassFlow = MassFlowSupIn;
2846 72850 : this->SupOutMassFlow = MassFlowSupOut;
2847 72850 : this->SupBypassMassFlow = MassFlowSupBypass;
2848 : }
2849 79796 : this->SupOutTemp = this->SupInTemp + this->SensEffectiveness * SafeDiv(CMin, CSup) * (this->SecInTemp - this->SupInTemp);
2850 79796 : this->SupOutHumRat = this->SupInHumRat + this->LatEffectiveness * SafeDiv(CMin, CSup) * (this->SecInHumRat - this->SupInHumRat);
2851 79796 : this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
2852 :
2853 : // Check for saturation in supply outlet and reset temp, then humidity ratio at constant enthalpy
2854 79796 : if (Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress) > this->SupOutTemp) {
2855 254 : this->SupOutTemp = Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress);
2856 254 : this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
2857 : }
2858 :
2859 79796 : QSensTrans = CSup * (this->SupInTemp - this->SupOutTemp);
2860 79796 : this->SecOutTemp = this->SecInTemp + QSensTrans / CSec;
2861 79796 : QTotTrans = this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
2862 79796 : this->SecOutEnth = this->SecInEnth + QTotTrans / this->SecOutMassFlow;
2863 79796 : this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
2864 :
2865 : // Perform mixing of core air stream and bypass air stream and set mass flow rates at outlet nodes
2866 79796 : this->SupOutEnth = (this->SupOutMassFlow * this->SupOutEnth + this->SupBypassMassFlow * this->SupInEnth) / this->SupInMassFlow;
2867 79796 : this->SupOutHumRat = (this->SupOutMassFlow * this->SupOutHumRat + this->SupBypassMassFlow * this->SupInHumRat) / this->SupInMassFlow;
2868 79796 : this->SupOutTemp = Psychrometrics::PsyTdbFnHW(this->SupOutEnth, this->SupOutHumRat);
2869 79796 : this->SupOutMassFlow = this->SupInMassFlow;
2870 79796 : this->SecOutEnth = (this->SecOutMassFlow * this->SecOutEnth + this->SecBypassMassFlow * this->SecInEnth) / this->SecInMassFlow;
2871 79796 : this->SecOutHumRat = (this->SecOutMassFlow * this->SecOutHumRat + this->SecBypassMassFlow * this->SecInHumRat) / this->SecInMassFlow;
2872 79796 : this->SecOutTemp = Psychrometrics::PsyTdbFnHW(this->SecOutEnth, this->SecOutHumRat);
2873 79796 : this->SecOutMassFlow = this->SecInMassFlow;
2874 79796 : break;
2875 :
2876 0 : case FrostControlOption::ExhaustAirRecirculation:
2877 : // Directing exhaust outlet air back across the HX core on the supply side
2878 : // Assume no heat exchange when in frost control mode, full heat exchange otherwise
2879 0 : DFFraction = max(0.0, min((this->InitialDefrostTime + this->RateofDefrostTimeIncrease * (TempThreshold - this->SupInTemp)), 1.0));
2880 :
2881 : // Calculate derated heat transfer using outlet air conditions assuming no defrost (calculated earlier)
2882 : // and (1-DefrostFraction)
2883 0 : QSensTrans = (1.0 - DFFraction) * CSup * (this->SupInTemp - this->SupOutTemp);
2884 0 : QTotTrans = (1.0 - DFFraction) * this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
2885 :
2886 0 : this->SupOutMassFlow = (1.0 - DFFraction) * this->SupInMassFlow + DFFraction * this->SecInMassFlow;
2887 :
2888 : // Blend supply outlet condition of HX core with exhaust air inlet to get final supply air outlet conditions
2889 0 : this->SupOutTemp = ((1.0 - DFFraction) * this->SupInMassFlow * this->SupOutTemp + DFFraction * this->SecInMassFlow * this->SecInTemp) /
2890 0 : this->SupOutMassFlow;
2891 :
2892 0 : this->SupOutHumRat =
2893 0 : ((1.0 - DFFraction) * this->SupInMassFlow * this->SupOutHumRat + DFFraction * this->SecInMassFlow * this->SecInHumRat) /
2894 0 : this->SupOutMassFlow;
2895 :
2896 0 : this->SupOutEnth = Psychrometrics::PsyHFnTdbW(this->SupOutTemp, this->SupOutHumRat);
2897 : // No need to check for saturation after SA out and EA inlet are blended
2898 :
2899 : // Derate effectiveness based on frost control time fraction for reporting purposes
2900 0 : this->SensEffectiveness *= (1.0 - DFFraction);
2901 0 : this->LatEffectiveness *= (1.0 - DFFraction);
2902 :
2903 : // Secondary air outlet conditions are previously calculated as the conditions when not
2904 : // in defrost, and this is what we want to report so no changes here.
2905 : // Average SupInMassFlow and SecOutMassFlow rates have been reduced due to frost control
2906 : // Equipment attached to the supply inlet node may have problems with our setting the
2907 : // mass flow rate in the next statement. This is done only to simulate exhaust air recirc.
2908 0 : state.dataLoopNodes->Node(this->SupInletNode).MassFlowRate = this->SupInMassFlow * (1.0 - DFFraction);
2909 0 : this->SecOutMassFlow *= (1.0 - DFFraction);
2910 0 : break;
2911 :
2912 0 : case FrostControlOption::ExhaustOnly:
2913 :
2914 : // Perform frost control by bypassing the supply air around the HX core during the defrost
2915 : // time period. HX heat transfer is reduced proportionally to (1 - defrosttimefraction)
2916 :
2917 0 : DFFraction = max(0.0, min((this->InitialDefrostTime + this->RateofDefrostTimeIncrease * (TempThreshold - this->SupInTemp)), 1.0));
2918 :
2919 : // Calculate derated heat transfer based on defrost time
2920 0 : QSensTrans = (1.0 - DFFraction) * CSup * (this->SupInTemp - this->SupOutTemp);
2921 0 : QTotTrans = (1.0 - DFFraction) * this->SupOutMassFlow * (this->SupInEnth - this->SupOutEnth);
2922 :
2923 : // Calculate the air conditions leaving heat exchanger unit
2924 : // Heat exchanger effectiveness is not derated, HX is fully bypassed during frost control
2925 :
2926 0 : this->SupBypassMassFlow = this->SupInMassFlow * DFFraction;
2927 0 : this->SupOutTemp = this->SupInTemp - QSensTrans / CSup;
2928 0 : this->SupOutEnth = this->SupInEnth - QTotTrans / this->SupOutMassFlow;
2929 0 : this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
2930 :
2931 0 : if (Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress) > this->SupOutTemp) {
2932 0 : this->SupOutTemp = Psychrometrics::PsyTsatFnHPb(state, this->SupOutEnth, state.dataEnvrn->OutBaroPress);
2933 0 : this->SupOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SupOutTemp, this->SupOutEnth);
2934 0 : QSensTrans = CSup * (this->SupInTemp - this->SupOutTemp);
2935 : // Should we be updating the sensible and latent effectiveness values also?
2936 : }
2937 :
2938 0 : this->SecOutEnth = this->SecInEnth + QTotTrans / this->SecOutMassFlow;
2939 0 : this->SecOutTemp = this->SecInTemp + QSensTrans / CSec;
2940 0 : this->SecOutHumRat = Psychrometrics::PsyWFnTdbH(state, this->SecOutTemp, this->SecOutEnth);
2941 0 : break;
2942 0 : default:
2943 0 : break; // :: None means don't do anything here, and ::Invalid is caught on GetInput
2944 : }
2945 :
2946 79796 : this->DefrostFraction = DFFraction;
2947 79796 : }
2948 :
2949 3964330 : void HeatExchCond::UpdateHeatRecovery(EnergyPlusData &state)
2950 : {
2951 :
2952 : // SUBROUTINE INFORMATION:
2953 : // AUTHOR Michael Wetter
2954 : // DATE WRITTEN March 1999
2955 : // MODIFIED Fred Buhl November 2000
2956 : // RE-ENGINEERED na
2957 :
2958 : // PURPOSE OF THIS SUBROUTINE:
2959 : // Moves heat exchanger output to the outlet nodes.
2960 :
2961 3964330 : int const SupInNode = this->SupInletNode;
2962 3964330 : int const SupOutNode = this->SupOutletNode;
2963 3964330 : int const SecInNode = this->SecInletNode;
2964 3964330 : int const SecOutNode = this->SecOutletNode;
2965 :
2966 3964330 : auto &thisSupInNode = state.dataLoopNodes->Node(SupInNode);
2967 3964330 : auto &thisSupOutNode = state.dataLoopNodes->Node(SupOutNode);
2968 3964330 : auto &thisSecInNode = state.dataLoopNodes->Node(SecInNode);
2969 3964330 : auto &thisSecOutNode = state.dataLoopNodes->Node(SecOutNode);
2970 :
2971 : // Set the outlet air nodes of the heat exchanger
2972 3964330 : thisSupOutNode.Temp = this->SupOutTemp;
2973 3964330 : thisSupOutNode.HumRat = this->SupOutHumRat;
2974 3964330 : thisSupOutNode.Enthalpy = this->SupOutEnth;
2975 3964330 : thisSupOutNode.MassFlowRate = this->SupOutMassFlow;
2976 3964330 : thisSecOutNode.Temp = this->SecOutTemp;
2977 3964330 : thisSecOutNode.HumRat = this->SecOutHumRat;
2978 3964330 : thisSecOutNode.Enthalpy = this->SecOutEnth;
2979 3964330 : thisSecOutNode.MassFlowRate = this->SecOutMassFlow;
2980 :
2981 : // Set the outlet nodes for properties that just pass through & not used
2982 3964330 : thisSupOutNode.Quality = thisSupInNode.Quality;
2983 3964330 : thisSupOutNode.Press = thisSupInNode.Press;
2984 3964330 : thisSupOutNode.MassFlowRateMin = thisSupInNode.MassFlowRateMin;
2985 3964330 : thisSupOutNode.MassFlowRateMax = thisSupInNode.MassFlowRateMax;
2986 3964330 : thisSupOutNode.MassFlowRateMinAvail = thisSupInNode.MassFlowRateMinAvail;
2987 3964330 : thisSupOutNode.MassFlowRateMaxAvail = thisSupInNode.MassFlowRateMaxAvail;
2988 3964330 : thisSecOutNode.Quality = thisSecInNode.Quality;
2989 3964330 : thisSecOutNode.Press = thisSecInNode.Press;
2990 3964330 : thisSecOutNode.MassFlowRateMin = thisSecInNode.MassFlowRateMin;
2991 3964330 : thisSecOutNode.MassFlowRateMax = thisSecInNode.MassFlowRateMax;
2992 3964330 : thisSecOutNode.MassFlowRateMinAvail = thisSecInNode.MassFlowRateMinAvail;
2993 3964330 : thisSecOutNode.MassFlowRateMaxAvail = thisSecInNode.MassFlowRateMaxAvail;
2994 :
2995 3964330 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2996 23997 : thisSupOutNode.CO2 = thisSupInNode.CO2;
2997 23997 : thisSecOutNode.CO2 = thisSecInNode.CO2;
2998 : }
2999 3964330 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
3000 0 : thisSupOutNode.GenContam = thisSupInNode.GenContam;
3001 0 : thisSecOutNode.GenContam = thisSecInNode.GenContam;
3002 : }
3003 3964330 : }
3004 :
3005 3964330 : void HeatExchCond::ReportHeatRecovery(EnergyPlusData &state)
3006 : {
3007 :
3008 : // SUBROUTINE INFORMATION:
3009 : // AUTHOR Michael Wetter
3010 : // DATE WRITTEN March 1999
3011 : // MODIFIED F Buhl Nov 2000, D Shirey Feb/June 2003
3012 : // RE-ENGINEERED na
3013 :
3014 : // PURPOSE OF THIS SUBROUTINE:
3015 : // Fill remaining report variables
3016 :
3017 3964330 : Real64 const ReportingConstant = state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
3018 3964330 : this->ElecUseEnergy = this->ElecUseRate * ReportingConstant;
3019 3964330 : this->SensHeatingEnergy = this->SensHeatingRate * ReportingConstant;
3020 3964330 : this->LatHeatingEnergy = this->LatHeatingRate * ReportingConstant;
3021 3964330 : this->TotHeatingEnergy = this->TotHeatingRate * ReportingConstant;
3022 3964330 : this->SensCoolingEnergy = this->SensCoolingRate * ReportingConstant;
3023 3964330 : this->LatCoolingEnergy = this->LatCoolingRate * ReportingConstant;
3024 3964330 : this->TotCoolingEnergy = this->TotCoolingRate * ReportingConstant;
3025 :
3026 3964330 : state.dataHVACGlobal->AirToAirHXElecPower = this->ElecUseRate;
3027 3964330 : }
3028 :
3029 2714207 : Real64 SafeDiv(Real64 const a, Real64 const b)
3030 : {
3031 :
3032 : // SUBROUTINE INFORMATION:
3033 : // AUTHOR Michael Wetter
3034 : // DATE WRITTEN March 1999
3035 : // MODIFIED na
3036 : // RE-ENGINEERED na
3037 :
3038 : // PURPOSE OF THIS FUNCTION:
3039 : // Returns a / b while preventing division by zero
3040 :
3041 : // METHODOLOGY EMPLOYED:
3042 : // Check for small or zero values before performing division
3043 :
3044 2714207 : if (std::abs(b) < SMALL) {
3045 20 : return a / sign(SMALL, b);
3046 : } else {
3047 2714187 : return a / b;
3048 : }
3049 : }
3050 :
3051 576994 : Real64 CalculateEpsFromNTUandZ(EnergyPlusData &state,
3052 : Real64 const NTU, // number of transfer units
3053 : Real64 const Z, // capacity rate ratio
3054 : HXConfiguration const FlowArr // flow arrangement
3055 : )
3056 : {
3057 :
3058 : // SUBROUTINE INFORMATION:
3059 : // AUTHOR Michael Wetter
3060 : // DATE WRITTEN March 1999
3061 : // MODIFIED Fred Buhl November 2000
3062 : // RE-ENGINEERED na
3063 :
3064 : // PURPOSE OF THIS SUBROUTINE:
3065 : // Calculates eps, the exchanger effectiveness,
3066 : // from NTU, the number of transfer units,
3067 : // from Z, the capacity rate ratio, and
3068 : // from the flow arrangement
3069 :
3070 : // METHODOLOGY EMPLOYED:
3071 : // Uses the effectiveness - NTU heat exchanger formulas
3072 :
3073 : // REFERENCES:
3074 : // M. Wetter, Simulation Model Air-to-Air Plate Heat Exchanger
3075 : // LBNL Report 42354, 1999.
3076 : // Also see:
3077 : // ASHRAE HVAC 2 Toolkit, pages 4-3 through 4-5
3078 :
3079 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3080 : Real64 Temp; // temporary variable
3081 576994 : Real64 Eps = 0.0; // heat exchanger effectiveness, return value
3082 :
3083 : // check input validity
3084 576994 : if (Z < 0.0 || Z > 1.0) {
3085 0 : ShowFatalError(state, format("Variable Z ({:.2R}) out of range [0.0,1.0] in CalculateEpsFromNTUandZ", Z));
3086 : }
3087 :
3088 : // effectiveness
3089 576994 : if (NTU < SMALL) {
3090 0 : Eps = 0.0;
3091 576994 : } else if (Z < SMALL) { // Eps independent of flow arrangement
3092 0 : Eps = 1.0 - std::exp(-NTU);
3093 : } else {
3094 576994 : switch (FlowArr) {
3095 565985 : case HXConfiguration::CounterFlow: { // COUNTER FLOW
3096 565985 : if (std::abs(Z - 1.0) < SMALL) {
3097 147147 : Eps = NTU / (NTU + 1.0);
3098 : } else {
3099 418838 : Temp = std::exp(-NTU * (1.0 - Z));
3100 418838 : Eps = (1.0 - Temp) / (1.0 - Z * Temp);
3101 : }
3102 565985 : } break;
3103 0 : case HXConfiguration::ParallelFlow: { // PARALLEL FLOW
3104 0 : Temp = (1.0 + Z);
3105 0 : Eps = (1.0 - std::exp(-NTU * Temp)) / Temp;
3106 0 : } break;
3107 11009 : case HXConfiguration::CrossFlowBothUnmixed: { // CROSS FLOW BOTH UNMIXED
3108 11009 : Temp = Z * std::pow(NTU, -0.22);
3109 11009 : Eps = 1.0 - std::exp((std::exp(-NTU * Temp) - 1.0) / Temp);
3110 11009 : } break;
3111 0 : case HXConfiguration::CrossFlowOther: { // CROSS FLOW, Cmax MIXED, Cmin UNMIXED
3112 0 : Eps = (1.0 - std::exp(-Z * (1.0 - std::exp(-NTU)))) / Z;
3113 0 : } break;
3114 0 : default: {
3115 0 : ShowFatalError(state, format("HeatRecovery: Illegal flow arrangement in CalculateEpsFromNTUandZ, Value={}", FlowArr));
3116 0 : } break;
3117 : }
3118 : }
3119 576994 : return Eps;
3120 : }
3121 :
3122 81 : void CalculateNTUfromEpsAndZ(EnergyPlusData &state,
3123 : Real64 &NTU, // number of transfer units
3124 : CalculateNTUBoundsErrors &Err, // error indicator
3125 : Real64 const Z, // capacity rate ratio
3126 : HXConfiguration const FlowArr, // flow arrangement
3127 : Real64 const Eps // heat exchanger effectiveness
3128 : )
3129 : {
3130 :
3131 : // SUBROUTINE INFORMATION:
3132 : // AUTHOR Michael Wetter
3133 : // DATE WRITTEN March 1999
3134 : // MODIFIED Fred Buhl November 2000
3135 : // RE-ENGINEERED na
3136 :
3137 : // PURPOSE OF THIS SUBROUTINE:
3138 : // Calculates NTU, the number of transfer units,
3139 : // based on eps, the exchanger effectiveness,
3140 : // Z, the capacity rate ratio, and
3141 : // from the flow arrangement
3142 :
3143 : // METHODOLOGY EMPLOYED:
3144 : // Uses the effectiveness - NTU heat exchanger formulas
3145 :
3146 : // REFERENCES:
3147 : // M. Wetter, Simulation Model Air-to-Air Plate Heat Exchanger
3148 : // LBNL Report 42354, 1999.
3149 : // Also see:
3150 : // ASHRAE HVAC 2 Toolkit, pages 4-3 through 4-5
3151 :
3152 81 : NTU = 0.0;
3153 : // check input validity
3154 81 : if (Z < 0.0 || Z > 1.0) {
3155 0 : Err = CalculateNTUBoundsErrors::MassFlowRatio;
3156 0 : return;
3157 : }
3158 :
3159 81 : if (FlowArr == HXConfiguration::ParallelFlow) {
3160 0 : if (Eps < 0.0 || Eps > 1.0 / (1.0 + Z)) {
3161 0 : Err = CalculateNTUBoundsErrors::NominalEffectiveness1;
3162 0 : return;
3163 : }
3164 81 : } else if (FlowArr == HXConfiguration::CrossFlowOther) {
3165 0 : if (Eps < 0.0 || Eps > (1.0 - std::exp(-Z)) / Z) {
3166 0 : Err = CalculateNTUBoundsErrors::NominalEffectiveness2;
3167 0 : return;
3168 : }
3169 : // check product (Eps*Z)
3170 0 : if (Eps * Z < 0.0 || Eps * Z > 1.0 - std::exp(Z * (SMALL - 1.0))) {
3171 0 : Err = CalculateNTUBoundsErrors::Quantity;
3172 0 : return;
3173 : }
3174 : // check product (Eps*Z)
3175 : } else {
3176 81 : if (Eps < 0.0 || Eps > 1.0) {
3177 0 : Err = CalculateNTUBoundsErrors::NominalEffectiveness3;
3178 0 : return;
3179 : }
3180 : }
3181 :
3182 81 : if (Eps < SMALL) { // no effectiveness. Set NTU = 0
3183 0 : NTU = 0.0;
3184 81 : } else if (Z < SMALL) { // Eps independent of flow arrangement
3185 0 : NTU = -std::log(1.0 - Eps);
3186 : } else {
3187 : // calculate based on configuration
3188 81 : switch (FlowArr) {
3189 69 : case HXConfiguration::CounterFlow: { // COUNTER FLOW
3190 69 : if (std::abs(Z - 1.0) < SMALL) {
3191 63 : NTU = Eps / (1.0 - Eps);
3192 : } else {
3193 6 : NTU = 1.0 / (Z - 1.0) * std::log((1.0 - Eps) / (1.0 - Eps * Z));
3194 : }
3195 69 : } break;
3196 0 : case HXConfiguration::ParallelFlow: { // PARALLEL FLOW
3197 0 : NTU = -std::log(-Eps - Eps * Z + 1.0) / (Z + 1.0);
3198 0 : } break;
3199 12 : case HXConfiguration::CrossFlowBothUnmixed: { // CROSS FLOW BOTH UNMIXED
3200 12 : NTU = GetNTUforCrossFlowBothUnmixed(state, Eps, Z);
3201 12 : } break;
3202 0 : case HXConfiguration::CrossFlowOther: { // CROSS FLOW, Cmax MIXED, Cmin UNMIXED
3203 0 : NTU = -std::log(1.0 + std::log(1.0 - Eps * Z) / Z);
3204 0 : } break;
3205 0 : default: {
3206 0 : ShowFatalError(state, format("HeatRecovery: Illegal flow arrangement in CalculateNTUfromEpsAndZ, Value={}", FlowArr));
3207 0 : } break;
3208 : }
3209 : }
3210 : }
3211 :
3212 12 : Real64 GetNTUforCrossFlowBothUnmixed(EnergyPlusData &state,
3213 : Real64 const Eps, // heat exchanger effectiveness
3214 : Real64 const Z // capacity rate ratio
3215 : )
3216 : {
3217 :
3218 : // FUNCTION INFORMATION:
3219 : // AUTHOR Michael Wetter
3220 : // DATE WRITTEN March 1999
3221 : // MODIFIED Fred Buhl November 2000
3222 : // RE-ENGINEERED na
3223 :
3224 : // PURPOSE OF THIS FUNCTION:
3225 : // Calculates the NTU value based on the exchanger effectiveness
3226 : // and the capacity ratio for cross flow exchanger, both
3227 : // streams unmixed
3228 :
3229 : // METHODOLOGY EMPLOYED:
3230 : // Uses a Regula Falsi solver function to numerically invert the formula
3231 : // giving effectiveness as a function of NTU and Z..
3232 :
3233 : // REFERENCES:
3234 : // M. Wetter, Simulation Model Air-to-Air Plate Heat Exchanger
3235 : // LBNL Report 42354, 1999.
3236 : // Also see:
3237 : // ASHRAE HVAC 2 Toolkit, pages 4-3 through 4-5
3238 :
3239 : // Return value
3240 : Real64 NTU; // result variable; number of transfer units
3241 :
3242 : // FUNCTION PARAMETER DEFINITIONS:
3243 12 : Real64 constexpr Acc(0.0001); // Accuracy of result
3244 12 : int constexpr MaxIte(500); // Maximum number of iterations
3245 :
3246 : int SolFla; // Flag of solver
3247 12 : Real64 constexpr NTU0(0.0); // lower bound for NTU
3248 12 : Real64 constexpr NTU1(50.0); // upper bound for NTU
3249 336 : auto f = [Eps, Z](Real64 const NTU) { return 1.0 - std::exp((std::exp(-std::pow(NTU, 0.78) * Z) - 1.0) / Z * std::pow(NTU, 0.22)) - Eps; };
3250 12 : General::SolveRoot(state, Acc, MaxIte, SolFla, NTU, f, NTU0, NTU1);
3251 :
3252 12 : if (SolFla == -2) {
3253 0 : ShowFatalError(state, "HeatRecovery: Bad initial bounds for NTU in GetNTUforCrossFlowBothUnmixed");
3254 12 : } else if (SolFla == -1) {
3255 0 : ShowFatalError(state, "HeatRecovery: No convergence in solving for NTU in GetNTUforCrossFlowBothUnmixed");
3256 : }
3257 :
3258 12 : return NTU;
3259 : }
3260 :
3261 103147 : void HeatExchCond::CheckModelBoundsTempEq(EnergyPlusData &state,
3262 : Real64 &T_RegenInTemp, // current regen inlet temperature (C) for regen outlet temp eqn
3263 : Real64 &T_RegenInHumRat, // current regen inlet hum rat for regen outlet temp eqn
3264 : Real64 &T_ProcInTemp, // current process inlet temperature (C) for regen outlet temp eqn
3265 : Real64 &T_ProcInHumRat, // current process inlet hum rat for regen outlet temp eqn
3266 : Real64 &T_FaceVel, // current process and regen face velocity (m/s)
3267 : bool const FirstHVACIteration // First HVAC iteration flag
3268 : ) const
3269 : {
3270 :
3271 : // SUBROUTINE INFORMATION:
3272 : // AUTHOR Mangesh Basarkar, FSEC
3273 : // DATE WRITTEN January 2007
3274 : // MODIFIED na
3275 : // RE-ENGINEERED na
3276 :
3277 : // PURPOSE OF THIS SUBROUTINE:
3278 : // To verify that the empirical model's independent variables are within the limits used during the
3279 : // developement of the empirical model.
3280 :
3281 : // METHODOLOGY EMPLOYED:
3282 : // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
3283 : // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
3284 : // The range of each independent variable is provided by the user and are based on the limits of the
3285 : // empirical model. These limits are tested in this subroutine each time step and returned for use by the calling
3286 : // routine.
3287 :
3288 : // Using/Aliasing
3289 103147 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
3290 103147 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
3291 : using General::CreateSysTimeIntervalString;
3292 :
3293 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3294 103147 : auto &OutputChar = state.dataHeatRecovery->error1.OutputChar;
3295 103147 : auto &OutputCharLo = state.dataHeatRecovery->error1.OutputCharLo;
3296 103147 : auto &OutputCharHi = state.dataHeatRecovery->error1.OutputCharHi;
3297 103147 : auto &CharValue = state.dataHeatRecovery->error1.CharValue;
3298 103147 : auto &TimeStepSysLast = state.dataHeatRecovery->error1.TimeStepSysLast;
3299 103147 : auto &CurrentEndTime = state.dataHeatRecovery->error1.CurrentEndTime;
3300 103147 : auto &CurrentEndTimeLast = state.dataHeatRecovery->error1.CurrentEndTimeLast;
3301 : // current end time is compared with last to see if time step changed
3302 :
3303 : // calculate end time of current time step
3304 103147 : CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
3305 :
3306 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
3307 : // Wait for next time step to print warnings. If simulation iterates, print out
3308 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
3309 : // If a warning occurs and the simulation down shifts, the warning is not valid.
3310 103147 : if (CurrentEndTime > CurrentEndTimeLast && TimeStepSys >= TimeStepSysLast) {
3311 :
3312 : // print error for variables of regeneration outlet temperature equation
3313 : // Regen inlet temp for temp eqn
3314 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.print) {
3315 30 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.count;
3316 30 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.count < 2) {
3317 1 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer1);
3318 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer2);
3319 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer3);
3320 1 : ShowContinueError(state,
3321 : "...Using regeneration inlet air temperatures that are outside the regeneration outlet air temperature "
3322 : "equation model boundaries may adversely affect desiccant model performance.");
3323 : } else {
3324 174 : ShowRecurringWarningErrorAtEnd(state,
3325 116 : format("{} \"{}\" - Regeneration inlet air temp used in regen outlet air temperature equation is "
3326 : "out of range error continues...",
3327 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3328 58 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
3329 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.index,
3330 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.last,
3331 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.last);
3332 : }
3333 : }
3334 : // Regen inlet humidity ratio for temp eqn
3335 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.print) {
3336 0 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.count;
3337 0 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.count < 2) {
3338 0 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer1);
3339 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer2);
3340 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer3);
3341 0 : ShowContinueError(state,
3342 : "...Using regeneration inlet air humidity ratios that are outside the regeneration outlet air temperature "
3343 : "equation model boundaries may adversely affect desiccant model performance.");
3344 : } else {
3345 0 : ShowRecurringWarningErrorAtEnd(state,
3346 0 : format("{} \"{}\" - Regeneration inlet air humidity ratio used in regen outlet temperature "
3347 : "equation is out of range error continues...",
3348 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3349 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
3350 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.index,
3351 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.last,
3352 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.last);
3353 : }
3354 : }
3355 : // Process inlet temp for temp eqn
3356 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print) {
3357 3 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.count;
3358 3 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.count < 2) {
3359 1 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer1);
3360 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer2);
3361 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer3);
3362 1 : ShowContinueError(state,
3363 : "...Using process inlet air temperatures that are outside the regeneration outlet air temperature equation "
3364 : "model boundaries may adversely affect desiccant model performance.");
3365 : } else {
3366 12 : ShowRecurringWarningErrorAtEnd(
3367 : state,
3368 8 : format(
3369 : "{} \"{}\" - Process inlet air temperature used in regen outlet temperature equation is out of range error continues...",
3370 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3371 4 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
3372 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.index,
3373 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.last,
3374 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.last);
3375 : }
3376 : }
3377 : // Process inlet humidity ratio for temp eqn
3378 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print) {
3379 0 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.count;
3380 0 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.count < 2) {
3381 0 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer1);
3382 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer2);
3383 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer3);
3384 0 : ShowContinueError(state,
3385 : "...Using process inlet air humidity ratios that are outside the regeneratoin outlet air temperature equation "
3386 : "model boundaries may adversely affect desiccant model performance.");
3387 : } else {
3388 0 : ShowRecurringWarningErrorAtEnd(state,
3389 0 : format("{} \"{}\" - Process inlet air humidity ratio used in regen outlet temperature equation is "
3390 : "out of range error continues...",
3391 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3392 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
3393 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.index,
3394 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.last,
3395 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.last);
3396 : }
3397 : }
3398 : // Process and regeneration face velocity for temp eqn
3399 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.print) {
3400 0 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.count;
3401 0 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.count < 2) {
3402 0 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer1);
3403 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer2);
3404 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer3);
3405 0 : ShowContinueError(state,
3406 : "...Using process and regeneration face velocities that are outside the regeneration outlet air temperature "
3407 : "equation model boundaries may adversely affect desiccant model performance.");
3408 : } else {
3409 0 : ShowRecurringWarningErrorAtEnd(state,
3410 0 : format("{} \"{}\" - Process and regen inlet air face velocity used in regen outlet temperature "
3411 : "equation is out of range error continues...",
3412 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3413 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
3414 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.index,
3415 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.last,
3416 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.last);
3417 : }
3418 : }
3419 : } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
3420 :
3421 : // save last system time step and last end time of current time step (used to determine if warning is valid)
3422 103147 : TimeStepSysLast = TimeStepSys;
3423 103147 : CurrentEndTimeLast = CurrentEndTime;
3424 :
3425 : // If regen and procees inlet temperatures are the same the coil is off, do not print out of bounds warning for this case
3426 103147 : if (std::abs(T_RegenInTemp - T_ProcInTemp) < SMALL) {
3427 805 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.print = false;
3428 805 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.print = false;
3429 805 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print = false;
3430 805 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print = false;
3431 805 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.print = false;
3432 805 : return;
3433 : }
3434 :
3435 : // check boundaries of independent variables and post warnings to individual buffers to print at end of time step
3436 : // checking model bounds for variables of regeneration outlet temperature equation
3437 : // Regen inlet temp
3438 204161 : if (T_RegenInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInTemp ||
3439 101819 : T_RegenInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInTemp) {
3440 523 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.last = T_RegenInTemp;
3441 523 : OutputChar = format("{:.2R}", T_RegenInTemp);
3442 523 : OutputCharLo = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInTemp);
3443 523 : OutputCharHi = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInTemp);
3444 523 : if (T_RegenInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInTemp) {
3445 523 : T_RegenInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInTemp;
3446 : }
3447 523 : if (T_RegenInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInTemp) {
3448 0 : T_RegenInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInTemp;
3449 : }
3450 523 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
3451 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.print = true;
3452 136 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer1 = format(
3453 : "{} \"{}\" - Regeneration inlet air temperature used in regen outlet air temperature equation is outside model boundaries at {}.",
3454 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3455 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
3456 68 : OutputChar);
3457 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer2 =
3458 136 : format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
3459 : OutputCharLo,
3460 : OutputCharHi,
3461 34 : state.dataEnvrn->EnvironmentName,
3462 34 : state.dataEnvrn->CurMnDy,
3463 136 : CreateSysTimeIntervalString(state));
3464 34 : CharValue = format("{:.6R}", T_RegenInTemp);
3465 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.buffer3 =
3466 102 : format("...Regeneration outlet air temperature equation: regeneration inlet air temperature passed to the model = {}", CharValue);
3467 : } else {
3468 489 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.print = false;
3469 : }
3470 : } else {
3471 101819 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInTempError.print = false;
3472 : }
3473 : // regen inlet humidity ratio
3474 204684 : if (T_RegenInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInHumRat ||
3475 102342 : T_RegenInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInHumRat) {
3476 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.last = T_RegenInHumRat;
3477 0 : OutputChar = format("{:.6R}", T_RegenInHumRat);
3478 0 : OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInHumRat);
3479 0 : OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInHumRat);
3480 0 : if (T_RegenInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInHumRat) {
3481 0 : T_RegenInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInHumRat;
3482 : }
3483 0 : if (T_RegenInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInHumRat) {
3484 0 : T_RegenInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInHumRat;
3485 : }
3486 0 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
3487 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.print = true;
3488 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer1 =
3489 0 : format("{} \"{}\" - Regeneration inlet air humidity ratio used in regen outlet air temperature equation is outside model "
3490 : "boundaries at {}.",
3491 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3492 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
3493 0 : OutputChar);
3494 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer2 =
3495 0 : format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
3496 : OutputCharLo,
3497 : OutputCharHi,
3498 0 : state.dataEnvrn->EnvironmentName,
3499 0 : state.dataEnvrn->CurMnDy,
3500 0 : CreateSysTimeIntervalString(state));
3501 0 : CharValue = format("{:.6R}", T_RegenInHumRat);
3502 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.buffer3 = format(
3503 0 : "...Regeneration outlet air temperature equation: regeneration inlet air humidity ratio passed to the model = {}", CharValue);
3504 : } else {
3505 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.print = false;
3506 : }
3507 : } else {
3508 102342 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_RegenInHumRatError.print = false;
3509 : }
3510 : // process inlet temp
3511 204684 : if (T_ProcInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInTemp ||
3512 102342 : T_ProcInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInTemp) {
3513 3084 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.last = T_ProcInTemp;
3514 3084 : OutputChar = format("{:.2R}", T_ProcInTemp);
3515 3084 : OutputCharLo = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInTemp);
3516 3084 : OutputCharHi = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInTemp);
3517 3084 : if (T_ProcInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInTemp) {
3518 0 : T_ProcInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInTemp;
3519 : }
3520 3084 : if (T_ProcInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInTemp) {
3521 3084 : T_ProcInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInTemp;
3522 : }
3523 3084 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
3524 115 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print = true;
3525 : // Suppress warning message when process inlet temperature = 0 (DX coil is off)
3526 115 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.last == 0.0)
3527 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print = false;
3528 460 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer1 = format(
3529 : "{} \"{}\" - Process inlet air temperature used in regen outlet air temperature equation is outside model boundaries at {}.",
3530 115 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3531 115 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
3532 230 : OutputChar);
3533 230 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer2 =
3534 460 : format("...Valid range = {} to {}. Occurrence info = {},{} {}",
3535 : OutputCharLo,
3536 : OutputCharHi,
3537 115 : state.dataEnvrn->EnvironmentName,
3538 115 : state.dataEnvrn->CurMnDy,
3539 460 : CreateSysTimeIntervalString(state));
3540 115 : CharValue = format("{:.6R}", T_ProcInTemp);
3541 230 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.buffer3 =
3542 345 : format("...Regeneration outlet air temperature equation: process inlet air temperature passed to the model = {}", CharValue);
3543 : } else {
3544 2969 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print = false;
3545 : }
3546 : } else {
3547 99258 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInTempError.print = false;
3548 : }
3549 : // process inlet humidity ratio
3550 204668 : if (T_ProcInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInHumRat ||
3551 102326 : T_ProcInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInHumRat) {
3552 26 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.last = T_ProcInHumRat;
3553 26 : OutputChar = format("{:.6R}", T_ProcInHumRat);
3554 26 : OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInHumRat);
3555 26 : OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInHumRat);
3556 26 : if (T_ProcInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInHumRat) {
3557 16 : T_ProcInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInHumRat;
3558 : }
3559 26 : if (T_ProcInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInHumRat) {
3560 10 : T_ProcInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInHumRat;
3561 : }
3562 26 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
3563 1 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print = true;
3564 : // Suppress warning message when process inlet humrat = 0 (DX coil is off)
3565 1 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.last == 0.0)
3566 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print = false;
3567 4 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer1 = format(
3568 : "{} \"{}\" - Process inlet air humidity ratio used in regen outlet air temperature equation is outside model boundaries at {}.",
3569 1 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3570 1 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
3571 2 : OutputChar);
3572 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer2 =
3573 4 : format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
3574 : OutputCharLo,
3575 : OutputCharHi,
3576 1 : state.dataEnvrn->EnvironmentName,
3577 1 : state.dataEnvrn->CurMnDy,
3578 4 : CreateSysTimeIntervalString(state));
3579 1 : CharValue = format("{:.6R}", T_ProcInHumRat);
3580 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.buffer3 =
3581 3 : format("...Regeneration outlet air temperature equation: process inlet air humidity ratio passed to the model = {}", CharValue);
3582 : } else {
3583 25 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print = false;
3584 : }
3585 : } else {
3586 102316 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.print = false;
3587 : }
3588 : // regeneration and process face velocity
3589 204684 : if (T_FaceVel < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinFaceVel ||
3590 102342 : T_FaceVel > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxFaceVel) {
3591 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.last = T_FaceVel;
3592 0 : OutputChar = format("{:.6R}", T_FaceVel);
3593 0 : OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinFaceVel);
3594 0 : OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxFaceVel);
3595 0 : if (T_FaceVel < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinFaceVel) {
3596 0 : T_FaceVel = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinFaceVel;
3597 : }
3598 0 : if (T_FaceVel > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxFaceVel) {
3599 0 : T_FaceVel = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxFaceVel;
3600 : }
3601 0 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
3602 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.print = true;
3603 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer1 =
3604 0 : format("{} \"{}\" - Process and regen inlet air face velocity used in regen outlet air temperature equation is outside model "
3605 : "boundaries at {}.",
3606 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3607 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
3608 0 : OutputChar);
3609 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer2 =
3610 0 : format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
3611 : OutputCharLo,
3612 : OutputCharHi,
3613 0 : state.dataEnvrn->EnvironmentName,
3614 0 : state.dataEnvrn->CurMnDy,
3615 0 : CreateSysTimeIntervalString(state));
3616 0 : CharValue = format("{:.6R}", T_FaceVel);
3617 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.buffer3 =
3618 0 : format("...Regeneration outlet air temperature equation: process and regen face velocity passed to the model = {}", CharValue);
3619 : } else {
3620 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.print = false;
3621 : }
3622 : } else {
3623 102342 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_FaceVelError.print = false;
3624 : }
3625 : }
3626 :
3627 103147 : void HeatExchCond::CheckModelBoundsHumRatEq(EnergyPlusData &state,
3628 : Real64 &H_RegenInTemp, // current regen inlet temperature (C) for regen outlet hum rat eqn
3629 : Real64 &H_RegenInHumRat, // current regen inlet hum rat for regen outlet hum rat eqn
3630 : Real64 &H_ProcInTemp, // current process inlet temperature (C) for regen outlet hum rat eqn
3631 : Real64 &H_ProcInHumRat, // current process inlet hum rat for regen outlet hum rat eqn
3632 : Real64 &H_FaceVel, // current process and regen face velocity (m/s)
3633 : bool const FirstHVACIteration // First HVAC iteration flag
3634 : ) const
3635 : {
3636 :
3637 : // SUBROUTINE INFORMATION:
3638 : // AUTHOR Mangesh Basarkar, FSEC
3639 : // DATE WRITTEN January 2007
3640 : // MODIFIED na
3641 : // RE-ENGINEERED na
3642 :
3643 : // PURPOSE OF THIS SUBROUTINE:
3644 : // To verify that the empirical model's independent variables are within the limits used during the
3645 : // developement of the empirical model.
3646 :
3647 : // METHODOLOGY EMPLOYED:
3648 : // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
3649 : // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
3650 : // The range of each independent variable is provided by the user and are based on the limits of the
3651 : // empirical model. These limits are tested in this subroutine each time step and returned for use by the calling
3652 : // routine.
3653 :
3654 : // Using/Aliasing
3655 103147 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
3656 103147 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
3657 : using General::CreateSysTimeIntervalString;
3658 :
3659 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3660 103147 : auto &OutputChar = state.dataHeatRecovery->error2.OutputChar;
3661 103147 : auto &OutputCharLo = state.dataHeatRecovery->error2.OutputCharLo;
3662 103147 : auto &OutputCharHi = state.dataHeatRecovery->error2.OutputCharHi;
3663 103147 : auto &CharValue = state.dataHeatRecovery->error2.CharValue;
3664 103147 : auto &TimeStepSysLast = state.dataHeatRecovery->error2.TimeStepSysLast;
3665 103147 : auto &CurrentEndTime = state.dataHeatRecovery->error2.CurrentEndTime;
3666 103147 : auto &CurrentEndTimeLast = state.dataHeatRecovery->error2.CurrentEndTimeLast;
3667 :
3668 : // current end time is compared with last to see if time step changed
3669 :
3670 : // calculate end time of current time step
3671 103147 : CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
3672 :
3673 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
3674 : // Wait for next time step to print warnings. If simulation iterates, print out
3675 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
3676 : // If a warning occurs and the simulation down shifts, the warning is not valid.
3677 103147 : if (CurrentEndTime > CurrentEndTimeLast && TimeStepSys >= TimeStepSysLast) {
3678 :
3679 : // print error for variables of regeneration outlet humidity ratio equation
3680 : // Regen inlet temp for humidity ratio eqn
3681 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.print) {
3682 30 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.count;
3683 30 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.count < 2) {
3684 1 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer1);
3685 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer2);
3686 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer3);
3687 1 : ShowContinueError(state,
3688 : "...Using regeneration inlet air temperatures that are outside the regeneration inlet air temperature equation "
3689 : "model boundaries may adversely affect desiccant model performance.");
3690 : } else {
3691 174 : ShowRecurringWarningErrorAtEnd(state,
3692 116 : format("{} \"{}\" - Regeneration inlet air temperature used in regen outlet air humidity ratio "
3693 : "equation is out of range error continues...",
3694 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3695 58 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
3696 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.index,
3697 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.last,
3698 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.last);
3699 : }
3700 : }
3701 : // Regen inlet humidity ratio for humidity ratio eqn
3702 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.print) {
3703 0 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.count;
3704 0 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.count < 2) {
3705 0 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer1);
3706 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer2);
3707 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer3);
3708 0 : ShowContinueError(state,
3709 : "...Using regeneration inlet air humidity ratios that are outside the regeneration outlet air humidity ratio "
3710 : "equation model boundaries may adversely affect desiccant model performance.");
3711 : } else {
3712 0 : ShowRecurringWarningErrorAtEnd(state,
3713 0 : format("{} \"{}\" - Regeneration inlet air humidity ratio used in regen outlet air humidity ratio "
3714 : "equation is out of range error continues...",
3715 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3716 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
3717 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.index,
3718 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.last,
3719 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.last);
3720 : }
3721 : }
3722 : // Process inlet temp for humidity ratio eqn
3723 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print) {
3724 3 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.count;
3725 3 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.count < 2) {
3726 1 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer1);
3727 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer2);
3728 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer3);
3729 1 : ShowContinueError(state,
3730 : "...Using process inlet air temperatures that are outside the regeneration outlet air humidity ratio equation "
3731 : "model may adversely affect desiccant model performance.");
3732 : } else {
3733 12 : ShowRecurringWarningErrorAtEnd(state,
3734 8 : format("{} \"{}\" - Process inlet air temperature used in regen outlet air humidity ratio "
3735 : "equation is out of range error continues...",
3736 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3737 4 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
3738 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.index,
3739 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.last,
3740 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.last);
3741 : }
3742 : }
3743 : // Process inlet humidity ratio for humidity ratio eqn
3744 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print) {
3745 0 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.count;
3746 0 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.count < 2) {
3747 0 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer1);
3748 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer2);
3749 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer3);
3750 0 : ShowContinueError(state,
3751 : "...Using process inlet air humidity ratios that are outside the regeneration outlet humidity ratio equation "
3752 : "model boundaries may adversely affect desiccant model performance.");
3753 : } else {
3754 0 : ShowRecurringWarningErrorAtEnd(state,
3755 0 : format("{} \"{}\" - Process inlet air humidity ratio used in regen outlet air humidity ratio "
3756 : "equation is out of range error continues...",
3757 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3758 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
3759 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_ProcInHumRatError.index,
3760 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.last,
3761 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.last);
3762 : }
3763 : }
3764 : // Process and regeneration face velocity for humidity ratio eqn
3765 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.print) {
3766 0 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.count;
3767 0 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.count < 2) {
3768 0 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer1);
3769 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer2);
3770 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer3);
3771 0 : ShowContinueError(state,
3772 : "...Using process and regeneration face velocities that are outside the regeneration outlet air humidity ratio "
3773 : "equation model boundaries may adversely affect desiccant model performance.");
3774 : } else {
3775 0 : ShowRecurringWarningErrorAtEnd(state,
3776 0 : format("{} \"{}\" - Process and regen face velocity used in regen outlet air humidity ratio "
3777 : "equation is out of range error continues...",
3778 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3779 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
3780 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.index,
3781 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.last,
3782 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.last);
3783 : }
3784 : }
3785 : } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
3786 :
3787 : // save last system time step and last end time of current time step (used to determine if warning is valid)
3788 103147 : TimeStepSysLast = TimeStepSys;
3789 103147 : CurrentEndTimeLast = CurrentEndTime;
3790 :
3791 : // If regen and procees inlet temperatures are the same the coil is off, do not print out of bounds warning for this case
3792 103147 : if (std::abs(H_RegenInTemp - H_ProcInTemp) < SMALL) {
3793 805 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.print = false;
3794 805 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.print = false;
3795 805 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print = false;
3796 805 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print = false;
3797 805 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.print = false;
3798 805 : return;
3799 : }
3800 :
3801 : // check boundaries of independent variables and post warnings to individual buffers to print at end of time step
3802 : // checking model bounds for variables of regeneration outlet humidity ratio equation
3803 : // Regen inlet temp
3804 204161 : if (H_RegenInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInTemp ||
3805 101819 : H_RegenInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInTemp) {
3806 523 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.last = H_RegenInTemp;
3807 523 : OutputChar = format("{:.2R}", H_RegenInTemp);
3808 523 : OutputCharLo = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInTemp);
3809 523 : OutputCharHi = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInTemp);
3810 523 : if (H_RegenInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInTemp) {
3811 523 : H_RegenInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInTemp;
3812 : }
3813 523 : if (H_RegenInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInTemp) {
3814 0 : H_RegenInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInTemp;
3815 : }
3816 523 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
3817 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.print = true;
3818 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer1 =
3819 136 : format("{} \"{}\" - Regeneration inlet air temperature used in regen outlet air humidity ratio equation is outside model "
3820 : "boundaries at {}.",
3821 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3822 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
3823 68 : OutputChar);
3824 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer2 =
3825 136 : format("...Valid range = {} to {}. Occurrence info = {}, {} , {}",
3826 : OutputCharLo,
3827 : OutputCharHi,
3828 34 : state.dataEnvrn->EnvironmentName,
3829 34 : state.dataEnvrn->CurMnDy,
3830 136 : CreateSysTimeIntervalString(state));
3831 34 : CharValue = format("{:.2R}", H_RegenInTemp);
3832 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.buffer3 = format(
3833 68 : "...Regeneration outlet air humidity ratio equation: regeneration inlet air temperature passed to the model = {}", CharValue);
3834 : } else {
3835 489 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.print = false;
3836 : }
3837 : } else {
3838 101819 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInTempError.print = false;
3839 : }
3840 : // regen inlet humidity ratio
3841 204684 : if (H_RegenInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInHumRat ||
3842 102342 : H_RegenInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInHumRat) {
3843 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.last = H_RegenInHumRat;
3844 0 : OutputChar = format("{:.6R}", H_RegenInHumRat);
3845 0 : OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInHumRat);
3846 0 : OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInHumRat);
3847 0 : if (H_RegenInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInHumRat) {
3848 0 : H_RegenInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInHumRat;
3849 : }
3850 0 : if (H_RegenInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInHumRat) {
3851 0 : H_RegenInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInHumRat;
3852 : }
3853 0 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
3854 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.print = true;
3855 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer1 =
3856 0 : format("{} \"{}\" - Regeneration inlet air humidity ratio used in regen outlet air humidity ratio equation is outside model "
3857 : "boundaries at {}.",
3858 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3859 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
3860 0 : OutputChar);
3861 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer2 =
3862 0 : format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
3863 : OutputCharLo,
3864 : OutputCharHi,
3865 0 : state.dataEnvrn->EnvironmentName,
3866 0 : state.dataEnvrn->CurMnDy,
3867 0 : CreateSysTimeIntervalString(state));
3868 0 : CharValue = format("{:.6R}", H_RegenInHumRat);
3869 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.buffer3 = format(
3870 0 : "...Regeneration outlet air humidity ratio equation: regeneration inlet air humidity ratio passed to the model = {}", CharValue);
3871 : } else {
3872 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.print = false;
3873 : }
3874 : } else {
3875 102342 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_RegenInHumRatError.print = false;
3876 : }
3877 : // process inlet temp
3878 204684 : if (H_ProcInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInTemp ||
3879 102342 : H_ProcInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInTemp) {
3880 3084 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.last = H_ProcInTemp;
3881 3084 : OutputChar = format("{:.2R}", H_ProcInTemp);
3882 3084 : OutputCharLo = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInTemp);
3883 3084 : OutputCharHi = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInTemp);
3884 3084 : if (H_ProcInTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInTemp) {
3885 0 : H_ProcInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInTemp;
3886 : }
3887 3084 : if (H_ProcInTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInTemp) {
3888 3084 : H_ProcInTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInTemp;
3889 : }
3890 3084 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
3891 115 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print = true;
3892 : // Suppress warning message when process inlet temperature = 0 (DX coil is off)
3893 115 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.last == 0.0)
3894 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print = false;
3895 460 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer1 = format(
3896 : "{} \"{}\" - Process inlet air temperature used in regen outlet air humidity ratio equation is outside model boundaries at {}.",
3897 115 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3898 115 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
3899 230 : OutputChar);
3900 230 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer2 =
3901 460 : format("...Valid range = {} to {}. Occurrence info = {}, {} {}",
3902 : OutputCharLo,
3903 : OutputCharHi,
3904 115 : state.dataEnvrn->EnvironmentName,
3905 115 : state.dataEnvrn->CurMnDy,
3906 460 : CreateSysTimeIntervalString(state));
3907 115 : CharValue = format("{:.6R}", H_ProcInTemp);
3908 230 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.buffer3 =
3909 345 : format("...Regeneration outlet air humidity ratio equation: process inlet air temperature passed to the model = {}", CharValue);
3910 : } else {
3911 2969 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print = false;
3912 : }
3913 : } else {
3914 99258 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInTempError.print = false;
3915 : }
3916 : // process inlet humidity ratio
3917 204668 : if (H_ProcInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInHumRat ||
3918 102326 : H_ProcInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInHumRat) {
3919 26 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.last = H_ProcInHumRat;
3920 26 : OutputChar = format("{:.6R}", H_ProcInHumRat);
3921 26 : OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInHumRat);
3922 26 : OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInHumRat);
3923 26 : if (H_ProcInHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInHumRat) {
3924 16 : H_ProcInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInHumRat;
3925 : }
3926 26 : if (H_ProcInHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInHumRat) {
3927 10 : H_ProcInHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInHumRat;
3928 : }
3929 26 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
3930 1 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print = true;
3931 : // Suppress warning message when process inlet humrat = 0 (DX coil is off)
3932 1 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.last == 0.0)
3933 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print = false;
3934 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer1 =
3935 4 : format("{} \"{}\" - Process inlet air humidity ratio used in regen outlet air humidity ratio equation is outside model "
3936 : "boundaries at {}.",
3937 1 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3938 1 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
3939 2 : OutputChar);
3940 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer2 =
3941 4 : format("...Valid range = {} to {}. Occurrence info = {}, {}, {}",
3942 : OutputCharLo,
3943 : OutputCharHi,
3944 1 : state.dataEnvrn->EnvironmentName,
3945 1 : state.dataEnvrn->CurMnDy,
3946 4 : CreateSysTimeIntervalString(state));
3947 1 : CharValue = format("{:.6R}", H_ProcInHumRat);
3948 2 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.buffer3 = format(
3949 2 : "...Regeneration outlet air humidity ratio equation: process inlet air humidity ratio passed to the model = {}", CharValue);
3950 : } else {
3951 25 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print = false;
3952 : }
3953 : } else {
3954 102316 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_ProcInHumRatError.print = false;
3955 : }
3956 : // regeneration and process face velocity
3957 204684 : if (H_FaceVel < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinFaceVel ||
3958 102342 : H_FaceVel > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxFaceVel) {
3959 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.last = H_FaceVel;
3960 0 : OutputChar = format("{:.6R}", H_FaceVel);
3961 0 : OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinFaceVel);
3962 0 : OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxFaceVel);
3963 0 : if (H_FaceVel < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinFaceVel) {
3964 0 : H_FaceVel = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinFaceVel;
3965 : }
3966 0 : if (H_FaceVel > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxFaceVel) {
3967 0 : H_FaceVel = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxFaceVel;
3968 : }
3969 0 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
3970 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.print = true;
3971 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer1 =
3972 0 : format("{} \"{}\" - Process and regen inlet air face velocity used in regen outlet air humidity ratio equation is outside model "
3973 : "boundaries at {}.",
3974 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
3975 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
3976 0 : OutputChar);
3977 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer2 =
3978 0 : format("...Valid range = {} to {}. Occurrence info = {}, {}, {}",
3979 : OutputCharLo,
3980 : OutputCharHi,
3981 0 : state.dataEnvrn->EnvironmentName,
3982 0 : state.dataEnvrn->CurMnDy,
3983 0 : CreateSysTimeIntervalString(state));
3984 0 : CharValue = format("{:.6R}", H_FaceVel);
3985 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.buffer3 = format(
3986 0 : "...Regeneration outlet air humidity ratio equation: process and regeneration face velocity passed to the model = {}", CharValue);
3987 : } else {
3988 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.print = false;
3989 : }
3990 : } else {
3991 102342 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_FaceVelError.print = false;
3992 : }
3993 : }
3994 :
3995 103147 : void HeatExchCond::CheckModelBoundOutput_Temp(EnergyPlusData &state,
3996 : Real64 const RegenInTemp, // current regen inlet temp passed to eqn
3997 : Real64 &RegenOutTemp, // current regen outlet temp from eqn
3998 : bool const FirstHVACIteration // First HVAC iteration flag
3999 : ) const
4000 : {
4001 :
4002 : // SUBROUTINE INFORMATION:
4003 : // AUTHOR Mangesh Basarkar, FSEC
4004 : // DATE WRITTEN January 2007
4005 : // MODIFIED June 2007, R. Raustad, changed requirement that regen outlet temp be less than inlet temp
4006 : // RE-ENGINEERED na
4007 :
4008 : // PURPOSE OF THIS SUBROUTINE:
4009 : // To verify that the empirical model's independent variables are within the limits used during the
4010 : // developement of the empirical model.
4011 :
4012 : // METHODOLOGY EMPLOYED:
4013 : // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
4014 : // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
4015 : // The range of each independent variable is provided by the user and are based on the limits of the
4016 : // empirical model. These limits are tested in this subroutine each time step and returned for use by the calling
4017 : // routine.
4018 :
4019 : // Using/Aliasing
4020 103147 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
4021 103147 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
4022 : using General::CreateSysTimeIntervalString;
4023 :
4024 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4025 103147 : auto &OutputChar = state.dataHeatRecovery->error3.OutputChar;
4026 103147 : auto &OutputCharLo = state.dataHeatRecovery->error3.OutputCharLo;
4027 103147 : auto &OutputCharHi = state.dataHeatRecovery->error3.OutputCharHi;
4028 103147 : auto &CharValue = state.dataHeatRecovery->error3.CharValue;
4029 103147 : auto &TimeStepSysLast = state.dataHeatRecovery->error3.TimeStepSysLast;
4030 103147 : auto &CurrentEndTime = state.dataHeatRecovery->error3.CurrentEndTime;
4031 103147 : auto &CurrentEndTimeLast = state.dataHeatRecovery->error3.CurrentEndTimeLast;
4032 : // current end time is compared with last to see if time step changed
4033 :
4034 : // calculate end time of current time step
4035 103147 : CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
4036 :
4037 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
4038 : // Wait for next time step to print warnings. If simulation iterates, print out
4039 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
4040 : // If a warning occurs and the simulation down shifts, the warning is not valid.
4041 103147 : if (CurrentEndTime > CurrentEndTimeLast && TimeStepSys >= TimeStepSysLast) {
4042 :
4043 : // print error when regeneration outlet temperature is greater than regen inlet temperature
4044 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.print) {
4045 30 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.count;
4046 30 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.count < 2) {
4047 1 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.buffer1);
4048 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.buffer2);
4049 1 : ShowContinueError(state,
4050 : "...Regeneration outlet air temperature should always be less than or equal to regen inlet air temperature. "
4051 : "Verify correct model coefficients.");
4052 : } else {
4053 174 : ShowRecurringWarningErrorAtEnd(
4054 : state,
4055 116 : format("{} \"{}\" - Regeneration outlet air temperature above regen inlet air temperature error continues...",
4056 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4057 58 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
4058 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.index,
4059 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.last,
4060 29 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.last);
4061 : }
4062 : }
4063 :
4064 : // print error for variables of regeneration outlet temperature
4065 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print) {
4066 0 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.count;
4067 0 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.count < 2) {
4068 0 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer1);
4069 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer2);
4070 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer3);
4071 0 : ShowContinueError(state,
4072 : "...Regeneration outlet air temperature should always be less than or equal to regen inlet air temperature. "
4073 : "Verify correct model coefficients.");
4074 : } else {
4075 0 : ShowRecurringWarningErrorAtEnd(
4076 : state,
4077 0 : format("{} \"{}\" - Regeneration outlet air temperature should be less than regen inlet air temperature error continues...",
4078 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4079 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
4080 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.index,
4081 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.last,
4082 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.last);
4083 : }
4084 : }
4085 : } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
4086 :
4087 : // save last system time step and last end time of current time step (used to determine if warning is valid)
4088 103147 : TimeStepSysLast = TimeStepSys;
4089 103147 : CurrentEndTimeLast = CurrentEndTime;
4090 :
4091 : // checking model regeneration outlet temperature to always be less than or equal to regeneration inlet temperature
4092 103147 : if (RegenOutTemp > RegenInTemp) {
4093 523 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.last = RegenOutTemp;
4094 523 : OutputChar = format("{:.2R}", RegenOutTemp);
4095 523 : OutputCharHi = format("{:.2R}", RegenInTemp);
4096 : // IF(RegenOutTemp .GT. RegenInTemp)THEN
4097 : // RegenOutTemp = RegenInTemp
4098 : // END IF
4099 523 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
4100 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.print = true;
4101 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.buffer1 =
4102 136 : format("{} \"{}\" - Regeneration outlet air temperature is greater than inlet temperature at {}.",
4103 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4104 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
4105 68 : OutputChar);
4106 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.buffer2 =
4107 136 : format("...Regen inlet air temperature = {}. Occurrence info = {}, {}, {}",
4108 : OutputCharHi,
4109 34 : state.dataEnvrn->EnvironmentName,
4110 34 : state.dataEnvrn->CurMnDy,
4111 136 : CreateSysTimeIntervalString(state));
4112 34 : CharValue = format("{:.6R}", RegenOutTemp);
4113 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempFailedError.buffer3 =
4114 102 : format("...Regen outlet air temperature equation: regeneration outlet air temperature allowed from the model = {}", CharValue);
4115 : } else {
4116 489 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print = false;
4117 : }
4118 : } else {
4119 102624 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print = false;
4120 : }
4121 :
4122 : // check boundaries of regen outlet temperature and post warnings to individual buffers to print at end of time step
4123 : // checking model bounds for regeneration outlet temperature
4124 206294 : if (RegenOutTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutTemp ||
4125 103147 : RegenOutTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutTemp) {
4126 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.last = RegenOutTemp;
4127 0 : OutputChar = format("{:.2R}", RegenOutTemp);
4128 0 : OutputCharLo = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutTemp);
4129 0 : OutputCharHi = format("{:.2R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutTemp);
4130 0 : if (RegenOutTemp < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutTemp) {
4131 0 : RegenOutTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutTemp;
4132 : }
4133 0 : if (RegenOutTemp > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutTemp) {
4134 0 : RegenOutTemp = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutTemp;
4135 : }
4136 0 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
4137 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print = true;
4138 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer1 =
4139 0 : format("{} \"{}\" - Regeneration outlet air temperature equation is outside model boundaries at {}.",
4140 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4141 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
4142 0 : OutputChar);
4143 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer2 =
4144 0 : format("...Valid range = {} to {}. Occurrence info = {}, {}, {}",
4145 : OutputCharLo,
4146 : OutputCharHi,
4147 0 : state.dataEnvrn->EnvironmentName,
4148 0 : state.dataEnvrn->CurMnDy,
4149 0 : CreateSysTimeIntervalString(state));
4150 0 : CharValue = format("{:.6R}", RegenOutTemp);
4151 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.buffer3 =
4152 0 : format("...Regen outlet air temperature equation: regeneration outlet air temperature allowed from the model = {}", CharValue);
4153 : } else {
4154 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print = false;
4155 : }
4156 : } else {
4157 103147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutTempError.print = false;
4158 : }
4159 103147 : }
4160 :
4161 103147 : void HeatExchCond::CheckModelBoundOutput_HumRat(EnergyPlusData &state,
4162 : Real64 const RegenInHumRat, // current regen inlet hum rat passed to eqn
4163 : Real64 &RegenOutHumRat, // current regen outlet hum rat from eqn
4164 : bool const FirstHVACIteration // First HVAC iteration flag
4165 : ) const
4166 : {
4167 :
4168 : // SUBROUTINE INFORMATION:
4169 : // AUTHOR Mangesh Basarkar, FSEC
4170 : // DATE WRITTEN January 2007
4171 : // MODIFIED June 2007, R. Raustad, changed requirement that regen outlet temp be less than inlet temp
4172 : // RE-ENGINEERED na
4173 :
4174 : // PURPOSE OF THIS SUBROUTINE:
4175 : // To verify that the empirical model's independent variables are within the limits used during the
4176 : // developement of the empirical model.
4177 :
4178 : // METHODOLOGY EMPLOYED:
4179 : // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
4180 : // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
4181 : // The range of each independent variable is provided by the user and are based on the limits of the
4182 : // empirical model. These limits are tested in this subroutine each time step and returned for use by the calling
4183 : // routine.
4184 : // REFERENCES:
4185 : // na
4186 :
4187 : // Using/Aliasing
4188 103147 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
4189 103147 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
4190 : using General::CreateSysTimeIntervalString;
4191 :
4192 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4193 103147 : auto &OutputChar = state.dataHeatRecovery->error4.OutputChar;
4194 103147 : auto &OutputCharLo = state.dataHeatRecovery->error4.OutputCharLo;
4195 103147 : auto &OutputCharHi = state.dataHeatRecovery->error4.OutputCharHi;
4196 103147 : auto &CharValue = state.dataHeatRecovery->error4.CharValue;
4197 103147 : auto &TimeStepSysLast = state.dataHeatRecovery->error4.TimeStepSysLast;
4198 103147 : auto &CurrentEndTime = state.dataHeatRecovery->error4.CurrentEndTime;
4199 103147 : auto &CurrentEndTimeLast = state.dataHeatRecovery->error4.CurrentEndTimeLast;
4200 : // current end time is compared with last to see if time step changed
4201 :
4202 : // calculate end time of current time step
4203 103147 : CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
4204 :
4205 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
4206 : // Wait for next time step to print warnings. If simulation iterates, print out
4207 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
4208 : // If a warning occurs and the simulation down shifts, the warning is not valid.
4209 103147 : if (CurrentEndTime > CurrentEndTimeLast && TimeStepSys >= TimeStepSysLast) {
4210 :
4211 : // print error when regeneration outlet humidity ratio is less than regeneration inlet humidity ratio
4212 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.print) {
4213 0 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.count;
4214 0 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.count < 2) {
4215 0 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.buffer1);
4216 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.buffer2);
4217 0 : ShowContinueError(state,
4218 : "...Regeneration outlet air humidity ratio should always be greater than or equal to regen inlet air humidity "
4219 : "ratio. Verify correct model coefficients.");
4220 : } else {
4221 0 : ShowRecurringWarningErrorAtEnd(state,
4222 0 : format("{} \"{}\" - Regeneration outlet air humidity ratio should be greater than regen inlet air "
4223 : "humidity ratio error continues...",
4224 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4225 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
4226 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.index,
4227 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.last,
4228 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.last);
4229 : }
4230 : }
4231 :
4232 : // print error for regeneration outlet humidity ratio
4233 6693 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.print) {
4234 0 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.count;
4235 0 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.count < 2) {
4236 0 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer1);
4237 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer2);
4238 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer3);
4239 0 : ShowContinueError(
4240 : state,
4241 : "...Regeneration outlet air humidity ratio outside model boundaries may adversely affect desiccant model performance.");
4242 : } else {
4243 0 : ShowRecurringWarningErrorAtEnd(state,
4244 0 : format("{} \"{}\" - Regeneration outlet air humidity ratio is out of range error continues...",
4245 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4246 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
4247 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.index,
4248 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.last,
4249 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.last);
4250 : }
4251 : }
4252 : } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
4253 :
4254 : // save last system time step and last end time of current time step (used to determine if warning is valid)
4255 103147 : TimeStepSysLast = TimeStepSys;
4256 103147 : CurrentEndTimeLast = CurrentEndTime;
4257 :
4258 : // checking for regeneration outlet humidity ratio less than or equal to regeneration inlet humidity ratio
4259 103147 : if (RegenOutHumRat < RegenInHumRat) {
4260 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.last = RegenOutHumRat;
4261 0 : OutputChar = format("{:.6R}", RegenOutHumRat);
4262 0 : OutputCharHi = format("{:.6R}", RegenInHumRat);
4263 : // IF(RegenOutHumRat .LT. RegenInHumRat)THEN
4264 : // RegenOutHumRat = RegenInHumRat
4265 : // END IF
4266 0 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
4267 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.print = true;
4268 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.buffer1 =
4269 0 : format("{} \"{}\" - Regeneration outlet air humidity ratio is less than the inlet air humidity ratio at {}.",
4270 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4271 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
4272 0 : OutputChar);
4273 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.buffer2 =
4274 0 : format("...Regen inlet air humidity ratio = {}. Occurrence info = {}, {}, {}",
4275 : OutputCharHi,
4276 0 : state.dataEnvrn->EnvironmentName,
4277 0 : state.dataEnvrn->CurMnDy,
4278 0 : CreateSysTimeIntervalString(state));
4279 0 : CharValue = format("{:.6R}", RegenOutHumRat);
4280 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.buffer3 = format(
4281 0 : "...Regen outlet air humidity ratio equation: regeneration outlet air humidity ratio allowed from the model = {}", CharValue);
4282 : } else {
4283 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.print = false;
4284 : }
4285 : } else {
4286 103147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatFailedErr.print = false;
4287 : }
4288 :
4289 : // check boundaries of regen outlet humrat and post warnings to individual buffers to print at end of time step
4290 : // checking model bounds for regeneration outlet humidity ratio
4291 206294 : if (RegenOutHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutHumRat ||
4292 103147 : RegenOutHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutHumRat) {
4293 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.last = RegenOutHumRat;
4294 0 : OutputChar = format("{:.6R}", RegenOutHumRat);
4295 0 : OutputCharLo = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutHumRat);
4296 0 : OutputCharHi = format("{:.6R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutHumRat);
4297 0 : if (RegenOutHumRat < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutHumRat) {
4298 0 : RegenOutHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MinRegenAirOutHumRat;
4299 : }
4300 0 : if (RegenOutHumRat > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutHumRat) {
4301 0 : RegenOutHumRat = state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).MaxRegenAirOutHumRat;
4302 : }
4303 0 : if (!state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
4304 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.print = true;
4305 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer1 =
4306 0 : format("{} \"{}\" - Regeneration outlet air humidity ratio is outside model boundaries at {}.",
4307 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4308 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
4309 0 : OutputChar);
4310 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer2 =
4311 0 : format("...Valid range = {} to {}. Occurrence info = {}, {}, {}",
4312 : OutputCharLo,
4313 : OutputCharHi,
4314 0 : state.dataEnvrn->EnvironmentName,
4315 0 : state.dataEnvrn->CurMnDy,
4316 0 : CreateSysTimeIntervalString(state));
4317 0 : CharValue = format("{:.6R}", RegenOutHumRat);
4318 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.buffer3 = format(
4319 0 : "...Regen outlet air humidity ratio equation: regeneration outlet air humidity ratio allowed from the model = {}", CharValue);
4320 : } else {
4321 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.print = false;
4322 : }
4323 : } else {
4324 103147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenOutHumRatError.print = false;
4325 : }
4326 103147 : }
4327 :
4328 103147 : void HeatExchCond::CheckModelBoundsRH_TempEq(EnergyPlusData &state,
4329 : Real64 const T_RegenInTemp, // current regen inlet temperature passed to eqn
4330 : Real64 const T_RegenInHumRat, // current regen inlet hum rat passed to eqn
4331 : Real64 const T_ProcInTemp, // current process inlet temperature passed to eqn
4332 : Real64 const T_ProcInHumRat, // current regen outlet hum rat from eqn
4333 : bool const FirstHVACIteration // first HVAC iteration flag
4334 : ) const
4335 : {
4336 :
4337 : // SUBROUTINE INFORMATION:
4338 : // AUTHOR Richard Raustad, FSEC
4339 : // DATE WRITTEN January 2007
4340 : // MODIFIED na
4341 : // RE-ENGINEERED na
4342 :
4343 : // PURPOSE OF THIS SUBROUTINE:
4344 : // To verify that the empirical model's independent variables result in a relative humidity that is within the range
4345 : // of relative humidities used when creating the empirical model. Both the regeneration and process inlet are tested.
4346 :
4347 : // METHODOLOGY EMPLOYED:
4348 : // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
4349 : // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
4350 : // In addition, the range of relative humidities in the original data set may influence the output of the
4351 : // empirical model. This subroutine tests the relative humidities passed to the empirical model and warns the
4352 : // user if these relative humidities are out of bounds based on the limits set by the user.
4353 : // REFERENCES:
4354 : // na
4355 :
4356 : // Using/Aliasing
4357 103147 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
4358 103147 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
4359 : using General::CreateSysTimeIntervalString;
4360 :
4361 : using Psychrometrics::PsyRhFnTdbWPb;
4362 :
4363 103147 : auto &RegenInletRH = state.dataHeatRecovery->RegenInletRH2;
4364 103147 : auto &ProcInletRH = state.dataHeatRecovery->ProcInletRH2;
4365 103147 : auto &OutputChar = state.dataHeatRecovery->error6.OutputChar;
4366 103147 : auto &OutputCharLo = state.dataHeatRecovery->error6.OutputCharLo;
4367 103147 : auto &OutputCharHi = state.dataHeatRecovery->error6.OutputCharHi;
4368 103147 : auto &TimeStepSysLast = state.dataHeatRecovery->error6.TimeStepSysLast;
4369 103147 : auto &CurrentEndTime = state.dataHeatRecovery->error6.CurrentEndTime;
4370 103147 : auto &CurrentEndTimeLast = state.dataHeatRecovery->error6.CurrentEndTimeLast;
4371 : // current end time is compared with last to see if time step changed
4372 :
4373 103147 : if (state.dataGlobal->WarmupFlag || FirstHVACIteration) return;
4374 :
4375 : // calculate end time of current time step
4376 4363 : CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
4377 :
4378 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
4379 : // Wait for next time step to print warnings. If simulation iterates, print out
4380 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
4381 : // If a warning occurs and the simulation down shifts, the warning is not valid.
4382 4363 : if (CurrentEndTime > CurrentEndTimeLast && TimeStepSys >= TimeStepSysLast) {
4383 :
4384 : // print error when regeneration inlet relative humidity is outside model boundaries
4385 318 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.print) {
4386 29 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.count;
4387 29 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.count < 2) {
4388 1 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer1);
4389 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer2);
4390 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer3);
4391 1 : ShowContinueError(state,
4392 : "...Using regeneration inlet air relative humidities that are outside the regeneration outlet temperature "
4393 : "equation model boundaries may adversely affect desiccant model performance. Verify correct model "
4394 : "coefficients.");
4395 : } else {
4396 168 : ShowRecurringWarningErrorAtEnd(state,
4397 112 : format("{} \"{}\" - Regeneration inlet air relative humidity related to regen outlet air "
4398 : "temperature equation is outside model boundaries error continues...",
4399 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4400 56 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
4401 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.index,
4402 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.last,
4403 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.last);
4404 : }
4405 : }
4406 :
4407 : // print error when process inlet relative humidity is outside model boundaries
4408 318 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.print) {
4409 29 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.count;
4410 29 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.count < 2) {
4411 1 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer1);
4412 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer2);
4413 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer3);
4414 1 : ShowContinueError(state,
4415 : "...Using process inlet air relative humidities that are outside the regeneration outlet temperature equation "
4416 : "model boundaries may adversely affect desiccant model performance. Verify correct model coefficients.");
4417 : } else {
4418 168 : ShowRecurringWarningErrorAtEnd(state,
4419 112 : format("{} \"{}\" - Process inlet air relative humidity related to regen outlet air temperature "
4420 : "equation is outside model boundaries error continues...",
4421 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4422 56 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
4423 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.index,
4424 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.last,
4425 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.last);
4426 : }
4427 : }
4428 :
4429 : } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
4430 :
4431 : // save last system time step and last end time of current time step (used to determine if warning is valid)
4432 4363 : TimeStepSysLast = TimeStepSys;
4433 4363 : CurrentEndTimeLast = CurrentEndTime;
4434 :
4435 : // Check that condition is not above saturation curve prior to next calc (PsyRhFnTdbWPb) to avoid psyc routine errors
4436 : // *
4437 : // *
4438 : // x------*---------- T_HumRat
4439 : // | *
4440 : // | *
4441 : // *----------------- PsyWFnTdpPb(Tdp,Pb)
4442 : // * |
4443 : // |
4444 : // T_Temp
4445 13089 : if (T_RegenInHumRat > Psychrometrics::PsyWFnTdpPb(state, T_RegenInTemp, state.dataEnvrn->OutBaroPress) ||
4446 8726 : T_ProcInHumRat > Psychrometrics::PsyWFnTdpPb(state, T_ProcInTemp, state.dataEnvrn->OutBaroPress)) {
4447 : // reset RH print flags just in case
4448 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.print = false;
4449 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.print = false;
4450 0 : return;
4451 : }
4452 :
4453 : // If regen and procees inlet temperatures are the same the coil is off, do not print out of bounds warning for this case
4454 4363 : if (std::abs(T_RegenInTemp - T_ProcInTemp) < SMALL) {
4455 25 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.print = false;
4456 25 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.print = false;
4457 25 : return;
4458 : }
4459 :
4460 4338 : RegenInletRH = PsyRhFnTdbWPb(state, T_RegenInTemp, T_RegenInHumRat, state.dataEnvrn->OutBaroPress);
4461 4338 : ProcInletRH = min(1.0, PsyRhFnTdbWPb(state, T_ProcInTemp, T_ProcInHumRat, state.dataEnvrn->OutBaroPress));
4462 :
4463 : // checking if regeneration inlet relative humidity is within model boundaries
4464 8676 : if (RegenInletRH < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInRelHum ||
4465 4338 : RegenInletRH > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInRelHum) {
4466 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.last = RegenInletRH * 100.0;
4467 34 : OutputChar = format("{:.1R}", RegenInletRH * 100.0);
4468 34 : OutputCharLo = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinRegenAirInRelHum * 100.0);
4469 34 : OutputCharHi = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxRegenAirInRelHum * 100.0);
4470 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.print = true;
4471 :
4472 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer1 =
4473 136 : format("{} \"{}\" - Regeneration inlet air relative humidity related to regen outlet air temperature equation is outside model "
4474 : "boundaries at {}.",
4475 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4476 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
4477 68 : OutputChar);
4478 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer2 =
4479 102 : format("...Model limit on regeneration inlet air relative humidity is {} to {}.", OutputCharLo, OutputCharHi);
4480 136 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.buffer3 = format(
4481 170 : "...Occurrence info = {}, {}, {}", state.dataEnvrn->EnvironmentName, state.dataEnvrn->CurMnDy, CreateSysTimeIntervalString(state));
4482 : } else {
4483 4304 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumTempErr.print = false;
4484 : }
4485 :
4486 : // checking if process inlet relative humidity is within model boundaries
4487 8529 : if (ProcInletRH < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInRelHum ||
4488 4191 : ProcInletRH > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInRelHum) {
4489 147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.last = ProcInletRH * 100.0;
4490 147 : OutputChar = format("{:.1R}", ProcInletRH * 100.0);
4491 147 : OutputCharLo = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MinProcAirInRelHum * 100.0);
4492 147 : OutputCharHi = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).T_MaxProcAirInRelHum * 100.0);
4493 147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.print = true;
4494 :
4495 588 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer1 = format(
4496 : "{} \"{}\" - Process inlet air relative humidity related to regen outlet air temperature equation is outside model boundaries at {}.",
4497 147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4498 147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
4499 294 : OutputChar);
4500 294 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer2 =
4501 441 : format("...Model limit on process inlet air relative humidity is {} to {}.", OutputCharLo, OutputCharHi);
4502 588 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.buffer3 = format(
4503 735 : "...Occurrence info = {}, {}, {}", state.dataEnvrn->EnvironmentName, state.dataEnvrn->CurMnDy, CreateSysTimeIntervalString(state));
4504 : } else {
4505 4191 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumTempErr.print = false;
4506 : }
4507 : }
4508 :
4509 103147 : void HeatExchCond::CheckModelBoundsRH_HumRatEq(EnergyPlusData &state,
4510 : Real64 const H_RegenInTemp, // current regen inlet temperature passed to eqn
4511 : Real64 const H_RegenInHumRat, // current regen inlet hum rat passed to eqn
4512 : Real64 const H_ProcInTemp, // current process inlet temperature passed to eqn
4513 : Real64 const H_ProcInHumRat, // current process inlet hum rat passed to eqn
4514 : bool const FirstHVACIteration // first HVAC iteration flag
4515 : ) const
4516 : {
4517 :
4518 : // SUBROUTINE INFORMATION:
4519 : // AUTHOR Richard Raustad, FSEC
4520 : // DATE WRITTEN January 2007
4521 : // MODIFIED na
4522 : // RE-ENGINEERED na
4523 :
4524 : // PURPOSE OF THIS SUBROUTINE:
4525 : // To verify that the empirical model's independent variables result in a relative humidity that is within the range
4526 : // of relative humidities used when creating the empirical model. Both the regeneration and process inlet are tested.
4527 :
4528 : // METHODOLOGY EMPLOYED:
4529 : // The empirical models used for simulating a desiccant enhanced cooling coil are based on a limited data set.
4530 : // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
4531 : // In addition, the range of relative humidities in the original data set may influence the output of the
4532 : // empirical model. This subroutine tests the relative humidities passed to the empirical model and warns the
4533 : // user if these relative humidities are out of bounds based on the limits set by the user.
4534 :
4535 : // Using/Aliasing
4536 103147 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
4537 103147 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
4538 : using General::CreateSysTimeIntervalString;
4539 :
4540 : using Psychrometrics::PsyRhFnTdbWPb;
4541 :
4542 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4543 103147 : auto &RegenInletRH = state.dataHeatRecovery->RegenInletRH;
4544 103147 : auto &ProcInletRH = state.dataHeatRecovery->ProcInletRH;
4545 103147 : auto &OutputChar = state.dataHeatRecovery->error5.OutputChar;
4546 103147 : auto &OutputCharLo = state.dataHeatRecovery->error5.OutputCharLo;
4547 103147 : auto &OutputCharHi = state.dataHeatRecovery->error5.OutputCharHi;
4548 103147 : auto &TimeStepSysLast = state.dataHeatRecovery->error5.TimeStepSysLast;
4549 103147 : auto &CurrentEndTime = state.dataHeatRecovery->error5.CurrentEndTime;
4550 103147 : auto &CurrentEndTimeLast = state.dataHeatRecovery->error5.CurrentEndTimeLast;
4551 : // current end time is compared with last to see if time step changed
4552 :
4553 103147 : if (state.dataGlobal->WarmupFlag || FirstHVACIteration) return;
4554 :
4555 : // calculate end time of current time step
4556 4363 : CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
4557 :
4558 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
4559 : // Wait for next time step to print warnings. If simulation iterates, print out
4560 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
4561 : // If a warning occurs and the simulation down shifts, the warning is not valid.
4562 4363 : if (CurrentEndTime > CurrentEndTimeLast && TimeStepSys >= TimeStepSysLast) {
4563 :
4564 : // print error when regeneration inlet relative humidity is outside model boundaries
4565 318 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.print) {
4566 29 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.count;
4567 29 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.count < 2) {
4568 1 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer1);
4569 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer2);
4570 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer3);
4571 1 : ShowContinueError(state,
4572 : "...Using regeneration inlet air relative humidities that are outside the regeneration outlet humidity ratio "
4573 : "equation model boundaries may adversely affect desiccant model performance. Verify correct model "
4574 : "coefficients.");
4575 : } else {
4576 168 : ShowRecurringWarningErrorAtEnd(state,
4577 112 : format("{} \"{}\" - Regeneration inlet air relative humidity related to regen outlet air humidity "
4578 : "ratio equation is outside model boundaries error continues...",
4579 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4580 56 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
4581 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.index,
4582 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.last,
4583 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.last);
4584 : }
4585 : }
4586 :
4587 : // print error when process inlet relative humidity is outside model boundaries
4588 318 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.print) {
4589 29 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.count;
4590 29 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.count < 2) {
4591 1 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer1);
4592 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer2);
4593 1 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer3);
4594 1 : ShowContinueError(state,
4595 : "...Using process inlet air relative humidities that are outside the regeneration outlet humidity ratio "
4596 : "equation model boundaries may adversely affect desiccant model performance. Verify correct model "
4597 : "coefficients.");
4598 : } else {
4599 168 : ShowRecurringWarningErrorAtEnd(state,
4600 112 : format("{} \"{}\" - Process inlet air relative humidity related to regen outlet air humidity "
4601 : "ratio equation is outside model boundaries error continues...",
4602 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4603 56 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name),
4604 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.index,
4605 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.last,
4606 28 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.last);
4607 : }
4608 : }
4609 :
4610 : } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
4611 :
4612 : // save last system time step and last end time of current time step (used to determine if warning is valid)
4613 4363 : TimeStepSysLast = TimeStepSys;
4614 4363 : CurrentEndTimeLast = CurrentEndTime;
4615 :
4616 : // Check that condition is not above saturation curve prior to next calc (PsyRhFnTdbWPb) to avoid psyc routine errors
4617 : // *
4618 : // *
4619 : // x------*---------- H_HumRat
4620 : // | *
4621 : // | *
4622 : // *----------------- PsyWFnTdpPb(Tdp,Pb)
4623 : // * |
4624 : // |
4625 : // H_Temp
4626 13089 : if (H_RegenInHumRat > Psychrometrics::PsyWFnTdpPb(state, H_RegenInTemp, state.dataEnvrn->OutBaroPress) ||
4627 8726 : H_ProcInHumRat > Psychrometrics::PsyWFnTdpPb(state, H_ProcInTemp, state.dataEnvrn->OutBaroPress)) {
4628 : // reset RH print flags just in case
4629 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.print = false;
4630 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.print = false;
4631 0 : return;
4632 : }
4633 :
4634 : // If regen and procees inlet temperatures are the same the coil is off, do not print out of bounds warning for this case
4635 4363 : if (std::abs(H_RegenInTemp - H_ProcInTemp) < SMALL) {
4636 25 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.print = false;
4637 25 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.print = false;
4638 25 : return;
4639 : }
4640 :
4641 4338 : RegenInletRH = PsyRhFnTdbWPb(state, H_RegenInTemp, H_RegenInHumRat, state.dataEnvrn->OutBaroPress);
4642 4338 : ProcInletRH = min(1.0, PsyRhFnTdbWPb(state, H_ProcInTemp, H_ProcInHumRat, state.dataEnvrn->OutBaroPress));
4643 :
4644 : // checking if regeneration inlet relative humidity is within model boundaries
4645 8676 : if (RegenInletRH < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInRelHum ||
4646 4338 : RegenInletRH > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInRelHum) {
4647 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.last = RegenInletRH * 100.0;
4648 34 : OutputChar = format("{:.1R}", RegenInletRH * 100.0);
4649 34 : OutputCharLo = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinRegenAirInRelHum * 100.0);
4650 34 : OutputCharHi = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxRegenAirInRelHum * 100.0);
4651 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.print = true;
4652 :
4653 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer1 =
4654 136 : format("{} \"{}\" - Regeneration inlet air relative humidity related to regen outlet air humidity ratio equation is outside model "
4655 : "boundaries at {}.",
4656 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4657 34 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
4658 68 : OutputChar);
4659 68 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer2 =
4660 102 : format("...Model limit on regeneration inlet air relative humidity is {} to {}.", OutputCharLo, OutputCharHi);
4661 136 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.buffer3 = format(
4662 170 : "...Occurrence info = {}, {}, {}", state.dataEnvrn->EnvironmentName, state.dataEnvrn->CurMnDy, CreateSysTimeIntervalString(state));
4663 : } else {
4664 4304 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).regenInRelHumHumRatErr.print = false;
4665 : }
4666 :
4667 : // checking if process inlet relative humidity is within model boundaries
4668 8529 : if (ProcInletRH < state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInRelHum ||
4669 4191 : ProcInletRH > state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInRelHum) {
4670 147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.last = ProcInletRH * 100.0;
4671 147 : OutputChar = format("{:.1R}", ProcInletRH * 100.0);
4672 147 : OutputCharLo = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MinProcAirInRelHum * 100.0);
4673 147 : OutputCharHi = format("{:.1R}", state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).H_MaxProcAirInRelHum * 100.0);
4674 147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.print = true;
4675 :
4676 294 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer1 =
4677 588 : format("{} \"{}\" - Process inlet air relative humidity related to regen outlet air humidity ratio equation is outside model "
4678 : "boundaries at {}.",
4679 147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).PerfType,
4680 147 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).Name,
4681 294 : OutputChar);
4682 294 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer2 =
4683 441 : format("...Model limit on process inlet air relative humidity is {} to {}.", OutputCharLo, OutputCharHi);
4684 588 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.buffer3 = format(
4685 735 : "...Occurrence info = {}, {}, {}", state.dataEnvrn->EnvironmentName, state.dataEnvrn->CurMnDy, CreateSysTimeIntervalString(state));
4686 : } else {
4687 4191 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).procInRelHumHumRatErr.print = false;
4688 : }
4689 : }
4690 :
4691 103147 : void HeatExchCond::CheckForBalancedFlow(EnergyPlusData &state,
4692 : Real64 const ProcessInMassFlow, // current process inlet air mass flow rate (m3/s)
4693 : Real64 const RegenInMassFlow, // current regeneration inlet air mass flow rate (m3/s)
4694 : bool const FirstHVACIteration // first HVAC iteration flag
4695 : ) const
4696 : {
4697 :
4698 : // SUBROUTINE INFORMATION:
4699 : // AUTHOR Richard Raustad, FSEC
4700 : // DATE WRITTEN June 2007
4701 : // MODIFIED na
4702 : // RE-ENGINEERED na
4703 :
4704 : // PURPOSE OF THIS SUBROUTINE:
4705 : // To verify that the balanced flow desiccant heat exchanger has the same regeneration and process air flow rates.
4706 :
4707 : // METHODOLOGY EMPLOYED:
4708 : // Check that the regeneration and process air mass flow rates are within 2%.
4709 : // REFERENCES:
4710 : // na
4711 :
4712 : // Using/Aliasing
4713 103147 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
4714 103147 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
4715 : using General::CreateSysTimeIntervalString;
4716 :
4717 103147 : auto &OutputCharProc = state.dataHeatRecovery->OutputCharProc;
4718 103147 : auto &OutputCharRegen = state.dataHeatRecovery->OutputCharRegen;
4719 103147 : auto &TimeStepSysLast = state.dataHeatRecovery->TimeStepSysLast7;
4720 103147 : auto &CurrentEndTime = state.dataHeatRecovery->CurrentEndTime7;
4721 103147 : auto &CurrentEndTimeLast = state.dataHeatRecovery->CurrentEndTimeLast7;
4722 :
4723 : // current end time is compared with last to see if time step changed
4724 : Real64 ABSImbalancedFlow; // absolute value of process and regeneration air flow imbalance fraction
4725 :
4726 103147 : if (state.dataGlobal->WarmupFlag || FirstHVACIteration) return;
4727 :
4728 : // calculate end time of current time step
4729 4363 : CurrentEndTime = state.dataGlobal->CurrentTime + SysTimeElapsed;
4730 :
4731 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
4732 : // Wait for next time step to print warnings. If simulation iterates, print out
4733 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
4734 : // If a warning occurs and the simulation down shifts, the warning is not valid.
4735 4363 : if (CurrentEndTime > CurrentEndTimeLast && TimeStepSys >= TimeStepSysLast) {
4736 :
4737 : // print error when regeneration inlet relative humidity is outside model boundaries
4738 318 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.print) {
4739 0 : ++state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.count;
4740 0 : if (state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.count < 2) {
4741 0 : ShowWarningError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer1);
4742 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer2);
4743 0 : ShowContinueError(state, state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer3);
4744 : // CALL ShowContinueError(state, '...Using regeneration inlet air relative humidities that are outside the regeneration
4745 : // '&
4746 : // //'outlet humidity ratio equation model boundaries may adversely affect desiccant model performance. '&
4747 : // //'Verify correct model coefficients.')
4748 : } else {
4749 0 : ShowRecurringWarningErrorAtEnd(state,
4750 0 : format("{} \"{}\" - unbalanced air flow rate is limited to 2% error continues with the imbalanced "
4751 : "fraction statistics reported...",
4752 0 : DataHVACGlobals::cHXTypes(this->ExchType),
4753 0 : this->Name),
4754 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.index,
4755 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.last,
4756 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.last);
4757 : }
4758 : }
4759 :
4760 : } // IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
4761 :
4762 : // save last system time step and last end time of current time step (used to determine if warning is valid)
4763 4363 : TimeStepSysLast = TimeStepSys;
4764 4363 : CurrentEndTimeLast = CurrentEndTime;
4765 :
4766 : // checking if regeneration inlet relative humidity is within model boundaries
4767 4363 : ABSImbalancedFlow = std::abs(RegenInMassFlow - ProcessInMassFlow) / RegenInMassFlow;
4768 4363 : if (ABSImbalancedFlow > 0.02) {
4769 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.last = ABSImbalancedFlow;
4770 0 : OutputCharRegen = format("{:.6R}", RegenInMassFlow);
4771 0 : OutputCharProc = format("{:.6R}", ProcessInMassFlow);
4772 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.print = true;
4773 :
4774 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer1 =
4775 0 : format("{} \"{}\" - unbalanced air flow rate is limited to 2%.", DataHVACGlobals::cHXTypes(this->ExchType), this->Name);
4776 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer2 =
4777 0 : format("...Regeneration air mass flow rate is {} and process air mass flow rate is {}.", OutputCharRegen, OutputCharProc);
4778 0 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.buffer3 = format(
4779 0 : "...Occurrence info = {}, {}, {}", state.dataEnvrn->EnvironmentName, state.dataEnvrn->CurMnDy, CreateSysTimeIntervalString(state));
4780 : } else {
4781 4363 : state.dataHeatRecovery->BalDesDehumPerfData(this->PerfDataIndex).imbalancedFlowErr.print = false;
4782 : }
4783 : }
4784 :
4785 121 : int GetSupplyInletNode(EnergyPlusData &state,
4786 : std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
4787 : bool &ErrorsFound // set to true if problem
4788 : )
4789 : {
4790 :
4791 : // FUNCTION INFORMATION:
4792 : // AUTHOR Richard Raustad
4793 : // DATE WRITTEN February 2007
4794 : // MODIFIED na
4795 : // RE-ENGINEERED na
4796 :
4797 : // PURPOSE OF THIS FUNCTION:
4798 : // This function looks up the given HX and returns the supply air inlet node number.
4799 : // If incorrect HX name is given, ErrorsFound is returned as true and node number as zero.
4800 :
4801 : // Obtains and Allocates heat exchanger related parameters from input file
4802 121 : if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
4803 10 : GetHeatRecoveryInput(state);
4804 10 : state.dataHeatRecovery->GetInputFlag = false;
4805 : }
4806 :
4807 121 : int const WhichHX = UtilityRoutines::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
4808 121 : if (WhichHX != 0) {
4809 121 : return state.dataHeatRecovery->ExchCond(WhichHX).SupInletNode;
4810 : } else {
4811 0 : ShowSevereError(state, format("GetSupplyInletNode: Could not find heat exchanger = \"{}\"", HXName));
4812 0 : ErrorsFound = true;
4813 0 : return 0;
4814 : }
4815 : }
4816 :
4817 14 : int GetSupplyOutletNode(EnergyPlusData &state,
4818 : std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
4819 : bool &ErrorsFound // set to true if problem
4820 : )
4821 : {
4822 :
4823 : // FUNCTION INFORMATION:
4824 : // AUTHOR Richard Raustad
4825 : // DATE WRITTEN February 2007
4826 : // MODIFIED na
4827 : // RE-ENGINEERED na
4828 :
4829 : // PURPOSE OF THIS FUNCTION:
4830 : // This function looks up the given HX and returns the supply air outlet node number.
4831 : // If incorrect HX name is given, ErrorsFound is returned as true and node number as zero.
4832 :
4833 : // Obtains and Allocates heat exchanger related parameters from input file
4834 14 : if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
4835 0 : GetHeatRecoveryInput(state);
4836 0 : state.dataHeatRecovery->GetInputFlag = false;
4837 : }
4838 :
4839 14 : int const WhichHX = UtilityRoutines::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
4840 14 : if (WhichHX != 0) {
4841 14 : return state.dataHeatRecovery->ExchCond(WhichHX).SupOutletNode;
4842 : } else {
4843 0 : ShowSevereError(state, format("GetSupplyOutletNode: Could not find heat exchanger = \"{}\"", HXName));
4844 0 : ErrorsFound = true;
4845 0 : return 0;
4846 : }
4847 : }
4848 :
4849 121 : int GetSecondaryInletNode(EnergyPlusData &state,
4850 : std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
4851 : bool &ErrorsFound // set to true if problem
4852 : )
4853 : {
4854 :
4855 : // FUNCTION INFORMATION:
4856 : // AUTHOR Richard Raustad
4857 : // DATE WRITTEN February 2007
4858 : // MODIFIED na
4859 : // RE-ENGINEERED na
4860 :
4861 : // PURPOSE OF THIS FUNCTION:
4862 : // This function looks up the given HX and returns the secondary air inlet node number.
4863 : // If incorrect HX name is given, ErrorsFound is returned as true and node number as zero.
4864 :
4865 : // Obtains and Allocates heat exchanger related parameters from input file
4866 121 : if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
4867 2 : GetHeatRecoveryInput(state);
4868 2 : state.dataHeatRecovery->GetInputFlag = false;
4869 : }
4870 :
4871 121 : int const WhichHX = UtilityRoutines::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
4872 121 : if (WhichHX != 0) {
4873 121 : return state.dataHeatRecovery->ExchCond(WhichHX).SecInletNode;
4874 : } else {
4875 0 : ShowSevereError(state, format("GetSecondaryInletNode: Could not find heat exchanger = \"{}\"", HXName));
4876 0 : ErrorsFound = true;
4877 0 : return 0;
4878 : }
4879 : }
4880 :
4881 14 : int GetSecondaryOutletNode(EnergyPlusData &state,
4882 : std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
4883 : bool &ErrorsFound // set to true if problem
4884 : )
4885 : {
4886 :
4887 : // FUNCTION INFORMATION:
4888 : // AUTHOR Richard Raustad
4889 : // DATE WRITTEN February 2007
4890 : // MODIFIED na
4891 : // RE-ENGINEERED na
4892 :
4893 : // PURPOSE OF THIS FUNCTION:
4894 : // This function looks up the given HX assisted cooling coil and returns the secondary air outlet node number.
4895 : // If incorrect HX name is given, ErrorsFound is returned as true and node number as zero.
4896 :
4897 : // Obtains and Allocates heat exchanger related parameters from input file
4898 14 : if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
4899 0 : GetHeatRecoveryInput(state);
4900 0 : state.dataHeatRecovery->GetInputFlag = false;
4901 : }
4902 :
4903 14 : int const WhichHX = UtilityRoutines::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
4904 14 : if (WhichHX != 0) {
4905 14 : return state.dataHeatRecovery->ExchCond(WhichHX).SecOutletNode;
4906 : } else {
4907 0 : ShowSevereError(state, format("GetSecondaryOutletNode: Could not find heat exchanger = \"{}\"", HXName));
4908 0 : ErrorsFound = true;
4909 0 : return 0;
4910 : }
4911 : }
4912 :
4913 107 : Real64 GetSupplyAirFlowRate(EnergyPlusData &state,
4914 : std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
4915 : bool &ErrorsFound // set to true if problem
4916 : )
4917 : {
4918 :
4919 : // FUNCTION INFORMATION:
4920 : // AUTHOR Richard Raustad
4921 : // DATE WRITTEN October 2007
4922 : // MODIFIED na
4923 : // RE-ENGINEERED na
4924 :
4925 : // PURPOSE OF THIS FUNCTION:
4926 : // This function looks up the given Generic HX and the voluetric air flow rate.
4927 : // If incorrect HX name is given, ErrorsFound is returned as true and air flow rate as zero.
4928 :
4929 : // Obtains and Allocates heat exchanger related parameters from input file
4930 107 : if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
4931 0 : GetHeatRecoveryInput(state);
4932 0 : state.dataHeatRecovery->GetInputFlag = false;
4933 : }
4934 :
4935 107 : int const WhichHX = UtilityRoutines::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
4936 107 : if (WhichHX != 0) {
4937 107 : return state.dataHeatRecovery->ExchCond(WhichHX).NomSupAirVolFlow;
4938 : } else {
4939 0 : ShowSevereError(state, format("GetSupplyAirFlowRate: Could not find heat exchanger = \"{}\"", HXName));
4940 0 : ShowContinueError(state, "... Supply Air Flow Rate returned as 0.");
4941 0 : ErrorsFound = true;
4942 0 : return 0.0;
4943 : }
4944 : }
4945 :
4946 107 : int GetHeatExchangerObjectTypeNum(EnergyPlusData &state,
4947 : std::string const &HXName, // must match HX names for the state.dataHeatRecovery->ExchCond type
4948 : bool &ErrorsFound // set to true if problem
4949 : )
4950 : {
4951 :
4952 : // FUNCTION INFORMATION:
4953 : // AUTHOR Richard Raustad
4954 : // DATE WRITTEN October 2007
4955 : // MODIFIED na
4956 : // RE-ENGINEERED na
4957 :
4958 : // PURPOSE OF THIS FUNCTION:
4959 : // This function looks up the given Generic HX and the voluetric air flow rate.
4960 : // If incorrect HX name is given, ErrorsFound is returned as true and air flow rate as zero.
4961 :
4962 : // Obtains and Allocates heat exchanger related parameters from input file
4963 107 : if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
4964 5 : GetHeatRecoveryInput(state);
4965 5 : state.dataHeatRecovery->GetInputFlag = false;
4966 : }
4967 :
4968 107 : int const WhichHX = UtilityRoutines::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
4969 107 : if (WhichHX != 0) {
4970 107 : return state.dataHeatRecovery->ExchCond(WhichHX).ExchType;
4971 : } else {
4972 0 : ShowSevereError(state, format("GetHeatExchangerObjectTypeNum: Could not find heat exchanger = \"{}\"", HXName));
4973 0 : ErrorsFound = true;
4974 0 : return 0;
4975 : }
4976 : }
4977 :
4978 0 : void SetHeatExchangerData(EnergyPlusData &state,
4979 : int const HXNum, // Index of HX
4980 : bool &ErrorsFound, // Set to true if certain errors found
4981 : std::string const &HXName, // Name of HX
4982 : Optional<Real64> SupplyAirVolFlow, // HX supply air flow rate [m3/s]
4983 : Optional<Real64> SecondaryAirVolFlow // HX secondary air flow rate [m3/s]
4984 : )
4985 : {
4986 :
4987 : // SUBROUTINE INFORMATION:
4988 : // AUTHOR Richard Raustad
4989 : // DATE WRITTEN October 2007
4990 : // MODIFIED na
4991 : // RE-ENGINEERED na
4992 :
4993 : // PURPOSE OF THIS SUBROUTINE:
4994 : // This routine was designed for to autosize the HeatExchanger:AirToAir:SensibleAndLatent using
4995 : // information from the ZoneHVAC:EnergyRecoveryVentilator object.
4996 : // This is an illustration of setting data from an outside source.
4997 :
4998 : // Obtains and Allocates heat exchanger related parameters from input file
4999 0 : if (state.dataHeatRecovery->GetInputFlag) { // First time subroutine has been entered
5000 0 : GetHeatRecoveryInput(state);
5001 0 : state.dataHeatRecovery->GetInputFlag = false;
5002 : }
5003 :
5004 : int WhichHX; // index to generic HX
5005 0 : if (HXNum == 0) {
5006 0 : WhichHX = UtilityRoutines::FindItemInList(HXName, state.dataHeatRecovery->ExchCond);
5007 : } else {
5008 0 : WhichHX = HXNum;
5009 : }
5010 :
5011 0 : if (WhichHX <= 0 || WhichHX > state.dataHeatRecovery->NumHeatExchangers) {
5012 0 : ShowSevereError(state, format("SetHeatExchangerData: Could not find heat exchanger = \"{}\"", HXName));
5013 0 : ErrorsFound = true;
5014 0 : return;
5015 : }
5016 :
5017 0 : if (present(SupplyAirVolFlow)) {
5018 0 : state.dataHeatRecovery->ExchCond(WhichHX).NomSupAirVolFlow = SupplyAirVolFlow;
5019 : }
5020 :
5021 0 : if (present(SecondaryAirVolFlow)) {
5022 0 : state.dataHeatRecovery->ExchCond(WhichHX).NomSecAirVolFlow = SecondaryAirVolFlow;
5023 : }
5024 : }
5025 :
5026 : } // namespace HeatRecovery
5027 :
5028 2313 : } // namespace EnergyPlus
|