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