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 : // EnergyPlus Headers
52 : #include <EnergyPlus/CurveManager.hh>
53 : #include <EnergyPlus/Data/EnergyPlusData.hh>
54 : #include <EnergyPlus/DataContaminantBalance.hh>
55 : #include <EnergyPlus/DataEnvironment.hh>
56 : #include <EnergyPlus/DataHVACGlobals.hh>
57 : #include <EnergyPlus/DataLoopNode.hh>
58 : #include <EnergyPlus/DataWater.hh>
59 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
60 : #include <EnergyPlus/DataZoneEquipment.hh>
61 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
62 : #include <EnergyPlus/NodeInputManager.hh>
63 : #include <EnergyPlus/OutputProcessor.hh>
64 : #include <EnergyPlus/Psychrometrics.hh>
65 : #include <EnergyPlus/ScheduleManager.hh>
66 : #include <EnergyPlus/UtilityRoutines.hh>
67 : #include <EnergyPlus/WaterManager.hh>
68 : #include <EnergyPlus/ZoneDehumidifier.hh>
69 :
70 : namespace EnergyPlus {
71 :
72 : namespace ZoneDehumidifier {
73 :
74 : // Module containing the routines dealing with the ZoneDehumidifier
75 :
76 : // MODULE INFORMATION:
77 : // AUTHOR Don Shirey, FSEC
78 : // DATE WRITTEN July/Aug 2009
79 : // MODIFIED na
80 : // RE-ENGINEERED na
81 :
82 : // PURPOSE OF THIS MODULE:
83 : // Calculate the performance of zone (room) air dehumidifiers. Meant to model
84 : // conventional direct expansion (DX) cooling-based room air dehumidifiers
85 : // (reject 100% of condenser heat to the zone air), but the approach
86 : // might be able to be used to model other room air dehumidifier types.
87 :
88 : // METHODOLOGY EMPLOYED:
89 : // Model as a piece of zone equipment, with inputs for water removal and
90 : // energy factor at rated conditions (26.7C, 60% RH). Then provide curve objects
91 : // to describe performance at off-rated conditions. A part-load cycling curve
92 : // input is also provided. It is assumed that this equipment dehumidifies but
93 : // heats the air. If used in tandem with another system that cools and dehumidifies,
94 : // then the zone dehumidifier should be specified as the lowest cooling priority
95 : // in the ZoneHVAC:EquipmentList object. The cooling and dehumidification system
96 : // operates first to meet the temperature setpoint (and possibly the high humidity
97 : // setpoint as well). If additional dehumidification is needed, then the zone
98 : // dehumidifier operates. The excess sensible heat generated by the dehumidifier
99 : // is carried over to the next HVAC time step.
100 :
101 : // OTHER NOTES:
102 : // Example manufacturer's data at:
103 : // http://www.thermastor.com/HI-E-DRY-100/HI-E-DRY-100-Spec.pdf
104 : // http://www.thermastor.com/HI-E-DRY-195/HI-E-DRY-195-Spec.pdf
105 :
106 : // Using/Aliasing
107 : using namespace DataLoopNode;
108 :
109 11174 : void SimZoneDehumidifier(EnergyPlusData &state,
110 : std::string const &CompName, // Name of the zone dehumidifier
111 : int const ZoneNum, // Number of zone being served
112 : [[maybe_unused]] bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
113 : Real64 &QSensOut, // Sensible capacity delivered to zone (W)
114 : Real64 &QLatOut, // Latent capacity delivered to zone (kg/s), dehumidify = negative
115 : int &CompIndex // Index to the zone dehumidifier
116 : )
117 : {
118 :
119 : // SUBROUTINE INFORMATION:
120 : // AUTHOR Don Shirey, FSEC
121 : // DATE WRITTEN July/Aug 2009
122 : // MODIFIED na
123 : // RE-ENGINEERED na
124 :
125 : // PURPOSE OF THIS SUBROUTINE:
126 : // Simulate a zone dehumidifier.
127 :
128 : // METHODOLOGY EMPLOYED:
129 : // Call appropriate subroutines to get input values, initialize variables, model performanc
130 : // update node information, report model outputs.
131 :
132 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
133 : int ZoneDehumidNum; // Index of zone dehumidifier being simulated
134 : Real64 QZnDehumidReq; // Zone dehumidification load required (kg moisture/sec)
135 :
136 11174 : if (state.dataZoneDehumidifier->GetInputFlag) {
137 1 : GetZoneDehumidifierInput(state);
138 1 : state.dataZoneDehumidifier->GetInputFlag = false;
139 : }
140 :
141 : // Find the correct zone dehumidifier
142 11174 : if (CompIndex == 0) {
143 1 : ZoneDehumidNum = Util::FindItemInList(CompName, state.dataZoneDehumidifier->ZoneDehumid);
144 1 : if (ZoneDehumidNum == 0) {
145 0 : ShowFatalError(state, format("SimZoneDehumidifier: Unit not found= {}", CompName));
146 : }
147 1 : CompIndex = ZoneDehumidNum;
148 : } else {
149 11173 : ZoneDehumidNum = CompIndex;
150 11173 : int NumDehumidifiers = (int)state.dataZoneDehumidifier->ZoneDehumid.size();
151 11173 : if (ZoneDehumidNum > NumDehumidifiers || ZoneDehumidNum < 1) {
152 0 : ShowFatalError(state,
153 0 : format("SimZoneDehumidifier: Invalid CompIndex passed= {}, Number of Units= {}, Entered Unit name= {}",
154 : ZoneDehumidNum,
155 : NumDehumidifiers,
156 : CompName));
157 : }
158 11173 : if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidNum).CheckEquipName) {
159 1 : if (CompName != state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidNum).Name) {
160 0 : ShowFatalError(state,
161 0 : format("SimZoneDehumidifier: Invalid CompIndex passed={}, Unit name= {}, stored Unit Name for that index= {}",
162 : ZoneDehumidNum,
163 : CompName,
164 0 : state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidNum).Name));
165 : }
166 1 : state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidNum).CheckEquipName = false;
167 : }
168 : }
169 :
170 11174 : QZnDehumidReq = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ZoneNum).RemainingOutputReqToDehumidSP; // Negative means dehumidify
171 :
172 11174 : InitZoneDehumidifier(state, ZoneDehumidNum);
173 :
174 11174 : CalcZoneDehumidifier(state, ZoneDehumidNum, QZnDehumidReq, QSensOut, QLatOut);
175 :
176 11174 : UpdateZoneDehumidifier(state, ZoneDehumidNum);
177 :
178 11174 : ReportZoneDehumidifier(state, ZoneDehumidNum);
179 11174 : }
180 :
181 13 : void GetZoneDehumidifierInput(EnergyPlusData &state)
182 : {
183 :
184 : // SUBROUTINE INFORMATION:
185 : // AUTHOR Don Shirey, FSEC
186 : // DATE WRITTEN July/Aug 2009
187 : // MODIFIED na
188 : // RE-ENGINEERED na
189 :
190 : // PURPOSE OF THIS SUBROUTINE:
191 : // Retrieve the inputs from the input data file (idf) being simulated.
192 :
193 : // METHODOLOGY EMPLOYED:
194 : // Standard EnergyPlus methodology using available utility routines where appropriate.
195 :
196 : // Using/Aliasing
197 : using NodeInputManager::GetOnlySingleNode;
198 : using WaterManager::SetupTankSupplyComponent;
199 :
200 : // SUBROUTINE PARAMETER DEFINITIONS:
201 : static constexpr std::string_view routineName = "GetZoneDehumidifierInput";
202 39 : static std::string const CurrentModuleObject("ZoneHVAC:Dehumidifier:DX");
203 13 : Real64 constexpr RatedInletAirTemp(26.7);
204 13 : Real64 constexpr RatedInletAirRH(60.0);
205 :
206 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
207 : int ZoneDehumidIndex; // Loop index
208 13 : int NumAlphas(0); // Number of Alphas to allocate arrays, then used for each GetObjectItem call
209 13 : int NumNumbers(0); // Number of Numbers to allocate arrays, then used for each GetObjectItem call
210 : int IOStatus; // Used in GetObjectItem
211 13 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
212 13 : Array1D_string Alphas; // Alpha input items for object
213 13 : Array1D_string cAlphaFields; // Alpha field names
214 13 : Array1D_string cNumericFields; // Numeric field names
215 13 : Array1D<Real64> Numbers; // Numeric input items for object
216 13 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
217 13 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
218 13 : int TotalArgs(0); // Total number of alpha and numeric arguments (max)
219 : Real64 CurveVal; // Output from curve object (water removal or energy factor curves)
220 :
221 13 : int NumDehumidifiers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
222 :
223 13 : state.dataZoneDehumidifier->ZoneDehumid.allocate(NumDehumidifiers);
224 :
225 13 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, TotalArgs, NumAlphas, NumNumbers);
226 :
227 13 : Alphas.allocate(NumAlphas);
228 13 : cAlphaFields.allocate(NumAlphas);
229 13 : cNumericFields.allocate(NumNumbers);
230 13 : Numbers.dimension(NumNumbers, 0.0);
231 13 : lAlphaBlanks.dimension(NumAlphas, true);
232 13 : lNumericBlanks.dimension(NumNumbers, true);
233 :
234 14 : for (ZoneDehumidIndex = 1; ZoneDehumidIndex <= NumDehumidifiers; ++ZoneDehumidIndex) {
235 :
236 1 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
237 : CurrentModuleObject,
238 : ZoneDehumidIndex,
239 : Alphas,
240 : NumAlphas,
241 : Numbers,
242 : NumNumbers,
243 : IOStatus,
244 : lNumericBlanks,
245 : lAlphaBlanks,
246 : cAlphaFields,
247 : cNumericFields);
248 :
249 1 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
250 :
251 1 : auto &dehumid = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex);
252 : // A1, \field Name
253 1 : dehumid.Name = Alphas(1);
254 1 : dehumid.UnitType = CurrentModuleObject; // 'ZoneHVAC:Dehumidifier:DX'
255 :
256 : // A2, \field Availability Schedule Name
257 1 : if (lAlphaBlanks(2)) {
258 0 : dehumid.availSched = Sched::GetScheduleAlwaysOn(state);
259 1 : } else if ((dehumid.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
260 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
261 0 : ErrorsFound = true;
262 : }
263 :
264 : // A3 , \field Air Inlet Node Name
265 1 : dehumid.AirInletNodeNum = GetOnlySingleNode(state,
266 1 : Alphas(3),
267 : ErrorsFound,
268 : DataLoopNode::ConnectionObjectType::ZoneHVACDehumidifierDX,
269 1 : Alphas(1),
270 : DataLoopNode::NodeFluidType::Air,
271 : DataLoopNode::ConnectionType::Inlet,
272 : NodeInputManager::CompFluidStream::Primary,
273 : ObjectIsNotParent);
274 :
275 : // A4 , \field Air Outlet Node Name
276 1 : dehumid.AirOutletNodeNum = GetOnlySingleNode(state,
277 1 : Alphas(4),
278 : ErrorsFound,
279 : DataLoopNode::ConnectionObjectType::ZoneHVACDehumidifierDX,
280 1 : Alphas(1),
281 : DataLoopNode::NodeFluidType::Air,
282 : DataLoopNode::ConnectionType::Outlet,
283 : NodeInputManager::CompFluidStream::Primary,
284 : ObjectIsNotParent);
285 :
286 : // N1, \field Rated Water Removal
287 1 : dehumid.RatedWaterRemoval = Numbers(1);
288 1 : if (dehumid.RatedWaterRemoval <= 0.0) {
289 0 : ShowSevereError(state, format("{} must be greater than zero.", cNumericFields(1)));
290 0 : ShowContinueError(state, format("Value specified = {:.5T}", Numbers(1)));
291 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, dehumid.Name));
292 0 : ErrorsFound = true;
293 : }
294 :
295 : // N2, \field Rated Energy Factor
296 1 : dehumid.RatedEnergyFactor = Numbers(2);
297 1 : if (dehumid.RatedEnergyFactor <= 0.0) {
298 0 : ShowSevereError(state, format("{} must be greater than zero.", cNumericFields(2)));
299 0 : ShowContinueError(state, format("Value specified = {:.5T}", Numbers(2)));
300 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, dehumid.Name));
301 0 : ErrorsFound = true;
302 : }
303 :
304 : // N3, \field Rated Air Flow Rate
305 1 : dehumid.RatedAirVolFlow = Numbers(3);
306 1 : if (dehumid.RatedAirVolFlow <= 0.0) {
307 0 : ShowSevereError(state, format("{} must be greater than zero.", cNumericFields(3)));
308 0 : ShowContinueError(state, format("Value specified = {:.5T}", Numbers(3)));
309 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, dehumid.Name));
310 0 : ErrorsFound = true;
311 : }
312 :
313 : // A5, \field Water Removal Curve Name
314 1 : if (lAlphaBlanks(5)) {
315 0 : ShowSevereEmptyField(state, eoh, cAlphaFields(5));
316 0 : ErrorsFound = true;
317 1 : } else if ((dehumid.WaterRemovalCurve = Curve::GetCurve(state, Alphas(5))) == nullptr) {
318 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(5), Alphas(5));
319 0 : ErrorsFound = true;
320 1 : } else if (dehumid.WaterRemovalCurve->numDims != 2) {
321 0 : Curve::ShowSevereCurveDims(state, eoh, cAlphaFields(5), Alphas(5), "2", dehumid.WaterRemovalCurve->numDims);
322 0 : ErrorsFound = true;
323 : } else {
324 1 : Real64 CurveVal = dehumid.WaterRemovalCurve->value(state, RatedInletAirTemp, RatedInletAirRH);
325 1 : if (CurveVal > 1.10 || CurveVal < 0.90) {
326 0 : ShowWarningError(state, format("{} output is not equal to 1.0", cAlphaFields(5)));
327 0 : ShowContinueError(state, format("(+ or -10%) at rated conditions for {} = {}", CurrentModuleObject, Alphas(1)));
328 0 : ShowContinueError(state, format("Curve output at rated conditions = {:.3T}", CurveVal));
329 : }
330 : }
331 :
332 : // A6, \field Energy Factor Curve Name
333 1 : if (lAlphaBlanks(6)) {
334 0 : ShowSevereEmptyField(state, eoh, cAlphaFields(6));
335 0 : ErrorsFound = true;
336 1 : } else if ((dehumid.EnergyFactorCurve = Curve::GetCurve(state, Alphas(6))) == nullptr) {
337 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(6), Alphas(6));
338 0 : ErrorsFound = true;
339 1 : } else if (dehumid.EnergyFactorCurve->numDims != 2) {
340 0 : Curve::ShowSevereCurveDims(state, eoh, cAlphaFields(6), Alphas(6), "2", dehumid.EnergyFactorCurve->numDims);
341 0 : ErrorsFound = true;
342 : } else {
343 1 : Real64 CurveVal = dehumid.EnergyFactorCurve->value(state, RatedInletAirTemp, RatedInletAirRH);
344 1 : if (CurveVal > 1.10 || CurveVal < 0.90) {
345 0 : ShowWarningError(state, format("{} output is not equal to 1.0", cAlphaFields(6)));
346 0 : ShowContinueError(state, format("(+ or -10%) at rated conditions for {} = {}", CurrentModuleObject, Alphas(1)));
347 0 : ShowContinueError(state, format("Curve output at rated conditions = {:.3T}", CurveVal));
348 : }
349 : }
350 :
351 : // A7, \field Part Load Fraction Correlation Curve Name
352 1 : if (lAlphaBlanks(7)) {
353 0 : ShowSevereEmptyField(state, eoh, cAlphaFields(7));
354 0 : ErrorsFound = true;
355 1 : } else if ((dehumid.PartLoadCurve = Curve::GetCurve(state, Alphas(7))) == nullptr) {
356 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(7), Alphas(7));
357 0 : ErrorsFound = true;
358 1 : } else if (dehumid.PartLoadCurve->numDims != 1) {
359 0 : Curve::ShowSevereCurveDims(state, eoh, cAlphaFields(7), Alphas(7), "1", dehumid.PartLoadCurve->numDims);
360 0 : ErrorsFound = true;
361 : }
362 :
363 : // N4, \field Minimum Dry-Bulb Temperature for Dehumidifier Operation
364 : // N5, \field Maximum Dry-Bulb Temperature for Dehumidifier Operation
365 1 : dehumid.MinInletAirTemp = Numbers(4);
366 1 : dehumid.MaxInletAirTemp = Numbers(5);
367 :
368 1 : if (dehumid.MinInletAirTemp >= dehumid.MaxInletAirTemp) {
369 0 : ShowSevereError(state, format("{} must be greater than {}", cNumericFields(5), cNumericFields(4)));
370 0 : ShowContinueError(state, format("{} specified = {:.1T}", cNumericFields(5), Numbers(5)));
371 0 : ShowContinueError(state, format("{} specified = {:.1T}", cNumericFields(4), Numbers(4)));
372 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, dehumid.Name));
373 0 : ErrorsFound = true;
374 : }
375 :
376 : // N6, \field Off Cycle Parasitic Electric Load
377 1 : dehumid.OffCycleParasiticLoad = Numbers(6); // Off Cycle Parasitic Load [W]
378 :
379 1 : if (dehumid.OffCycleParasiticLoad < 0.0) {
380 0 : ShowSevereError(state, format("{} must be >= zero.", cNumericFields(6)));
381 0 : ShowContinueError(state, format("Value specified = {:.2T}", Numbers(6)));
382 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, dehumid.Name));
383 0 : ErrorsFound = true;
384 : }
385 :
386 : // A8; \field Condensate Collection Water Storage Tank Name
387 1 : dehumid.CondensateCollectName = Alphas(8);
388 1 : if (lAlphaBlanks(8)) {
389 1 : dehumid.CondensateCollectMode = CondensateOutlet::Discarded;
390 : } else {
391 0 : dehumid.CondensateCollectMode = CondensateOutlet::ToTank;
392 0 : SetupTankSupplyComponent(state,
393 : dehumid.Name,
394 : CurrentModuleObject,
395 : dehumid.CondensateCollectName,
396 : ErrorsFound,
397 0 : dehumid.CondensateTankID,
398 0 : dehumid.CondensateTankSupplyARRID);
399 : }
400 :
401 : } // DO ZoneDehumidIndex=1,NumDehumidifiers
402 :
403 13 : Alphas.deallocate();
404 13 : cAlphaFields.deallocate();
405 13 : cNumericFields.deallocate();
406 13 : Numbers.deallocate();
407 13 : lAlphaBlanks.deallocate();
408 13 : lNumericBlanks.deallocate();
409 :
410 13 : if (ErrorsFound) {
411 0 : ShowFatalError(state, format("{}:{}: Errors found in input.", routineName, CurrentModuleObject));
412 : }
413 :
414 14 : for (ZoneDehumidIndex = 1; ZoneDehumidIndex <= NumDehumidifiers; ++ZoneDehumidIndex) {
415 1 : auto &dehumid = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex);
416 : // Set up report variables for the dehumidifiers
417 2 : SetupOutputVariable(state,
418 : "Zone Dehumidifier Sensible Heating Rate",
419 : Constant::Units::W,
420 1 : dehumid.SensHeatingRate,
421 : OutputProcessor::TimeStepType::System,
422 : OutputProcessor::StoreType::Average,
423 1 : dehumid.Name);
424 2 : SetupOutputVariable(state,
425 : "Zone Dehumidifier Sensible Heating Energy",
426 : Constant::Units::J,
427 1 : dehumid.SensHeatingEnergy,
428 : OutputProcessor::TimeStepType::System,
429 : OutputProcessor::StoreType::Sum,
430 1 : dehumid.Name);
431 2 : SetupOutputVariable(state,
432 : "Zone Dehumidifier Removed Water Mass Flow Rate",
433 : Constant::Units::kg_s,
434 1 : dehumid.WaterRemovalRate,
435 : OutputProcessor::TimeStepType::System,
436 : OutputProcessor::StoreType::Average,
437 1 : dehumid.Name);
438 2 : SetupOutputVariable(state,
439 : "Zone Dehumidifier Removed Water Mass",
440 : Constant::Units::kg,
441 1 : dehumid.WaterRemoved,
442 : OutputProcessor::TimeStepType::System,
443 : OutputProcessor::StoreType::Sum,
444 1 : dehumid.Name);
445 2 : SetupOutputVariable(state,
446 : "Zone Dehumidifier Electricity Rate",
447 : Constant::Units::W,
448 1 : dehumid.ElecPower,
449 : OutputProcessor::TimeStepType::System,
450 : OutputProcessor::StoreType::Average,
451 1 : dehumid.Name);
452 2 : SetupOutputVariable(state,
453 : "Zone Dehumidifier Electricity Energy",
454 : Constant::Units::J,
455 1 : dehumid.ElecConsumption,
456 : OutputProcessor::TimeStepType::System,
457 : OutputProcessor::StoreType::Sum,
458 1 : dehumid.Name,
459 : Constant::eResource::Electricity,
460 : OutputProcessor::Group::HVAC,
461 : OutputProcessor::EndUseCat::Cooling);
462 2 : SetupOutputVariable(state,
463 : "Zone Dehumidifier Off Cycle Parasitic Electricity Rate",
464 : Constant::Units::W,
465 1 : dehumid.OffCycleParasiticElecPower,
466 : OutputProcessor::TimeStepType::System,
467 : OutputProcessor::StoreType::Average,
468 1 : dehumid.Name);
469 2 : SetupOutputVariable(state,
470 : "Zone Dehumidifier Off Cycle Parasitic Electricity Energy",
471 : Constant::Units::J,
472 1 : dehumid.OffCycleParasiticElecCons,
473 : OutputProcessor::TimeStepType::System,
474 : OutputProcessor::StoreType::Sum,
475 1 : dehumid.Name);
476 2 : SetupOutputVariable(state,
477 : "Zone Dehumidifier Part Load Ratio",
478 : Constant::Units::None,
479 1 : dehumid.DehumidPLR,
480 : OutputProcessor::TimeStepType::System,
481 : OutputProcessor::StoreType::Average,
482 1 : dehumid.Name);
483 2 : SetupOutputVariable(state,
484 : "Zone Dehumidifier Runtime Fraction",
485 : Constant::Units::None,
486 1 : dehumid.DehumidRTF,
487 : OutputProcessor::TimeStepType::System,
488 : OutputProcessor::StoreType::Average,
489 1 : dehumid.Name);
490 2 : SetupOutputVariable(state,
491 : "Zone Dehumidifier Outlet Air Temperature",
492 : Constant::Units::C,
493 1 : dehumid.OutletAirTemp,
494 : OutputProcessor::TimeStepType::System,
495 : OutputProcessor::StoreType::Average,
496 1 : dehumid.Name);
497 :
498 1 : if (dehumid.CondensateCollectMode == CondensateOutlet::ToTank) {
499 0 : SetupOutputVariable(state,
500 : "Zone Dehumidifier Condensate Volume Flow Rate",
501 : Constant::Units::m3_s,
502 0 : dehumid.DehumidCondVolFlowRate,
503 : OutputProcessor::TimeStepType::System,
504 : OutputProcessor::StoreType::Average,
505 0 : dehumid.Name);
506 0 : SetupOutputVariable(state,
507 : "Zone Dehumidifier Condensate Volume",
508 : Constant::Units::m3,
509 0 : dehumid.DehumidCondVol,
510 : OutputProcessor::TimeStepType::System,
511 : OutputProcessor::StoreType::Sum,
512 0 : dehumid.Name,
513 : Constant::eResource::OnSiteWater,
514 : OutputProcessor::Group::HVAC,
515 : OutputProcessor::EndUseCat::Condensate);
516 : }
517 : }
518 13 : }
519 :
520 11174 : void InitZoneDehumidifier(EnergyPlusData &state, int const ZoneDehumNum) // Number of the current zone dehumidifier being simulated
521 : {
522 :
523 : // SUBROUTINE INFORMATION:
524 : // AUTHOR Don Shirey, FSEC
525 : // DATE WRITTEN July/Aug 2009
526 : // MODIFIED na
527 : // RE-ENGINEERED na
528 :
529 : // PURPOSE OF THIS SUBROUTINE:
530 : // This subroutine initializes information for the zone dehumidifier model
531 :
532 : // METHODOLOGY EMPLOYED:
533 : // Use status flags to trigger various initializations
534 :
535 : // Using/Aliasing
536 : using DataZoneEquipment::CheckZoneEquipmentList;
537 : using Psychrometrics::PsyRhoAirFnPbTdbW;
538 : using Psychrometrics::PsyWFnTdbRhPb;
539 :
540 : // SUBROUTINE PARAMETER DEFINITIONS:
541 : static constexpr std::string_view RoutineName("InitZoneDehumidifier");
542 :
543 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
544 : int AirInletNode; // Inlet air node number
545 : Real64 RatedAirHumrat; // Humidity ratio (kg/kg) at rated inlet air conditions of 26.6667C, 60% RH
546 : Real64 RatedAirDBTemp; // Dry-bulb air temperature at rated conditions 26.6667C
547 : Real64 RatedAirRH; // Relative humidity of air (0.6 --> 60%) at rated conditions
548 :
549 11174 : auto &dehumid = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum);
550 : // Need to check all dehumidifiers to see if they are on Zone Equipment List or issue warning
551 11174 : if (!dehumid.ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
552 1 : dehumid.ZoneEquipmentListChecked = true;
553 1 : if (!CheckZoneEquipmentList(state, dehumid.UnitType, dehumid.Name)) {
554 0 : ShowSevereError(
555 : state,
556 0 : format("InitZoneDehumidifier: Zone Dehumidifier=\"{},{}\" is not on any ZoneHVAC:EquipmentList. It will not be simulated.",
557 0 : dehumid.UnitType,
558 0 : dehumid.Name));
559 : }
560 : }
561 :
562 11174 : AirInletNode = dehumid.AirInletNodeNum;
563 : // Do the Begin Environment initializations
564 11174 : if (state.dataGlobal->BeginEnvrnFlag && dehumid.MyEnvrnFlag) {
565 :
566 : // Set the mass flow rates from the input volume flow rates, at rated conditions of 26.6667C, 60% RH
567 : // Might default back to STP later after discussion with M. Witte, use StdRhoAir instead of calc'd RhoAir at rated conditions
568 4 : RatedAirDBTemp = 26.6667; // 26.6667 C, 80F
569 4 : RatedAirRH = 0.6; // 60% RH
570 4 : RatedAirHumrat = PsyWFnTdbRhPb(state, RatedAirDBTemp, RatedAirRH, state.dataEnvrn->StdBaroPress, RoutineName);
571 4 : dehumid.RatedAirMassFlow =
572 4 : PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, RatedAirDBTemp, RatedAirHumrat, RoutineName) * dehumid.RatedAirVolFlow;
573 :
574 : // Set the node max and min mass flow rates on inlet node... outlet node gets updated in UPDATE subroutine
575 4 : state.dataLoopNodes->Node(AirInletNode).MassFlowRateMax = dehumid.RatedAirMassFlow;
576 4 : state.dataLoopNodes->Node(AirInletNode).MassFlowRateMaxAvail = dehumid.RatedAirMassFlow;
577 4 : state.dataLoopNodes->Node(AirInletNode).MassFlowRateMinAvail = 0.0;
578 4 : state.dataLoopNodes->Node(AirInletNode).MassFlowRateMin = 0.0;
579 :
580 4 : dehumid.MyEnvrnFlag = false;
581 : } // End one time inits
582 :
583 11174 : if (!state.dataGlobal->BeginEnvrnFlag) {
584 11099 : dehumid.MyEnvrnFlag = true;
585 : }
586 :
587 : // These initializations are done every iteration
588 11174 : state.dataLoopNodes->Node(AirInletNode).MassFlowRate = dehumid.RatedAirMassFlow;
589 :
590 : // Zero out the report variables
591 11174 : dehumid.SensHeatingRate = 0.0; // Zone Dehumidifier Sensible Heating Rate [W]
592 11174 : dehumid.SensHeatingEnergy = 0.0; // Zone Dehumidifier Sensible Heating Energy [J]
593 11174 : dehumid.WaterRemovalRate = 0.0; // Zone Dehumidifier Water Removal Rate [kg/s]
594 11174 : dehumid.WaterRemoved = 0.0; // Zone Dehumidifier Water Removed [kg]
595 11174 : dehumid.ElecPower = 0.0; // Zone Dehumidifier Electric Power [W]
596 11174 : dehumid.ElecConsumption = 0.0; // Zone Dehumidifier Electric Consumption [J]
597 11174 : dehumid.DehumidPLR = 0.0; // Zone Dehumidifier Part-Load Ratio [-]
598 11174 : dehumid.DehumidRTF = 0.0; // Zone Dehumidifier Runtime Fraction [-]
599 11174 : dehumid.OffCycleParasiticElecPower = 0.0; // Zone Dehumidifier Off-Cycle Parasitic Electric Power [W]
600 11174 : dehumid.OffCycleParasiticElecCons = 0.0; // Zone Dehumidifier Off-Cycle Parasitic Electric Consumption [J]
601 11174 : dehumid.DehumidCondVolFlowRate = 0.0; // Zone Dehumidifier Condensate Volumetric Flow Rate [m3/s]
602 11174 : dehumid.DehumidCondVol = 0.0; // Zone Dehumidifier Condensate Volume [m3]
603 11174 : dehumid.OutletAirTemp = state.dataLoopNodes->Node(AirInletNode).Temp; // Zone Dehumidifier Outlet Air Temperature [C]
604 11174 : }
605 :
606 11174 : void CalcZoneDehumidifier(EnergyPlusData &state,
607 : int const ZoneDehumNum, // Index number of the current zone dehumidifier being simulated
608 : Real64 const QZnDehumidReq, // Dehumidification load to be met (kg/s), negative value means dehumidification load
609 : Real64 &SensibleOutput, // Sensible (heating) output (W), sent to load predictor for next simulation time step
610 : Real64 &LatentOutput // Latent (dehumidification) output provided (kg/s)
611 : )
612 : {
613 :
614 : // SUBROUTINE INFORMATION:
615 : // AUTHOR Don Shirey, FSEC
616 : // DATE WRITTEN July/Aug 2009
617 : // MODIFIED na
618 : // RE-ENGINEERED na
619 :
620 : // PURPOSE OF THIS SUBROUTINE:
621 : // Calculate the delivered capacity, electric energy consumption and water/condensate
622 : // removal rates for the zone dehumidifier.
623 :
624 : // METHODOLOGY EMPLOYED:
625 : // Cycle the dehumidifier as needed to meet the remaining zone dehumidification load.
626 : // Send excess sensible heat to zone energy balance (via SensibleOutput) for next HVAC time step,
627 : // so set the dehumidifier outlet air temp = inlet air temp to avoid double counting excess sensible.
628 :
629 : // REFERENCES:
630 : // na
631 :
632 : // Using/Aliasing
633 : using Psychrometrics::PsyCpAirFnW;
634 : using Psychrometrics::PsyHfgAirFnWTdb;
635 : using Psychrometrics::PsyHFnTdbW;
636 : using Psychrometrics::PsyRhFnTdbWPb;
637 : using Psychrometrics::RhoH2O;
638 :
639 : // Locals
640 : // SUBROUTINE ARGUMENT DEFINITIONS:
641 :
642 : // SUBROUTINE PARAMETER DEFINITIONS:
643 : static constexpr std::string_view RoutineName("CalcZoneDehumidifier");
644 :
645 : // INTERFACE BLOCK SPECIFICATIONS:
646 : // na
647 :
648 : // DERIVED TYPE DEFINITIONS:
649 : // na
650 :
651 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
652 : Real64 WaterRemovalRateFactor; // Adjustment to Rate Water Removal as a function of inlet air T and RH
653 : Real64 WaterRemovalVolRate; // Actual water removal rate at current inlet air conditions (L/day)
654 : Real64 WaterRemovalMassRate; // Actual water removal rate at current inlet air conditions (kg/s)
655 : Real64 EnergyFactorAdjFactor; // Adjustment to Rate Energy Factor as a function of inlet air T and RH
656 : Real64 EnergyFactor; // Actual Energy Factor as a function of inlet air T and RH
657 : Real64 InletAirTemp; // Dry-bulb temperature of air entering the dehumidifier (C)
658 : Real64 InletAirHumRat; // Humidity ratio of the air entering the dehumidifier (kg/kg)
659 : Real64 InletAirRH; // Relative humidity of air entering the dehumidifier (%)
660 : Real64 OutletAirTemp; // Dry-bulb temperature of air leaving the dehumidifier (C)
661 : Real64 OutletAirHumRat; // Humidity ratio of air leaving the dehumidifier (kg/kg)
662 : Real64 PLR; // Part-load ratio = (dehumid load to be met)/(dehumid capacity of the dehumidifier)
663 : Real64 PLF; // Part-load fraction (-), RuntimeFraction = PLR/PLF
664 : Real64 RunTimeFraction; // Dehumidifier runtime fraction (-)
665 : Real64 ElectricPowerOnCycle; // Electric power when dehumidifier is operating (W)
666 : Real64 ElectricPowerAvg; // Average electric power for this dehumidifier (W)
667 : Real64 hfg; // Enthalpy of evaporation of inlet air (J/kg)
668 : Real64 AirMassFlowRate; // Air mass flow rate through this dehumidifier (kg/s)
669 : Real64 Cp; // Heat capacity of inlet air (J/kg-C)
670 11174 : int AirInletNodeNum(0); // Node number for the inlet air to the dehumidifier
671 :
672 11174 : auto &dehumid = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum);
673 :
674 11174 : SensibleOutput = 0.0;
675 11174 : LatentOutput = 0.0;
676 11174 : WaterRemovalRateFactor = 0.0;
677 11174 : AirMassFlowRate = 0.0;
678 11174 : PLR = 0.0;
679 11174 : PLF = 0.0;
680 11174 : EnergyFactorAdjFactor = 0.0;
681 11174 : RunTimeFraction = 0.0;
682 11174 : ElectricPowerAvg = 0.0;
683 11174 : ElectricPowerOnCycle = 0.0;
684 :
685 11174 : AirInletNodeNum = dehumid.AirInletNodeNum;
686 :
687 11174 : InletAirTemp = state.dataLoopNodes->Node(AirInletNodeNum).Temp;
688 11174 : InletAirHumRat = state.dataLoopNodes->Node(AirInletNodeNum).HumRat;
689 11174 : InletAirRH = 100.0 * PsyRhFnTdbWPb(state, InletAirTemp, InletAirHumRat, state.dataEnvrn->OutBaroPress, RoutineName); // RH in percent (%)
690 :
691 11206 : if (QZnDehumidReq < 0.0 && dehumid.availSched->getCurrentVal() > 0.0 && InletAirTemp >= dehumid.MinInletAirTemp &&
692 32 : InletAirTemp <= dehumid.MaxInletAirTemp) {
693 : // A dehumidification load is being requested and dehumidifier is available (schedule value > 0)
694 : // and the inlet air temperature is within the min/max values specified by user input
695 :
696 32 : WaterRemovalRateFactor = dehumid.WaterRemovalCurve->value(state, InletAirTemp, InletAirRH);
697 : // Warn user if curve output goes negative
698 32 : if (WaterRemovalRateFactor <= 0.0) {
699 0 : if (dehumid.WaterRemovalCurveErrorCount < 1) {
700 0 : ++dehumid.WaterRemovalCurveErrorCount;
701 0 : ShowWarningError(state, format("{} \"{}\":", dehumid.UnitType, dehumid.Name));
702 0 : ShowContinueError(state, format(" Water Removal Rate Curve output is <= 0.0 ({:.5T}).", WaterRemovalRateFactor));
703 0 : ShowContinueError(
704 : state,
705 0 : format(
706 : " Negative value occurs using an inlet air dry-bulb temperature of {:.2T} and an inlet air relative humidity of {:.1T}.",
707 : InletAirTemp,
708 : InletAirRH));
709 0 : ShowContinueErrorTimeStamp(state, " Dehumidifier turned off for this time step but simulation continues.");
710 : } else {
711 0 : ShowRecurringWarningErrorAtEnd(state,
712 0 : dehumid.UnitType + " \"" + dehumid.Name +
713 : "\": Water Removal Rate Curve output is <= 0.0 warning continues...",
714 0 : dehumid.WaterRemovalCurveErrorIndex,
715 : WaterRemovalRateFactor,
716 : WaterRemovalRateFactor);
717 : }
718 0 : WaterRemovalRateFactor = 0.0;
719 : }
720 :
721 32 : WaterRemovalVolRate = WaterRemovalRateFactor * dehumid.RatedWaterRemoval;
722 :
723 32 : WaterRemovalMassRate =
724 32 : WaterRemovalVolRate / (Constant::rSecsInDay * 1000.0) *
725 32 : RhoH2O(max((InletAirTemp - 11.0), 1.0)); //(L/d)/(24 hr/day *3600 sec/hr * 1000 L/m3) | Density of water, minimum temp = 1.0C
726 :
727 32 : if (WaterRemovalMassRate > 0.0) {
728 32 : PLR = max(0.0, min(1.0, -QZnDehumidReq / WaterRemovalMassRate));
729 : } else {
730 0 : PLR = 0.0;
731 0 : RunTimeFraction = 0.0;
732 : }
733 :
734 32 : EnergyFactorAdjFactor = dehumid.EnergyFactorCurve->value(state, InletAirTemp, InletAirRH);
735 :
736 : // Warn user if curve output goes negative
737 32 : if (EnergyFactorAdjFactor <= 0.0) {
738 0 : if (dehumid.EnergyFactorCurveErrorCount < 1) {
739 0 : ++dehumid.EnergyFactorCurveErrorCount;
740 0 : ShowWarningError(state, format("{} \"{}\":", dehumid.UnitType, dehumid.Name));
741 0 : ShowContinueError(state, format(" Energy Factor Curve output is <= 0.0 ({:.5T}).", EnergyFactorAdjFactor));
742 0 : ShowContinueError(
743 : state,
744 0 : format(
745 : " Negative value occurs using an inlet air dry-bulb temperature of {:.2T} and an inlet air relative humidity of {:.1T}.",
746 : InletAirTemp,
747 : InletAirRH));
748 0 : ShowContinueErrorTimeStamp(state, " Dehumidifier turned off for this time step but simulation continues.");
749 : } else {
750 0 : ShowRecurringWarningErrorAtEnd(state,
751 0 : dehumid.UnitType + " \"" + dehumid.Name +
752 : "\": Energy Factor Curve output is <= 0.0 warning continues...",
753 0 : dehumid.EnergyFactorCurveErrorIndex,
754 : EnergyFactorAdjFactor,
755 : EnergyFactorAdjFactor);
756 : }
757 0 : ElectricPowerAvg = 0.0;
758 0 : PLR = 0.0;
759 0 : RunTimeFraction = 0.0;
760 : } else {
761 : // EnergyFactorAdjFactor is not negative, so proceed with calculations
762 32 : EnergyFactor = EnergyFactorAdjFactor * dehumid.RatedEnergyFactor;
763 :
764 32 : if (dehumid.PartLoadCurve != nullptr) {
765 32 : PLF = dehumid.PartLoadCurve->value(state, PLR); // Calculate part load fraction
766 : } else {
767 0 : PLF = 1.0;
768 : }
769 :
770 32 : if (PLF < 0.7) {
771 0 : if (dehumid.LowPLFErrorCount < 1) {
772 0 : ++dehumid.LowPLFErrorCount;
773 0 : ShowWarningError(state, format("{} \"{}\":", dehumid.UnitType, dehumid.Name));
774 0 : ShowContinueError(
775 0 : state, format(" The Part Load Fraction Correlation Curve output is ({:.2T}) at a part-load ratio ={:.3T}", PLF, PLR));
776 0 : ShowContinueErrorTimeStamp(state,
777 : " PLF curve values must be >= 0.7. PLF has been reset to 0.7 and simulation is continuing.");
778 : } else {
779 0 : ShowRecurringWarningErrorAtEnd(state,
780 0 : dehumid.UnitType + " \"" + dehumid.Name +
781 : "\": Part Load Fraction Correlation Curve output < 0.7 warning continues...",
782 0 : dehumid.LowPLFErrorIndex,
783 : PLF,
784 : PLF);
785 : }
786 0 : PLF = 0.7;
787 : }
788 :
789 32 : if (PLF > 1.0) {
790 0 : if (dehumid.HighPLFErrorCount < 1) {
791 0 : ++dehumid.HighPLFErrorCount;
792 0 : ShowWarningError(state, format("{} \"{}\":", dehumid.UnitType, dehumid.Name));
793 0 : ShowContinueError(
794 0 : state, format(" The Part Load Fraction Correlation Curve output is ({:.2T}) at a part-load ratio ={:.3T}", PLF, PLR));
795 0 : ShowContinueErrorTimeStamp(state,
796 : " PLF curve values must be < 1.0. PLF has been reset to 1.0 and simulation is continuing.");
797 : } else {
798 0 : ShowRecurringWarningErrorAtEnd(state,
799 0 : format("{} \"{}\": Part Load Fraction Correlation Curve output > 1.0 warning continues...",
800 0 : dehumid.UnitType,
801 0 : dehumid.Name),
802 0 : dehumid.HighPLFErrorIndex,
803 : PLF,
804 : PLF);
805 : }
806 0 : PLF = 1.0;
807 : }
808 :
809 32 : if (PLF > 0.0 && PLF >= PLR) {
810 32 : RunTimeFraction = PLR / PLF; // Calculate dehumidifier runtime fraction
811 : } else {
812 0 : if (dehumid.PLFPLRErrorCount < 1) {
813 0 : ++dehumid.PLFPLRErrorCount;
814 0 : ShowWarningError(state, format("{} \"{}\":", dehumid.UnitType, dehumid.Name));
815 0 : ShowContinueError(
816 : state,
817 0 : format("The part load fraction was less than the part load ratio calculated for this time step [PLR={:.4T}, PLF={:.4T}].",
818 : PLR,
819 : PLF));
820 0 : ShowContinueError(state, "Runtime fraction reset to 1 and the simulation will continue.");
821 0 : ShowContinueErrorTimeStamp(state, "");
822 : } else {
823 0 : ShowRecurringWarningErrorAtEnd(state,
824 0 : dehumid.UnitType + " \"" + dehumid.Name +
825 : "\": Part load fraction less than part load ratio warning continues...",
826 0 : dehumid.PLFPLRErrorIndex);
827 : }
828 0 : RunTimeFraction = 1.0;
829 : }
830 :
831 32 : if (RunTimeFraction > 1.0 && std::abs(RunTimeFraction - 1.0) > 0.001) {
832 0 : if (dehumid.HighRTFErrorCount < 1) {
833 0 : ++dehumid.HighRTFErrorCount;
834 0 : ShowWarningError(state, format("{} \"{}\":", dehumid.UnitType, dehumid.Name));
835 0 : ShowContinueError(state, format("The runtime fraction for this zone dehumidifier exceeded 1.0 [{:.4T}].", RunTimeFraction));
836 0 : ShowContinueError(state, "Runtime fraction reset to 1 and the simulation will continue.");
837 0 : ShowContinueErrorTimeStamp(state, "");
838 : } else {
839 0 : ShowRecurringWarningErrorAtEnd(state,
840 0 : dehumid.UnitType + " \"" + dehumid.Name +
841 : "\": Runtime fraction for zone dehumidifier exceeded 1.0 warning continues...",
842 0 : dehumid.HighRTFErrorIndex,
843 : RunTimeFraction,
844 : RunTimeFraction);
845 : }
846 0 : RunTimeFraction = 1.0;
847 : }
848 :
849 : // ElectricPowerOnCycle = Water removal volumetric rate (L/day) / (Energy Factor(L/kWh) * 24 hrs/day ) * 1000 Wh/kWh
850 32 : ElectricPowerOnCycle = WaterRemovalVolRate / (EnergyFactor * 24.0) * 1000.0; // Watts
851 : // ElectricPowerAvg = ElectricPowerOnCycle * RTF + (1-RTF)*OffCycleParsiticLoad
852 32 : ElectricPowerAvg = ElectricPowerOnCycle * RunTimeFraction + (1.0 - RunTimeFraction) * dehumid.OffCycleParasiticLoad; // average Watts
853 : }
854 :
855 32 : LatentOutput = WaterRemovalMassRate * PLR; // Average moisture removal rate, kg/s, for this timestep
856 32 : hfg = PsyHfgAirFnWTdb(InletAirHumRat, InletAirTemp);
857 32 : SensibleOutput = (LatentOutput * hfg) + ElectricPowerAvg; // Average sensible output, Watts
858 : // Send SensibleOutput to zone air heat balance via SysDepZoneLoads in ZoneEquipmentManager
859 :
860 32 : state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRate = dehumid.RatedAirMassFlow * PLR;
861 32 : AirMassFlowRate = state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRate; // Average air mass flow for this timestep
862 32 : Cp = PsyCpAirFnW(InletAirHumRat); // Heat capacity of air
863 32 : if (AirMassFlowRate > 0.0 && Cp > 0.0) {
864 32 : OutletAirTemp = InletAirTemp + (ElectricPowerOnCycle + (WaterRemovalMassRate * hfg)) / (dehumid.RatedAirMassFlow * Cp);
865 32 : OutletAirHumRat = InletAirHumRat - LatentOutput / AirMassFlowRate;
866 : } else {
867 0 : OutletAirTemp = InletAirTemp;
868 0 : OutletAirHumRat = InletAirHumRat;
869 : }
870 :
871 : } else {
872 :
873 : // No load or not available or inlet air temps beyond min/max limits, then set outlet conditions
874 : // equal to inlet conditions and PLR = RTF = 0.0
875 11142 : OutletAirTemp = InletAirTemp;
876 11142 : OutletAirHumRat = InletAirHumRat;
877 11142 : PLR = 0.0;
878 11142 : RunTimeFraction = 0.0;
879 11142 : state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRate = 0.0;
880 : // If available but didn't operate, then set electric power = off cycle parasitic load.
881 : // Else, electric power = 0.0
882 11142 : if (dehumid.availSched->getCurrentVal() > 0.0) {
883 11142 : ElectricPowerAvg = dehumid.OffCycleParasiticLoad; // off cycle parasitic is on entire timestep
884 : } else {
885 0 : ElectricPowerAvg = 0.0;
886 : }
887 : }
888 :
889 11174 : dehumid.OutletAirTemp = OutletAirTemp; // Update report variable here. Node outlet Temp set equal
890 : // to Node inlet Temp in Update subroutine
891 11174 : dehumid.OutletAirHumRat = OutletAirHumRat; // Store in structure, updated outlet node in Update subroutine
892 :
893 : // Use inlet air temperature in outlet air enthalpy calculation... since the sensible heat output
894 : // from the dehumidifier is being sent directly to the zone air heat balance for next hvac simulation time step
895 11174 : dehumid.OutletAirEnthalpy = PsyHFnTdbW(InletAirTemp, OutletAirHumRat);
896 :
897 11174 : dehumid.SensHeatingRate = SensibleOutput; // Report variable update, W, avg sens output when unit is 'on'
898 11174 : dehumid.WaterRemovalRate = LatentOutput; // Report variable update, kg/s
899 11174 : LatentOutput = -LatentOutput; // change sign... negative is dehumidification in zone air balance
900 :
901 11174 : dehumid.OffCycleParasiticElecPower = (1.0 - RunTimeFraction) * dehumid.OffCycleParasiticLoad;
902 11174 : dehumid.ElecPower = ElectricPowerAvg;
903 11174 : dehumid.DehumidPLR = PLR;
904 11174 : dehumid.DehumidRTF = RunTimeFraction;
905 11174 : }
906 :
907 11174 : void UpdateZoneDehumidifier(EnergyPlusData &state, int const ZoneDehumNum) // Number of the current zone dehumidifier being simulated
908 : {
909 :
910 : // SUBROUTINE INFORMATION:
911 : // AUTHOR Don Shirey, FSEC
912 : // DATE WRITTEN August 2009
913 : // MODIFIED na
914 : // RE-ENGINEERED na
915 :
916 : // PURPOSE OF THIS SUBROUTINE:
917 : // This subroutine is for passing results to the outlet air node.
918 :
919 11174 : auto &dehumid = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum);
920 11174 : auto &airInletNode = state.dataLoopNodes->Node(dehumid.AirInletNodeNum);
921 11174 : auto &airOutletNode = state.dataLoopNodes->Node(dehumid.AirOutletNodeNum);
922 :
923 : // Changed outlet node properties
924 11174 : airOutletNode.Enthalpy = dehumid.OutletAirEnthalpy;
925 11174 : airOutletNode.HumRat = dehumid.OutletAirHumRat;
926 : // Set outlet temp = inlet temp; send excess sensible heat directly to air heat balance
927 : // (via SensibleOutput and QSensOut) for the next hvac simulation time step.
928 11174 : airOutletNode.Temp = airInletNode.Temp;
929 :
930 : // Pass through output node properties
931 11174 : airOutletNode.Quality = airInletNode.Quality;
932 11174 : airOutletNode.Press = airInletNode.Press;
933 11174 : airOutletNode.MassFlowRate = airInletNode.MassFlowRate;
934 11174 : airOutletNode.MassFlowRateMin = airInletNode.MassFlowRateMin;
935 11174 : airOutletNode.MassFlowRateMax = airInletNode.MassFlowRateMax;
936 11174 : airOutletNode.MassFlowRateMinAvail = airInletNode.MassFlowRateMinAvail;
937 11174 : airOutletNode.MassFlowRateMaxAvail = airInletNode.MassFlowRateMaxAvail;
938 :
939 11174 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
940 0 : airOutletNode.CO2 = airInletNode.CO2;
941 : }
942 11174 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
943 0 : airOutletNode.GenContam = airInletNode.GenContam;
944 : }
945 11174 : }
946 :
947 11174 : void ReportZoneDehumidifier(EnergyPlusData &state, int const DehumidNum) // Index of the current zone dehumidifier being simulated
948 : {
949 :
950 : // SUBROUTINE INFORMATION:
951 : // AUTHOR Don Shirey, FSEC
952 : // DATE WRITTEN August 2009
953 : // MODIFIED na
954 : // RE-ENGINEERED na
955 :
956 : // PURPOSE OF THIS SUBROUTINE:
957 : // Fills some of the report variables for the zone dehumidifiers
958 :
959 : // Using/Aliasing
960 11174 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
961 : using Psychrometrics::RhoH2O;
962 :
963 : // DERIVED TYPE DEFINITIONS:
964 : // na
965 :
966 11174 : auto &dehumid = state.dataZoneDehumidifier->ZoneDehumid(DehumidNum);
967 :
968 11174 : dehumid.SensHeatingEnergy = dehumid.SensHeatingRate * TimeStepSysSec;
969 11174 : dehumid.WaterRemoved = dehumid.WaterRemovalRate * TimeStepSysSec;
970 11174 : dehumid.ElecConsumption = dehumid.ElecPower * TimeStepSysSec;
971 11174 : dehumid.OffCycleParasiticElecCons = dehumid.OffCycleParasiticElecPower * TimeStepSysSec;
972 :
973 : // Dehumidifier water collection to water storage tank (if needed)
974 11174 : if (dehumid.CondensateCollectMode == CondensateOutlet::ToTank) {
975 : // Calculate and report condensation rate (how much water extracted from the air stream)
976 : // Volumetric flow of water in m3/s for water system interactions
977 :
978 0 : int AirInletNodeNum = dehumid.AirInletNodeNum;
979 0 : Real64 InletAirTemp = state.dataLoopNodes->Node(AirInletNodeNum).Temp;
980 0 : Real64 OutletAirTemp = max((InletAirTemp - 11.0), 1.0); // Assume coil outlet air is 11C (20F) lower than inlet air temp
981 0 : Real64 RhoWater = RhoH2O(OutletAirTemp); // Density of water, minimum temp = 1.0 C
982 :
983 0 : if (RhoWater > 0.0) {
984 0 : dehumid.DehumidCondVolFlowRate = dehumid.WaterRemovalRate / RhoWater;
985 : }
986 :
987 0 : dehumid.DehumidCondVol = dehumid.DehumidCondVolFlowRate * TimeStepSysSec;
988 :
989 0 : state.dataWaterData->WaterStorage(dehumid.CondensateTankID).VdotAvailSupply(dehumid.CondensateTankSupplyARRID) =
990 0 : dehumid.DehumidCondVolFlowRate;
991 : // Assume water outlet temp = air outlet temp.... same assumption in other places in code (e.g., water coil component)
992 0 : state.dataWaterData->WaterStorage(dehumid.CondensateTankID).TwaterSupply(dehumid.CondensateTankSupplyARRID) = OutletAirTemp;
993 : }
994 11174 : }
995 :
996 53 : bool GetZoneDehumidifierNodeNumber(EnergyPlusData &state, int const NodeNumber) // Node being tested
997 : {
998 :
999 : // FUNCTION INFORMATION:
1000 : // AUTHOR Lixing Gu
1001 : // DATE WRITTEN August 2009
1002 : // MODIFIED na
1003 : // RE-ENGINEERED na
1004 :
1005 : // PURPOSE OF THIS FUNCTION:
1006 : // After making sure get input is done, the node number of indicated
1007 : // zone dehumidifier is returned.
1008 :
1009 : // Return value
1010 : bool FindZoneDehumidifierNodeNumber; // Zone Dehumidifier Node Number Check
1011 :
1012 53 : if (state.dataZoneDehumidifier->GetInputFlag) {
1013 12 : GetZoneDehumidifierInput(state);
1014 12 : state.dataZoneDehumidifier->GetInputFlag = false;
1015 : }
1016 :
1017 53 : FindZoneDehumidifierNodeNumber = false;
1018 54 : for (int ZoneDehumidIndex = 1; ZoneDehumidIndex <= (int)state.dataZoneDehumidifier->ZoneDehumid.size(); ++ZoneDehumidIndex) {
1019 3 : if (NodeNumber == state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).AirInletNodeNum) {
1020 1 : FindZoneDehumidifierNodeNumber = true;
1021 1 : break;
1022 : }
1023 2 : if (NodeNumber == state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).AirOutletNodeNum) {
1024 1 : FindZoneDehumidifierNodeNumber = true;
1025 1 : break;
1026 : }
1027 : }
1028 :
1029 53 : return FindZoneDehumidifierNodeNumber;
1030 : }
1031 :
1032 1 : int getZoneDehumidifierIndex(EnergyPlusData &state, std::string_view CompName)
1033 : {
1034 1 : if (state.dataZoneDehumidifier->GetInputFlag) {
1035 0 : GetZoneDehumidifierInput(state);
1036 0 : state.dataZoneDehumidifier->GetInputFlag = false;
1037 : }
1038 :
1039 1 : for (int ZoneDehumidNum = 1; ZoneDehumidNum <= (int)state.dataZoneDehumidifier->ZoneDehumid.size(); ++ZoneDehumidNum) {
1040 1 : if (Util::SameString(state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidNum).Name, CompName)) {
1041 1 : return ZoneDehumidNum;
1042 : }
1043 : }
1044 :
1045 0 : return 0;
1046 : }
1047 :
1048 : } // namespace ZoneDehumidifier
1049 :
1050 : } // namespace EnergyPlus
|