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