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 : // ObjexxFCL Headers
49 : #include <ObjexxFCL/Fmath.hh>
50 :
51 : // EnergyPlus Headers
52 : #include <EnergyPlus/Autosizing/Base.hh>
53 : #include <EnergyPlus/BranchNodeConnections.hh>
54 : #include <EnergyPlus/CurveManager.hh>
55 : #include <EnergyPlus/Data/EnergyPlusData.hh>
56 : #include <EnergyPlus/DataContaminantBalance.hh>
57 : #include <EnergyPlus/DataEnvironment.hh>
58 : #include <EnergyPlus/DataHVACGlobals.hh>
59 : #include <EnergyPlus/DataIPShortCuts.hh>
60 : #include <EnergyPlus/DataLoopNode.hh>
61 : #include <EnergyPlus/DataSizing.hh>
62 : #include <EnergyPlus/DataWater.hh>
63 : #include <EnergyPlus/EMSManager.hh>
64 : #include <EnergyPlus/FluidProperties.hh>
65 : #include <EnergyPlus/General.hh>
66 : #include <EnergyPlus/GeneralRoutines.hh>
67 : #include <EnergyPlus/GlobalNames.hh>
68 : #include <EnergyPlus/Humidifiers.hh>
69 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
70 : #include <EnergyPlus/NodeInputManager.hh>
71 : #include <EnergyPlus/OutputProcessor.hh>
72 : #include <EnergyPlus/Psychrometrics.hh>
73 : #include <EnergyPlus/ScheduleManager.hh>
74 : #include <EnergyPlus/UtilityRoutines.hh>
75 : #include <EnergyPlus/WaterManager.hh>
76 :
77 : namespace EnergyPlus {
78 :
79 : namespace Humidifiers {
80 :
81 : // Module containing the routines dealing with humidifiers
82 :
83 : // MODULE INFORMATION:
84 : // AUTHOR Fred Buhl
85 : // DATE WRITTEN September 2000
86 : // MODIFIED B Griffith, Aug. 2006 added water system interactions
87 : // February 2015, B.Nigusse, FSEC, - transitioned the code
88 : // to object oriented approach and Added gas fired humidifier
89 : // RE-ENGINEERED na
90 :
91 : // PURPOSE OF THIS MODULE:
92 : // To encapsulate the data and routines required to model humidifier
93 : // components in the EnergyPlus HVAC simulation
94 :
95 : // METHODOLOGY EMPLOYED:
96 : // The humidifier encompasses not just the component but also its
97 : // control. The humidifier adds moisture to its air inlet to meet
98 : // the HumRatMin setpoint at its exit node. The HumRatMin is set by
99 : // an external setpoint manager.
100 :
101 : // REFERENCES: ASHRAE HVAC 2 Toolkit, page 4-112
102 :
103 : // Using/Aliasing
104 : using namespace DataLoopNode;
105 : using HVAC::SmallMassFlow;
106 :
107 3 : void SimHumidifier(EnergyPlusData &state,
108 : std::string_view CompName, // name of the humidifier unit
109 : [[maybe_unused]] bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
110 : int &CompIndex // Pointer to Humidifier Unit
111 : )
112 : {
113 :
114 : // SUBROUTINE INFORMATION:
115 : // AUTHOR Fred Buhl
116 : // DATE WRITTEN September 2000
117 : // MODIFIED February 2015, B. Nigusse, FSEC, - Added gas fired humidifier
118 : // RE-ENGINEERED na
119 :
120 : // PURPOSE OF THIS SUBROUTINE:
121 : // Manage the simulation of an air humidifier
122 :
123 : // Using/Aliasing
124 :
125 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
126 : int HumNum; // index of humidifier unit being simulated
127 : Real64 WaterAddNeeded; // output in kg/s needed from humidifier to meet humidity setpoint
128 :
129 3 : if (state.dataHumidifiers->GetInputFlag) {
130 1 : GetHumidifierInput(state);
131 1 : state.dataHumidifiers->GetInputFlag = false;
132 : }
133 :
134 : // Get the humidifier unit index
135 3 : if (CompIndex == 0) {
136 1 : HumNum = Util::FindItemInList(CompName, state.dataHumidifiers->Humidifier);
137 1 : if (HumNum == 0) {
138 0 : ShowFatalError(state, format("SimHumidifier: Unit not found={}", CompName));
139 : }
140 1 : CompIndex = HumNum;
141 : } else {
142 2 : HumNum = CompIndex;
143 2 : if (HumNum > state.dataHumidifiers->NumHumidifiers || HumNum < 1) {
144 0 : ShowFatalError(state,
145 0 : format("SimHumidifier: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
146 : HumNum,
147 0 : state.dataHumidifiers->NumHumidifiers,
148 : CompName));
149 : }
150 2 : if (state.dataHumidifiers->CheckEquipName(HumNum)) {
151 1 : if (CompName != state.dataHumidifiers->Humidifier(HumNum).Name) {
152 0 : ShowFatalError(state,
153 0 : format("SimHumidifier: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
154 : HumNum,
155 : CompName,
156 0 : state.dataHumidifiers->Humidifier(HumNum).Name));
157 : }
158 1 : state.dataHumidifiers->CheckEquipName(HumNum) = false;
159 : }
160 : }
161 3 : if (HumNum <= 0) {
162 0 : ShowFatalError(state, format("SimHumidifier: Unit not found={}", CompName));
163 : }
164 :
165 3 : auto &thisHum = state.dataHumidifiers->Humidifier(HumNum);
166 :
167 3 : thisHum.InitHumidifier(state);
168 :
169 3 : thisHum.ControlHumidifier(state, WaterAddNeeded);
170 :
171 : // call the correct humidifier calculation routine
172 3 : switch (thisHum.HumType) {
173 3 : case HumidType::Electric: { // 'HUMIDIFIER:STEAM:ELECTRIC'
174 3 : thisHum.CalcElecSteamHumidifier(state, WaterAddNeeded);
175 3 : } break;
176 0 : case HumidType::Gas: { // 'HUMIDIFIER:STEAM:GAS'
177 0 : thisHum.CalcGasSteamHumidifier(state, WaterAddNeeded);
178 0 : } break;
179 0 : default: {
180 0 : ShowSevereError(state, format("SimHumidifier: Invalid Humidifier Type Code={}", thisHum.HumType));
181 0 : ShowContinueError(state, format("...Component Name=[{}].", CompName));
182 0 : ShowFatalError(state, "Preceding Condition causes termination.");
183 0 : } break;
184 : }
185 :
186 3 : thisHum.UpdateReportWaterSystem(state);
187 :
188 3 : thisHum.UpdateHumidifier(state);
189 :
190 3 : thisHum.ReportHumidifier(state);
191 3 : }
192 :
193 5 : void GetHumidifierInput(EnergyPlusData &state)
194 : {
195 :
196 : // SUBROUTINE INFORMATION:
197 : // AUTHOR Fred Buhl
198 : // DATE WRITTEN September 2000
199 : // MODIFIED February 2015, B. Nigusse, FSEC, - Added gas fired humidifier
200 : // RE-ENGINEERED na
201 :
202 : // PURPOSE OF THIS SUBROUTINE:
203 : // Obtains input data for humidifiers and stores it in humidifier data structures.
204 :
205 : // METHODOLOGY EMPLOYED:
206 : // Uses InputProcessor "Get" routines to obtain data.
207 :
208 : // Using/Aliasing
209 : using BranchNodeConnections::TestCompSet;
210 : using Curve::GetCurveIndex;
211 : using NodeInputManager::GetOnlySingleNode;
212 : using WaterManager::SetupTankDemandComponent;
213 : using WaterManager::SetupTankSupplyComponent;
214 :
215 : // SUBROUTINE PARAMETER DEFINITIONS:
216 : static constexpr std::string_view RoutineName("GetHumidifierInputs: "); // include trailing blank space
217 : static constexpr std::string_view routineName = "GetHumidifierInputs"; // include trailing blank space
218 :
219 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
220 : int HumidifierIndex; // loop index
221 : int HumNum; // current humidifier number
222 : int NumAlphas; // Number of Alphas for each GetObjectItem call
223 : int NumNumbers; // Number of Numbers for each GetObjectItem call
224 : int MaxNums; // maximum Number of Numbers for each GetObjectItem call
225 : int MaxAlphas; // maximum Number of Numbers for each GetObjectItem call
226 : int IOStatus; // Used in GetObjectItem
227 5 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
228 5 : std::string CurrentModuleObject; // for ease in getting objects
229 5 : Array1D_string Alphas; // Alpha input items for object
230 5 : Array1D_string cAlphaFields; // Alpha field names
231 5 : Array1D_string cNumericFields; // Numeric field names
232 5 : Array1D<Real64> Numbers; // Numeric input items for object
233 5 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
234 5 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
235 5 : int TotalArgs(0); // Total number of alpha and numeric arguments (max) for a
236 :
237 : // Update Nums in state and make local convenience copies
238 5 : CurrentModuleObject = "Humidifier:Steam:Electric";
239 10 : int NumElecSteamHums = state.dataHumidifiers->NumElecSteamHums =
240 5 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
241 5 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, TotalArgs, NumAlphas, NumNumbers);
242 5 : MaxNums = NumNumbers;
243 5 : MaxAlphas = NumAlphas;
244 5 : CurrentModuleObject = "Humidifier:Steam:Gas";
245 10 : int NumGasSteamHums = state.dataHumidifiers->NumGasSteamHums =
246 5 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
247 5 : int NumHumidifiers = state.dataHumidifiers->NumHumidifiers = NumElecSteamHums + NumGasSteamHums;
248 5 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, TotalArgs, NumAlphas, NumNumbers);
249 5 : MaxNums = max(MaxNums, NumNumbers);
250 5 : MaxAlphas = max(MaxAlphas, NumAlphas);
251 :
252 : // allocate the data array
253 5 : state.dataHumidifiers->Humidifier.allocate(NumHumidifiers);
254 5 : state.dataHumidifiers->HumidifierUniqueNames.reserve(static_cast<unsigned>(NumHumidifiers));
255 5 : state.dataHumidifiers->CheckEquipName.dimension(NumHumidifiers, true);
256 :
257 5 : Alphas.allocate(MaxAlphas);
258 5 : cAlphaFields.allocate(MaxAlphas);
259 5 : cNumericFields.allocate(MaxNums);
260 5 : Numbers.dimension(MaxNums, 0.0);
261 5 : lAlphaBlanks.dimension(MaxAlphas, true);
262 5 : lNumericBlanks.dimension(MaxAlphas, true);
263 :
264 : // loop over electric steam humidifiers and load the input data
265 5 : CurrentModuleObject = "Humidifier:Steam:Electric";
266 9 : for (HumidifierIndex = 1; HumidifierIndex <= NumElecSteamHums; ++HumidifierIndex) {
267 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
268 : CurrentModuleObject,
269 : HumidifierIndex,
270 : Alphas,
271 : NumAlphas,
272 : Numbers,
273 : NumNumbers,
274 : IOStatus,
275 : lNumericBlanks,
276 : lAlphaBlanks,
277 : cAlphaFields,
278 : cNumericFields);
279 :
280 4 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
281 4 : HumNum = HumidifierIndex;
282 4 : auto &Humidifier = state.dataHumidifiers->Humidifier(HumNum);
283 4 : GlobalNames::VerifyUniqueInterObjectName(
284 8 : state, state.dataHumidifiers->HumidifierUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
285 4 : Humidifier.Name = Alphas(1);
286 4 : Humidifier.HumType = HumidType::Electric;
287 :
288 4 : if (lAlphaBlanks(2)) {
289 0 : Humidifier.availSched = Sched::GetScheduleAlwaysOn(state);
290 4 : } else if ((Humidifier.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
291 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
292 0 : ErrorsFound = true;
293 : }
294 4 : Humidifier.NomCapVol = Numbers(1);
295 4 : Humidifier.NomPower = Numbers(2);
296 4 : Humidifier.FanPower = Numbers(3);
297 4 : Humidifier.StandbyPower = Numbers(4);
298 4 : Humidifier.AirInNode = GetOnlySingleNode(state,
299 4 : Alphas(3),
300 : ErrorsFound,
301 : DataLoopNode::ConnectionObjectType::HumidifierSteamElectric,
302 4 : Alphas(1),
303 : DataLoopNode::NodeFluidType::Air,
304 : DataLoopNode::ConnectionType::Inlet,
305 : NodeInputManager::CompFluidStream::Primary,
306 : ObjectIsNotParent);
307 8 : Humidifier.AirOutNode = GetOnlySingleNode(state,
308 4 : Alphas(4),
309 : ErrorsFound,
310 : DataLoopNode::ConnectionObjectType::HumidifierSteamElectric,
311 4 : Alphas(1),
312 : DataLoopNode::NodeFluidType::Air,
313 : DataLoopNode::ConnectionType::Outlet,
314 : NodeInputManager::CompFluidStream::Primary,
315 : ObjectIsNotParent);
316 4 : TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
317 :
318 : // A5; \field Name of Water Storage Tank
319 4 : if (lAlphaBlanks(5)) {
320 4 : Humidifier.SuppliedByWaterSystem = false;
321 : } else { // water from storage tank
322 0 : SetupTankDemandComponent(
323 0 : state, Alphas(1), CurrentModuleObject, Alphas(5), ErrorsFound, Humidifier.WaterTankID, Humidifier.WaterTankDemandARRID);
324 0 : Humidifier.SuppliedByWaterSystem = true;
325 : }
326 : }
327 :
328 : // loop over gas fired steam humidifiers and load the input data
329 5 : CurrentModuleObject = "Humidifier:Steam:Gas";
330 6 : for (HumidifierIndex = 1; HumidifierIndex <= NumGasSteamHums; ++HumidifierIndex) {
331 1 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
332 : CurrentModuleObject,
333 : HumidifierIndex,
334 : Alphas,
335 : NumAlphas,
336 : Numbers,
337 : NumNumbers,
338 : IOStatus,
339 : lNumericBlanks,
340 : lAlphaBlanks,
341 : cAlphaFields,
342 : cNumericFields);
343 :
344 1 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
345 :
346 1 : HumNum = NumElecSteamHums + HumidifierIndex;
347 1 : auto &Humidifier = state.dataHumidifiers->Humidifier(HumNum);
348 1 : GlobalNames::VerifyUniqueInterObjectName(
349 2 : state, state.dataHumidifiers->HumidifierUniqueNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
350 1 : Humidifier.Name = Alphas(1);
351 1 : Humidifier.HumType = HumidType::Gas;
352 :
353 1 : if (lAlphaBlanks(2)) {
354 1 : Humidifier.availSched = Sched::GetScheduleAlwaysOn(state);
355 0 : } else if ((Humidifier.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
356 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
357 0 : ErrorsFound = true;
358 : }
359 1 : Humidifier.NomCapVol = Numbers(1);
360 1 : Humidifier.NomPower = Numbers(2); // nominal gas use rate for gas fired steam humidifier
361 1 : Humidifier.ThermalEffRated = Numbers(3);
362 1 : Humidifier.FanPower = Numbers(4);
363 1 : Humidifier.StandbyPower = Numbers(5);
364 1 : Humidifier.AirInNode = GetOnlySingleNode(state,
365 1 : Alphas(4),
366 : ErrorsFound,
367 : DataLoopNode::ConnectionObjectType::HumidifierSteamGas,
368 1 : Alphas(1),
369 : DataLoopNode::NodeFluidType::Air,
370 : DataLoopNode::ConnectionType::Inlet,
371 : NodeInputManager::CompFluidStream::Primary,
372 : ObjectIsNotParent);
373 2 : Humidifier.AirOutNode = GetOnlySingleNode(state,
374 1 : Alphas(5),
375 : ErrorsFound,
376 : DataLoopNode::ConnectionObjectType::HumidifierSteamGas,
377 1 : Alphas(1),
378 : DataLoopNode::NodeFluidType::Air,
379 : DataLoopNode::ConnectionType::Outlet,
380 : NodeInputManager::CompFluidStream::Primary,
381 : ObjectIsNotParent);
382 1 : TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(4), Alphas(5), "Air Nodes");
383 :
384 1 : Humidifier.EfficiencyCurvePtr = GetCurveIndex(state, Alphas(3));
385 1 : if (Humidifier.EfficiencyCurvePtr > 0) {
386 3 : ErrorsFound |= Curve::CheckCurveDims(state,
387 : Humidifier.EfficiencyCurvePtr, // Curve index
388 : {1}, // Valid dimensions
389 : RoutineName, // Routine name
390 : CurrentModuleObject, // Object Type
391 : Humidifier.Name, // Object Name
392 1 : cAlphaFields(3)); // Field Name
393 0 : } else if (!lAlphaBlanks(3)) {
394 0 : ShowSevereError(state, format("{}{}=\"{}\",", RoutineName, CurrentModuleObject, Alphas(1)));
395 0 : ShowContinueError(state, format("Invalid {}={}", cAlphaFields(3), Alphas(3)));
396 0 : ShowContinueError(state, format("...{} not found.", cAlphaFields(3)));
397 0 : ErrorsFound = true;
398 : }
399 :
400 : // A6; \field Name of Water Storage Tank
401 1 : if (lAlphaBlanks(6)) {
402 1 : Humidifier.SuppliedByWaterSystem = false;
403 : } else { // water from storage tank
404 0 : SetupTankDemandComponent(
405 0 : state, Alphas(1), CurrentModuleObject, Alphas(6), ErrorsFound, Humidifier.WaterTankID, Humidifier.WaterTankDemandARRID);
406 0 : SetupTankSupplyComponent(
407 0 : state, Alphas(1), CurrentModuleObject, Alphas(6), ErrorsFound, Humidifier.WaterTankID, Humidifier.TankSupplyID);
408 0 : Humidifier.SuppliedByWaterSystem = true;
409 : }
410 :
411 : // A7; \field Inlet Water Temperature Option
412 1 : if (lAlphaBlanks(7)) {
413 1 : Humidifier.InletWaterTempOption = InletWaterTemp::Fixed;
414 : } else { // water from storage tank
415 0 : Humidifier.InletWaterTempOption = static_cast<InletWaterTemp>(getEnumValue(inletWaterTempsUC, Alphas(7)));
416 : }
417 : }
418 :
419 10 : for (HumNum = 1; HumNum <= NumHumidifiers; ++HumNum) {
420 : // Setup Report variables for the Humidifiers
421 5 : auto &Humidifier = state.dataHumidifiers->Humidifier(HumNum);
422 5 : if (Humidifier.SuppliedByWaterSystem) {
423 0 : SetupOutputVariable(state,
424 : "Humidifier Water Volume Flow Rate",
425 : Constant::Units::m3_s,
426 0 : Humidifier.WaterConsRate,
427 : OutputProcessor::TimeStepType::System,
428 : OutputProcessor::StoreType::Average,
429 0 : Humidifier.Name);
430 0 : SetupOutputVariable(state,
431 : "Humidifier Water Volume",
432 : Constant::Units::m3,
433 0 : Humidifier.WaterCons,
434 : OutputProcessor::TimeStepType::System,
435 : OutputProcessor::StoreType::Sum,
436 0 : Humidifier.Name);
437 0 : SetupOutputVariable(state,
438 : "Humidifier Storage Tank Water Volume Flow Rate",
439 : Constant::Units::m3_s,
440 0 : Humidifier.TankSupplyVdot,
441 : OutputProcessor::TimeStepType::System,
442 : OutputProcessor::StoreType::Average,
443 0 : Humidifier.Name);
444 0 : SetupOutputVariable(state,
445 : "Humidifier Storage Tank Water Volume",
446 : Constant::Units::m3,
447 0 : Humidifier.TankSupplyVol,
448 : OutputProcessor::TimeStepType::System,
449 : OutputProcessor::StoreType::Sum,
450 0 : Humidifier.Name,
451 : Constant::eResource::Water,
452 : OutputProcessor::Group::HVAC,
453 : OutputProcessor::EndUseCat::Humidification);
454 0 : SetupOutputVariable(state,
455 : "Humidifier Starved Storage Tank Water Volume Flow Rate",
456 : Constant::Units::m3_s,
457 0 : Humidifier.StarvedSupplyVdot,
458 : OutputProcessor::TimeStepType::System,
459 : OutputProcessor::StoreType::Average,
460 0 : Humidifier.Name);
461 0 : SetupOutputVariable(state,
462 : "Humidifier Starved Storage Tank Water Volume",
463 : Constant::Units::m3,
464 0 : Humidifier.StarvedSupplyVol,
465 : OutputProcessor::TimeStepType::System,
466 : OutputProcessor::StoreType::Sum,
467 0 : Humidifier.Name,
468 : Constant::eResource::Water,
469 : OutputProcessor::Group::HVAC,
470 : OutputProcessor::EndUseCat::Humidification);
471 0 : SetupOutputVariable(state,
472 : "Humidifier Mains Water Volume",
473 : Constant::Units::m3,
474 0 : Humidifier.StarvedSupplyVol,
475 : OutputProcessor::TimeStepType::System,
476 : OutputProcessor::StoreType::Sum,
477 0 : Humidifier.Name,
478 : Constant::eResource::MainsWater,
479 : OutputProcessor::Group::HVAC,
480 : OutputProcessor::EndUseCat::Humidification);
481 :
482 : } else {
483 10 : SetupOutputVariable(state,
484 : "Humidifier Water Volume Flow Rate",
485 : Constant::Units::m3_s,
486 5 : Humidifier.WaterConsRate,
487 : OutputProcessor::TimeStepType::System,
488 : OutputProcessor::StoreType::Average,
489 5 : Humidifier.Name);
490 10 : SetupOutputVariable(state,
491 : "Humidifier Water Volume",
492 : Constant::Units::m3,
493 5 : Humidifier.WaterCons,
494 : OutputProcessor::TimeStepType::System,
495 : OutputProcessor::StoreType::Sum,
496 5 : Humidifier.Name,
497 : Constant::eResource::Water,
498 : OutputProcessor::Group::HVAC,
499 : OutputProcessor::EndUseCat::Humidification);
500 10 : SetupOutputVariable(state,
501 : "Humidifier Mains Water Volume",
502 : Constant::Units::m3,
503 5 : Humidifier.WaterCons,
504 : OutputProcessor::TimeStepType::System,
505 : OutputProcessor::StoreType::Sum,
506 5 : Humidifier.Name,
507 : Constant::eResource::MainsWater,
508 : OutputProcessor::Group::HVAC,
509 : OutputProcessor::EndUseCat::Humidification);
510 : }
511 5 : if (Humidifier.HumType == HumidType::Electric) {
512 8 : SetupOutputVariable(state,
513 : "Humidifier Electricity Rate",
514 : Constant::Units::W,
515 4 : Humidifier.ElecUseRate,
516 : OutputProcessor::TimeStepType::System,
517 : OutputProcessor::StoreType::Average,
518 4 : Humidifier.Name);
519 8 : SetupOutputVariable(state,
520 : "Humidifier Electricity Energy",
521 : Constant::Units::J,
522 4 : Humidifier.ElecUseEnergy,
523 : OutputProcessor::TimeStepType::System,
524 : OutputProcessor::StoreType::Sum,
525 4 : Humidifier.Name,
526 : Constant::eResource::Electricity,
527 : OutputProcessor::Group::HVAC,
528 : OutputProcessor::EndUseCat::Humidification);
529 1 : } else if (Humidifier.HumType == HumidType::Gas) {
530 2 : SetupOutputVariable(state,
531 : "Humidifier NaturalGas Use Thermal Efficiency",
532 : Constant::Units::None,
533 1 : Humidifier.ThermalEff,
534 : OutputProcessor::TimeStepType::System,
535 : OutputProcessor::StoreType::Average,
536 1 : Humidifier.Name);
537 2 : SetupOutputVariable(state,
538 : "Humidifier NaturalGas Rate",
539 : Constant::Units::W,
540 1 : Humidifier.GasUseRate,
541 : OutputProcessor::TimeStepType::System,
542 : OutputProcessor::StoreType::Average,
543 1 : Humidifier.Name);
544 2 : SetupOutputVariable(state,
545 : "Humidifier NaturalGas Energy",
546 : Constant::Units::J,
547 1 : Humidifier.GasUseEnergy,
548 : OutputProcessor::TimeStepType::System,
549 : OutputProcessor::StoreType::Sum,
550 1 : Humidifier.Name,
551 : Constant::eResource::NaturalGas,
552 : OutputProcessor::Group::HVAC,
553 : OutputProcessor::EndUseCat::Humidification);
554 2 : SetupOutputVariable(state,
555 : "Humidifier Auxiliary Electricity Rate",
556 : Constant::Units::W,
557 1 : Humidifier.AuxElecUseRate,
558 : OutputProcessor::TimeStepType::System,
559 : OutputProcessor::StoreType::Average,
560 1 : Humidifier.Name);
561 2 : SetupOutputVariable(state,
562 : "Humidifier Auxiliary Electricity Energy",
563 : Constant::Units::J,
564 1 : Humidifier.AuxElecUseEnergy,
565 : OutputProcessor::TimeStepType::System,
566 : OutputProcessor::StoreType::Sum,
567 1 : Humidifier.Name,
568 : Constant::eResource::Electricity,
569 : OutputProcessor::Group::HVAC,
570 : OutputProcessor::EndUseCat::Humidification);
571 : }
572 : }
573 :
574 5 : Alphas.deallocate();
575 5 : cAlphaFields.deallocate();
576 5 : cNumericFields.deallocate();
577 5 : Numbers.deallocate();
578 5 : lAlphaBlanks.deallocate();
579 5 : lNumericBlanks.deallocate();
580 :
581 5 : if (ErrorsFound) {
582 0 : ShowFatalError(state, format("{}Errors found in input.", RoutineName));
583 : }
584 5 : }
585 :
586 3 : void HumidifierData::InitHumidifier(EnergyPlusData &state) // number of the current humidifier being simulated
587 : {
588 :
589 : // SUBROUTINE INFORMATION:
590 : // AUTHOR Fred Buhl
591 : // DATE WRITTEN September 2000
592 : // MODIFIED February 2015, B. Nigusse, FSEC, - Added gas fired humidifier
593 : // RE-ENGINEERED na
594 :
595 : // PURPOSE OF THIS SUBROUTINE:
596 : // This subroutine is for initializations of the Humidifier Components.
597 :
598 : // METHODOLOGY EMPLOYED:
599 : // Uses the status flags to trigger initializations.
600 :
601 : // REFERENCES:
602 : // na
603 :
604 : // Using/Aliasing
605 : using EMSManager::CheckIfNodeSetPointManagedByEMS;
606 :
607 : // Locals
608 : // SUBROUTINE ARGUMENT DEFINITIONS:
609 :
610 : // do sizing calculation once
611 3 : if (MySizeFlag) {
612 1 : SizeHumidifier(state);
613 1 : MySizeFlag = false;
614 : }
615 :
616 3 : if (!state.dataGlobal->SysSizingCalc && MySetPointCheckFlag && state.dataHVACGlobal->DoSetPointTest) {
617 0 : if (AirOutNode > 0) {
618 0 : if (state.dataLoopNodes->Node(AirOutNode).HumRatMin == SensedNodeFlagValue) {
619 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
620 0 : ShowSevereError(
621 : state,
622 0 : format("Humidifiers: Missing humidity setpoint for {} = {}", format(HumidifierType[static_cast<int>(HumType)]), Name));
623 0 : ShowContinueError(state,
624 : " use a Setpoint Manager with Control Variable = \"MinimumHumidityRatio\" to establish a setpoint at the "
625 : "humidifier outlet node.");
626 0 : ShowContinueError(state, format(" expecting it on Node=\"{}\".", state.dataLoopNodes->NodeID(AirOutNode)));
627 0 : state.dataHVACGlobal->SetPointErrorFlag = true;
628 : } else {
629 0 : CheckIfNodeSetPointManagedByEMS(state, AirOutNode, HVAC::CtrlVarType::MinHumRat, state.dataHVACGlobal->SetPointErrorFlag);
630 0 : if (state.dataHVACGlobal->SetPointErrorFlag) {
631 0 : ShowSevereError(state,
632 0 : format("Humidifiers: Missing humidity setpoint for {} = {}",
633 0 : format(HumidifierType[static_cast<int>(HumType)]),
634 0 : Name));
635 0 : ShowContinueError(state,
636 : " use a Setpoint Manager with Control Variable = \"MinimumHumidityRatio\" to establish a setpoint at "
637 : "the humidifier outlet node.");
638 0 : ShowContinueError(state, format(" expecting it on Node=\"{}\".", state.dataLoopNodes->NodeID(AirOutNode)));
639 0 : ShowContinueError(
640 : state,
641 : " or use an EMS actuator to control minimum humidity ratio to establish a setpoint at the humidifier outlet node.");
642 : }
643 : }
644 : }
645 : }
646 0 : MySetPointCheckFlag = false;
647 : }
648 :
649 3 : if (!state.dataGlobal->BeginEnvrnFlag) {
650 0 : MyEnvrnFlag = true;
651 : }
652 :
653 : // do these initializations every HVAC time step
654 3 : HumRatSet = state.dataLoopNodes->Node(AirOutNode).HumRatMin;
655 3 : AirInTemp = state.dataLoopNodes->Node(AirInNode).Temp;
656 3 : AirInHumRat = state.dataLoopNodes->Node(AirInNode).HumRat;
657 3 : AirInEnthalpy = state.dataLoopNodes->Node(AirInNode).Enthalpy;
658 3 : AirInMassFlowRate = state.dataLoopNodes->Node(AirInNode).MassFlowRate;
659 :
660 3 : WaterAdd = 0.0;
661 3 : ElecUseEnergy = 0.0;
662 3 : ElecUseRate = 0.0;
663 3 : WaterCons = 0.0;
664 3 : WaterConsRate = 0.0;
665 3 : ThermalEff = 0.0;
666 3 : GasUseRate = 0.0;
667 3 : GasUseEnergy = 0.0;
668 3 : AuxElecUseRate = 0.0;
669 3 : AuxElecUseEnergy = 0.0;
670 3 : }
671 :
672 4 : void HumidifierData::SizeHumidifier(EnergyPlusData &state) // number of the current humidifier being sized
673 : {
674 :
675 : // SUBROUTINE INFORMATION:
676 : // AUTHOR Bereket Nigusse, UCF/FSEC,
677 : // DATE WRITTEN March, 2012
678 : // MODIFIED May 2014, Daeho Kang, PNNL - Added additional sizing field
679 : // February 2015, B. Nigusse, FSEC, - Added gas fired humidifier
680 : // RE-ENGINEERED na
681 :
682 : // PURPOSE OF THIS SUBROUTINE:
683 : // This subroutine is for for sizing electric steam humidifier nominal electric power.
684 :
685 : // METHODOLOGY EMPLOYED:
686 : // Uses user specified nominal capacity in m3/s and water enthalpy change required to
687 : // vaporize water from a reference temperature of 20.0C. to steam at 100.0C.
688 : // m_dot = Nominal Capacity [m3/s] * Density of water at 5.05 [kg/m3]
689 : // Nominal Capacity = m_dot [kg/s] * delta_enthalpy [J/kg]
690 :
691 : // REFERENCES:
692 : // na
693 :
694 : // Using/Aliasing
695 : using DataSizing::AutoSize;
696 :
697 : using Psychrometrics::PsyRhoAirFnPbTdbW;
698 : using Psychrometrics::RhoH2O;
699 :
700 : // Locals
701 : // SUBROUTINE ARGUMENT DEFINITIONS:
702 :
703 : // SUBROUTINE PARAMETER DEFINITIONS:
704 : static constexpr std::string_view CalledFrom("Humidifier:SizeHumidifier");
705 4 : Real64 constexpr Tref(20.0); // Reference temp of water for rated capacity calcs [C]
706 4 : Real64 constexpr TSteam(100.0); // saturated steam temperature generated by Humidifier [C]
707 :
708 : // INTERFACE BLOCK SPECIFICATIONS
709 : // na
710 :
711 : // DERIVED TYPE DEFINITIONS
712 : // na
713 :
714 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
715 : Real64 NominalPower; // Nominal power input to humidifier, W
716 : Real64 WaterSpecHeatAvg; // specific heat of water, J/kgK
717 : Real64 SteamSatEnthalpy; // enthalpy of saturated steam at 100C, J/kg
718 : Real64 WaterSatEnthalpy; // enthalpy of saturated water at 100C, J/kg
719 4 : bool ErrorsFound(false); // TRUE if errors detected in input
720 : Real64 NomPowerDes; // Autosized nominal power for reporting
721 : Real64 NomPowerUser; // Hardsized nominal power for reporting
722 : Real64 NomCapVolDes; // Autosized Nominal capacity volume for reporting
723 : Real64 NomCapVolUser; // HardSized nominal capacity volume for reporting
724 : Real64 AirVolFlow; // Design air volume flow rate
725 : Real64 AirDensity; // Density of air
726 :
727 4 : Real64 MassFlowDes = 0.0; // Design air mass flow rate
728 4 : Real64 InletHumRatDes = 0.0; // Design inlet humidity ratio
729 4 : Real64 OutletHumRatDes = 0.0; // Design outlet humidity ratio
730 :
731 4 : if (HumType == HumidType::Electric || HumType == HumidType::Gas) {
732 4 : bool IsAutoSize = false;
733 4 : bool HardSizeNoDesRun = false;
734 4 : NomPowerDes = 0.0;
735 4 : NomPowerUser = 0.0;
736 4 : std::string ModuleObjectType; // for ease in getting objects
737 :
738 4 : if (HumType == HumidType::Electric) {
739 1 : ModuleObjectType = "electric";
740 3 : } else if (HumType == HumidType::Gas) {
741 3 : ModuleObjectType = "gas";
742 : }
743 4 : if (NomCapVol == AutoSize) {
744 1 : IsAutoSize = true;
745 : }
746 4 : if (state.dataSize->CurZoneEqNum > 0) {
747 0 : if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Hardsize with no sizing run
748 0 : HardSizeNoDesRun = true;
749 0 : if (NomCapVol > 0.0) {
750 0 : BaseSizer::reportSizerOutput(state,
751 0 : format(HumidifierType[static_cast<int>(HumType)]),
752 : Name,
753 : "User-Specified Nominal Capacity Volume [m3/s]",
754 : NomCapVol);
755 : }
756 : } else { // Sizing run done
757 :
758 0 : CheckZoneSizing(state, "Humidifier:SizeHumidifier", Name);
759 0 : AirDensity = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolDens;
760 0 : MassFlowDes = max(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow,
761 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesHeatVolFlow) *
762 : AirDensity;
763 0 : InletHumRatDes = std::min(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).OutHumRatAtHeatPeak,
764 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).OutHumRatAtCoolPeak);
765 0 : OutletHumRatDes = std::max(state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneHumRatAtHeatPeak,
766 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).ZoneHumRatAtCoolPeak);
767 : }
768 4 : } else if (state.dataSize->CurSysNum > 0) {
769 4 : if (!IsAutoSize && !state.dataSize->SysSizingRunDone) {
770 1 : HardSizeNoDesRun = true;
771 1 : if (NomCapVol > 0.0) {
772 3 : BaseSizer::reportSizerOutput(state,
773 2 : format(HumidifierType[static_cast<int>(HumType)]),
774 : Name,
775 : "User-Specified Nominal Capacity Volume [m3/s]",
776 : NomCapVol);
777 : }
778 : } else {
779 3 : CheckSysSizing(state, "Humidifier:SizeHumidifier", Name);
780 3 : auto &thisFinalSysSizing = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum);
781 3 : if (state.dataSize->CurOASysNum > 0 && thisFinalSysSizing.DesOutAirVolFlow > 0.0) {
782 : // size to outdoor air volume flow rate if available
783 0 : AirDensity = PsyRhoAirFnPbTdbW(
784 0 : state, state.dataEnvrn->OutBaroPress, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat, CalledFrom);
785 0 : MassFlowDes = thisFinalSysSizing.DesOutAirVolFlow * AirDensity;
786 0 : InletHumRatDes = std::min(thisFinalSysSizing.OutHumRatAtCoolPeak, thisFinalSysSizing.HeatOutHumRat);
787 0 : OutletHumRatDes = std::max(thisFinalSysSizing.CoolSupHumRat, thisFinalSysSizing.HeatSupHumRat);
788 : } else { // ELSE size to supply air duct flow rate
789 3 : switch (state.dataSize->CurDuctType) {
790 0 : case HVAC::AirDuctType::Cooling: {
791 0 : AirVolFlow = thisFinalSysSizing.DesCoolVolFlow;
792 0 : } break;
793 0 : case HVAC::AirDuctType::Heating: {
794 0 : AirVolFlow = thisFinalSysSizing.DesHeatVolFlow;
795 0 : } break;
796 3 : default: {
797 3 : AirVolFlow = thisFinalSysSizing.DesMainVolFlow;
798 3 : } break;
799 : }
800 :
801 3 : AirDensity = PsyRhoAirFnPbTdbW(state,
802 3 : state.dataEnvrn->OutBaroPress,
803 : thisFinalSysSizing.MixTempAtCoolPeak,
804 : thisFinalSysSizing.MixHumRatAtCoolPeak,
805 : CalledFrom);
806 3 : MassFlowDes = AirVolFlow * AirDensity;
807 3 : InletHumRatDes = std::min(thisFinalSysSizing.MixHumRatAtCoolPeak, thisFinalSysSizing.HeatMixHumRat);
808 3 : OutletHumRatDes = std::max(thisFinalSysSizing.CoolSupHumRat, thisFinalSysSizing.HeatSupHumRat);
809 : }
810 : }
811 : }
812 :
813 4 : if (!HardSizeNoDesRun) {
814 3 : NomCapVolDes = MassFlowDes * (OutletHumRatDes - InletHumRatDes) / RhoH2O(Constant::InitConvTemp);
815 3 : if (NomCapVolDes < 0.0) {
816 0 : NomCapVolDes = 0.0; // No humidity demand
817 : }
818 :
819 3 : if (IsAutoSize) {
820 1 : NomCapVol = NomCapVolDes;
821 3 : BaseSizer::reportSizerOutput(
822 2 : state, format(HumidifierType[static_cast<int>(HumType)]), Name, "Design Size Nominal Capacity Volume [m3/s]", NomCapVolDes);
823 : } else {
824 2 : if (NomCapVol > 0.0) {
825 2 : NomCapVolUser = NomCapVol;
826 6 : BaseSizer::reportSizerOutput(state,
827 4 : format(HumidifierType[static_cast<int>(HumType)]),
828 : Name,
829 : "Design Size Nominal Capacity Volume [m3/s]",
830 : NomCapVolDes,
831 : "User-Specified Nominal Capacity Volume [m3/s]",
832 : NomCapVolUser);
833 2 : if (state.dataGlobal->DisplayExtraWarnings) {
834 0 : if ((std::abs(NomCapVolDes - NomCapVolUser) / NomCapVolUser) > state.dataSize->AutoVsHardSizingThreshold) {
835 0 : ShowMessage(state,
836 0 : format("SizeHumidifier: Potential issue with equipment sizing for {} = \"{}\".",
837 0 : format(HumidifierType[static_cast<int>(HumType)]),
838 0 : Name));
839 0 : ShowContinueError(state, format("User-Specified Nominal Capacity Volume of {:.2R} [Wm3/s]", NomCapVolUser));
840 0 : ShowContinueError(state, format("differs from Design Size Nominal Capacity Volume of {:.2R} [m3/s]", NomCapVolDes));
841 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
842 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
843 : }
844 : }
845 : }
846 : }
847 : }
848 :
849 4 : NomCap = RhoH2O(Constant::InitConvTemp) * NomCapVol;
850 :
851 4 : auto *water = Fluid::GetWater(state);
852 4 : auto *steam = Fluid::GetSteam(state);
853 4 : SteamSatEnthalpy = steam->getSatEnthalpy(state, TSteam, 1.0, CalledFrom);
854 4 : WaterSatEnthalpy = steam->getSatEnthalpy(state, TSteam, 0.0, CalledFrom);
855 4 : WaterSpecHeatAvg = 0.5 * (water->getSpecificHeat(state, TSteam, CalledFrom) + water->getSpecificHeat(state, Tref, CalledFrom));
856 4 : NominalPower = NomCap * ((SteamSatEnthalpy - WaterSatEnthalpy) + WaterSpecHeatAvg * (TSteam - Tref));
857 :
858 4 : if (NomPower == AutoSize) {
859 2 : IsAutoSize = true;
860 : }
861 :
862 4 : if (HumType == HumidType::Gas) {
863 :
864 3 : if (!IsAutoSize) {
865 : // override user specified rated thermal efficiency
866 1 : if (NomPower >= NominalPower) {
867 0 : ThermalEffRated = NominalPower / NomPower;
868 : } else {
869 2 : ShowMessage(state,
870 2 : format("{}: capacity and thermal efficiency mismatch for {} =\"{}\".",
871 : CalledFrom,
872 2 : format(HumidifierType[static_cast<int>(HumType)]),
873 1 : Name));
874 1 : ShowContinueError(state, format("User-Specified Rated Gas Use Rate of {:.2R} [W]", NomPower));
875 1 : ShowContinueError(state, format("User-Specified or Autosized Rated Capacity of {:.2R} [m3/s]", NomCapVol));
876 2 : ShowContinueError(state,
877 2 : format("Rated Gas Use Rate at the Rated Capacity of {:.2R} [m3/s] must be greater than the ideal, i.e., "
878 : "100% thermal efficiency gas use rate of {:.2R} [W]",
879 1 : NomCapVol,
880 : NomPowerDes));
881 2 : ShowContinueError(state,
882 : "Resize the Rated Gas Use Rate by dividing the ideal gas use rate with expected thermal efficiency. ");
883 : // Changing this from a hard-stop condition to just a limiting condition of eta=1.0
884 : // ErrorsFound = true;
885 1 : ThermalEffRated = 1.0;
886 : }
887 : } else {
888 2 : if (ThermalEffRated > 0.0) {
889 2 : NominalPower = NominalPower / ThermalEffRated;
890 : }
891 : }
892 :
893 : // gas fired steam humidifier's nominal gas use rate is always autosized
894 3 : IsAutoSize = true;
895 : }
896 :
897 4 : NomPowerDes = NominalPower;
898 4 : if (IsAutoSize) {
899 3 : NomPower = NomPowerDes;
900 9 : BaseSizer::reportSizerOutput(
901 6 : state, format(HumidifierType[static_cast<int>(HumType)]), Name, "Design Size Rated Power [W]", NomPowerDes);
902 : } else {
903 1 : if (NomPower >= 0.0 && NomCap > 0.0) {
904 1 : NomPowerUser = NomPower;
905 3 : BaseSizer::reportSizerOutput(state,
906 2 : format(HumidifierType[static_cast<int>(HumType)]),
907 : Name,
908 : "Design Size Rated Power [W]",
909 : NomPowerDes,
910 : "User-Specified Rated Power [W]",
911 : NomPowerUser);
912 1 : if (state.dataGlobal->DisplayExtraWarnings) {
913 0 : if ((std::abs(NomPowerDes - NomPowerUser) / NomPowerUser) > state.dataSize->AutoVsHardSizingThreshold) {
914 0 : ShowMessage(state,
915 0 : format("SizeHumidifier: Potential issue with equipment sizing for {} =\"{}\".",
916 0 : format(HumidifierType[static_cast<int>(HumType)]),
917 0 : Name));
918 0 : ShowContinueError(state, format("User-Specified Rated Power of {:.2R} [W]", NomPowerUser));
919 0 : ShowContinueError(state, format("differs from Design Size Rated Power of {:.2R} [W]", NomPowerDes));
920 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
921 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
922 : }
923 : }
924 1 : if (NomPower < NominalPower) {
925 0 : ShowWarningError(state,
926 0 : format(HumidifierType[static_cast<int>(HumType)]) +
927 0 : ": specified Rated Power is less than nominal Rated Power for " + ModuleObjectType +
928 0 : " steam humidifier = " + Name + ". ");
929 0 : ShowContinueError(state, format(" specified Rated Power = {:.2R}", NomPower));
930 0 : ShowContinueError(state, format(" while expecting a minimum Rated Power = {:.2R}", NominalPower));
931 : }
932 : } else {
933 0 : ShowWarningError(state,
934 0 : format(HumidifierType[static_cast<int>(HumType)]) + ": specified nominal capacity is zero for " +
935 0 : ModuleObjectType + " steam humidifier = " + Name + ". ");
936 0 : ShowContinueError(state, " For zero nominal capacity humidifier the rated power is zero.");
937 : }
938 : }
939 4 : }
940 :
941 4 : if (ErrorsFound) {
942 0 : ShowFatalError(state,
943 0 : format("{}: Mismatch was found in the Rated Gas Use Rate and Thermal Efficiency for gas fired steam humidifier = {}. ",
944 : CalledFrom,
945 0 : Name));
946 : }
947 4 : }
948 :
949 3 : void HumidifierData::ControlHumidifier(EnergyPlusData &state,
950 : Real64 &WaterAddNeeded // moisture addition rate needed to meet minimum humidity ratio setpoint [kg/s]
951 : )
952 : {
953 :
954 : // SUBROUTINE INFORMATION:
955 : // AUTHOR Fred Buhl
956 : // DATE WRITTEN September 2000
957 : // MODIFIED February 2015, B. Nigusse, FSEC, - transitioned the code to OO approach
958 : // RE-ENGINEERED na
959 :
960 : // PURPOSE OF THIS SUBROUTINE:
961 : // This subroutine sets the output required from the humidifier
962 :
963 : // METHODOLOGY EMPLOYED:
964 : // Uses a minimum humidity setpoint and water mass balance to calculate moisture addition needed
965 :
966 : // REFERENCES:
967 : // na
968 :
969 : // Using/Aliasing
970 : using Psychrometrics::PsyWFnTdbRhPb;
971 :
972 : // Locals
973 : // SUBROUTINE ARGUMENT DEFINITIONS:
974 : static constexpr std::string_view RoutineName("ControlHumidifier");
975 :
976 : // SUBROUTINE PARAMETER DEFINITIONS:
977 : // na
978 :
979 : // INTERFACE BLOCK SPECIFICATIONS
980 : // na
981 :
982 : // DERIVED TYPE DEFINITIONS
983 : // na
984 :
985 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
986 : bool UnitOn; // unit on flag
987 : Real64 HumRatSatIn; // humidity ratio at saturation at the inlet temperature [kgWater/kgDryAir]
988 :
989 3 : UnitOn = true;
990 3 : if (HumRatSet <= 0.0) {
991 2 : UnitOn = false;
992 : }
993 3 : if (AirInMassFlowRate <= SmallMassFlow) {
994 1 : UnitOn = false;
995 : }
996 3 : if (availSched->getCurrentVal() <= 0.0) {
997 0 : UnitOn = false;
998 : }
999 3 : if (AirInHumRat >= HumRatSet) {
1000 2 : UnitOn = false;
1001 : }
1002 3 : HumRatSatIn = PsyWFnTdbRhPb(state, AirInTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1003 3 : if (AirInHumRat >= HumRatSatIn) {
1004 0 : UnitOn = false;
1005 : }
1006 3 : if (UnitOn) {
1007 : // AirMassFlowRate*AirInHumRat + WaterAddNeeded = AirMassFlowRate*HumRatSet
1008 1 : WaterAddNeeded = AirInMassFlowRate * (HumRatSet - AirInHumRat);
1009 : } else {
1010 2 : WaterAddNeeded = 0.0;
1011 : }
1012 3 : }
1013 :
1014 3 : void HumidifierData::CalcElecSteamHumidifier(EnergyPlusData &state, Real64 const WaterAddNeeded // moisture addition rate set by controller [kg/s]
1015 : )
1016 : {
1017 :
1018 : // SUBROUTINE INFORMATION:
1019 : // AUTHOR Fred Buhl
1020 : // DATE WRITTEN September 2000
1021 : // MODIFIED February 2015, B. Nigusse, FSEC, - transitioned the code to OO approach
1022 : // RE-ENGINEERED na
1023 :
1024 : // PURPOSE OF THIS SUBROUTINE:
1025 : // Calculate the electricity consumption and the outlet conditions for an electric steam
1026 : // humidifier, given the inlet conditions and the steam addition rate.
1027 :
1028 : // METHODOLOGY EMPLOYED:
1029 : // Uses energy and mass balance as well as pschrometric relations.
1030 :
1031 : // REFERENCES:
1032 : // ASHRAE HVAC 2 Toolkit, page 4-112
1033 : // 1997 ASHRAE Handbook Fundamentals, page 6.18
1034 :
1035 : // Using/Aliasing
1036 : using Psychrometrics::PsyHFnTdbW;
1037 : using Psychrometrics::PsyTdbFnHW;
1038 : using Psychrometrics::PsyWFnTdbRhPb;
1039 : using Psychrometrics::RhoH2O;
1040 :
1041 : // Locals
1042 : // SUBROUTINE ARGUMENT DEFINITIONS:
1043 :
1044 : // SUBROUTINE PARAMETER DEFINITIONS:
1045 : static constexpr std::string_view RoutineName("CalcElecSteamHumidifier");
1046 :
1047 : // INTERFACE BLOCK SPECIFICATIONS
1048 : // na
1049 :
1050 : // DERIVED TYPE DEFINITIONS
1051 : // na
1052 :
1053 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1054 :
1055 : Real64 HumRatSatOut; // humidity ratio at saturation at the outlet temperature [kgWater/kgDryAir]
1056 : Real64 HumRatSatIn; // humidity ratio at saturation at the inlet temperature [kgWater/kgDryAir]
1057 : Real64 WaterAddNeededMax; // moisture addition rate set by controller, limited by humidifier capacity
1058 : Real64 WaterInEnthalpy; // enthalpy of the inlet steam [J/kg]
1059 : Real64 HumRatSatApp; // the approximate humidity ratio where the line drawn between inlet and desired outlet conditions
1060 : // crosses the saturation line.
1061 : Real64 WaterDens; // density of liquid water [kg/m3]
1062 :
1063 3 : HumRatSatIn = PsyWFnTdbRhPb(state, AirInTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1064 3 : HumRatSatOut = 0.0;
1065 3 : HumRatSatApp = 0.0;
1066 3 : WaterInEnthalpy = 2676125.0; // At 100 C
1067 3 : WaterDens = RhoH2O(Constant::InitConvTemp);
1068 3 : WaterAddNeededMax = min(WaterAddNeeded, NomCap);
1069 3 : if (WaterAddNeededMax > 0.0) {
1070 : // ma*W1 + mw = ma*W2
1071 : // ma*h1 + mw*hw = ma*h2
1072 : // where ma is air mass flow rate; h1,W1 are the inlet enthalpy and humidity ratio; h2 and W2 are
1073 : // the outlet enthalpy and humidity ratio; mw is the steam mass flow rate; hw is the steam enthalpy.
1074 : // Setting mw equal to the desired water addition rate, use the above 2 equations to calculate the
1075 : // outlet conditions
1076 1 : AirOutEnthalpy = (AirInMassFlowRate * AirInEnthalpy + WaterAddNeededMax * WaterInEnthalpy) / AirInMassFlowRate;
1077 1 : AirOutHumRat = (AirInMassFlowRate * AirInHumRat + WaterAddNeededMax) / AirInMassFlowRate;
1078 1 : AirOutTemp = PsyTdbFnHW(AirOutEnthalpy, AirOutHumRat);
1079 1 : HumRatSatOut = PsyWFnTdbRhPb(state, AirOutTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1080 1 : if (AirOutHumRat <= HumRatSatOut) {
1081 : // If the outlet condition is below the saturation curve, the desired moisture addition rate can be met.
1082 1 : WaterAdd = WaterAddNeededMax;
1083 : } else {
1084 : // The desired moisture addition rate results in an outlet state above the saturation curve. We need to
1085 : // find the point where the line drawn between state 1 (inlet) and state 2 (our desired outlet) crosses
1086 : // the saturation curve. This will be the new outlet condition. Rather than iterate to obtain this point,
1087 : // we find it approximately by solving for the point where 2 lines cross: the first drawn from
1088 : // state 1 to state 2, the second from T1, W1s to T2, W2s; where T1 is the inlet temperature, W1s is
1089 : // the humidity ratio at saturation at temperature T1; and T2 is the desired outlet temperature, W2s
1090 : // is the humidity ratio at saturation at temperature T2. The 2 lines are given by the equations:
1091 : // W = W1 + ((W2-W1)/(T2-T1))*(T-T1)
1092 : // W = W1s + ((W2s-W1s)/(T2-T1))*(T-T1)
1093 : // Solving for the point where the line cross (T3,W3):
1094 : // W3 = W1 + ((W2-W1)*(W1s-W1))/(W2-W2s + W1s-W1)
1095 : // T3 = T1 + (W3-W1)*((T2-T1)/(W2-W1)) ! "T1 +" added by Shirey 8/12/04 That's correct! [WFB 9/29/2004]
1096 0 : HumRatSatApp = AirInHumRat +
1097 0 : (AirOutHumRat - AirInHumRat) * (HumRatSatIn - AirInHumRat) / (AirOutHumRat - HumRatSatOut + HumRatSatIn - AirInHumRat);
1098 0 : AirOutTemp = AirInTemp + (HumRatSatApp - AirInHumRat) * ((AirOutTemp - AirInTemp) / (AirOutHumRat - AirInHumRat));
1099 : // This point isn't quite on the saturation curve since we made a linear approximation of the curve,
1100 : // but the temperature should be very close to the correct outlet temperature. We will use this temperature
1101 : // as the outlet temperature and move to the saturation curve for the outlet humidity and enthalpy
1102 0 : AirOutHumRat = PsyWFnTdbRhPb(state, AirOutTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1103 0 : AirOutEnthalpy = PsyHFnTdbW(AirOutTemp, AirOutHumRat);
1104 0 : WaterAdd = AirInMassFlowRate * (AirOutHumRat - AirInHumRat);
1105 : }
1106 :
1107 : } else {
1108 2 : WaterAdd = 0.0;
1109 2 : AirOutEnthalpy = AirInEnthalpy;
1110 2 : AirOutTemp = AirInTemp;
1111 2 : AirOutHumRat = AirInHumRat;
1112 : }
1113 3 : if (WaterAdd > 0.0) {
1114 1 : ElecUseRate = (WaterAdd / NomCap) * NomPower + FanPower + StandbyPower;
1115 2 : } else if (availSched->getCurrentVal() > 0.0) {
1116 2 : ElecUseRate = StandbyPower;
1117 : } else {
1118 0 : ElecUseRate = 0.0;
1119 : }
1120 3 : WaterConsRate = WaterAdd / WaterDens;
1121 3 : AirOutMassFlowRate = AirInMassFlowRate;
1122 3 : }
1123 :
1124 2 : void HumidifierData::CalcGasSteamHumidifier(EnergyPlusData &state, Real64 const WaterAddNeeded // moisture addition rate set by controller [kg/s]
1125 : )
1126 : {
1127 :
1128 : // SUBROUTINE INFORMATION:
1129 : // AUTHOR Bereket Nigusse, FSEC/UCF
1130 : // DATE WRITTEN February 2015
1131 : // MODIFIED na
1132 : // RE-ENGINEERED na
1133 :
1134 : // PURPOSE OF THIS SUBROUTINE:
1135 : // Calculate the gas consumption and the outlet conditions for a gas fired steam
1136 : // humidifier, given the inlet conditions and the steam addition rate.
1137 :
1138 : // METHODOLOGY EMPLOYED:
1139 : // Uses energy and mass balance as well as pschrometric relations. Adopted
1140 : // from routine CalcElecSteamHumidifier by Fred Buhl
1141 :
1142 : // Using/Aliasing
1143 : using Curve::CurveValue;
1144 : using Psychrometrics::PsyHFnTdbW;
1145 : using Psychrometrics::PsyTdbFnHW;
1146 : using Psychrometrics::PsyWFnTdbRhPb;
1147 : using Psychrometrics::RhoH2O;
1148 :
1149 : // SUBROUTINE PARAMETER DEFINITIONS:
1150 : static constexpr std::string_view RoutineName("CalcGasSteamHumidifier");
1151 2 : Real64 constexpr TSteam(100.0); // saturated steam temperature generated by Humidifier [C]
1152 :
1153 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1154 :
1155 : Real64 HumRatSatOut; // humidity ratio at saturation at the outlet temperature [kgWater/kgDryAir]
1156 : Real64 HumRatSatIn; // humidity ratio at saturation at the inlet temperature [kgWater/kgDryAir]
1157 : Real64 WaterAddNeededMax; // moisture addition rate set by controller, limited by humidifier capacity
1158 : Real64 WaterInEnthalpy; // enthalpy of the inlet steam [J/kg]
1159 : Real64 HumRatSatApp; // the approximate humidity ratio where the line drawn between inlet and desired outlet conditions
1160 : // crosses the saturation line.
1161 : Real64 WaterDens; // density of liquid water [kg/m3]
1162 2 : Real64 ThermEffCurveOutput(0); // thermal efficiency modifier normalized curve output value [-]
1163 : Real64 PartLoadRatio; // gas fired humidifier part load ratio [-]
1164 2 : Real64 GasUseRateAtRatedEff(0); // gas use rate at rated thermal efficiency [W]
1165 : Real64 WaterSpecHeatAvg; // specific heat of water [J/kgK]
1166 : Real64 SteamSatEnthalpy; // enthalpy of saturated steam at 100C [J/kg]
1167 : Real64 WaterSatEnthalpy; // enthalpy of saturated water at 100C [J/kg]
1168 : Real64 Tref; // humidifier entering water temperature [C]
1169 :
1170 2 : HumRatSatIn = PsyWFnTdbRhPb(state, AirInTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1171 2 : HumRatSatOut = 0.0;
1172 2 : HumRatSatApp = 0.0;
1173 2 : WaterInEnthalpy = 2676125.0; // At 100 C
1174 2 : WaterDens = RhoH2O(Constant::InitConvTemp);
1175 2 : WaterAddNeededMax = min(WaterAddNeeded, NomCap);
1176 2 : if (WaterAddNeededMax > 0.0) {
1177 : // ma*W1 + mw = ma*W2
1178 : // ma*h1 + mw*hw = ma*h2
1179 : // where ma is air mass flow rate; h1,W1 are the inlet enthalpy and humidity ratio; h2 and W2 are
1180 : // the outlet enthalpy and humidity ratio; mw is the steam mass flow rate; hw is the steam enthalpy.
1181 : // Setting mw equal to the desired water addition rate, use the above 2 equations to calculate the
1182 : // outlet conditions
1183 2 : AirOutEnthalpy = (AirInMassFlowRate * AirInEnthalpy + WaterAddNeededMax * WaterInEnthalpy) / AirInMassFlowRate;
1184 2 : AirOutHumRat = (AirInMassFlowRate * AirInHumRat + WaterAddNeededMax) / AirInMassFlowRate;
1185 2 : AirOutTemp = PsyTdbFnHW(AirOutEnthalpy, AirOutHumRat);
1186 2 : HumRatSatOut = PsyWFnTdbRhPb(state, AirOutTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1187 2 : if (AirOutHumRat <= HumRatSatOut) {
1188 : // If the outlet condition is below the saturation curve, the desired moisture addition rate can be met.
1189 2 : WaterAdd = WaterAddNeededMax;
1190 : } else {
1191 : // The desired moisture addition rate results in an outlet state above the saturation curve. We need to
1192 : // find the point where the line drawn between state 1 (inlet) and state 2 (our desired outlet) crosses
1193 : // the saturation curve. This will be the new outlet condition. Rather than iterate to obtain this point,
1194 : // we find it approximately by solving for the point where 2 lines cross: the first drawn from
1195 : // state 1 to state 2, the second from T1, W1s to T2, W2s; where T1 is the inlet temperature, W1s is
1196 : // the humidity ratio at saturation at temperature T1; and T2 is the desired outlet temperature, W2s
1197 : // is the humidity ratio at saturation at temperature T2. The 2 lines are given by the equations:
1198 : // W = W1 + ((W2-W1)/(T2-T1))*(T-T1)
1199 : // W = W1s + ((W2s-W1s)/(T2-T1))*(T-T1)
1200 : // Solving for the point where the line cross (T3,W3):
1201 : // W3 = W1 + ((W2-W1)*(W1s-W1))/(W2-W2s + W1s-W1)
1202 : // T3 = T1 + (W3-W1)*((T2-T1)/(W2-W1)) ! "T1 +" added by Shirey 8/12/04 That's correct! [WFB 9/29/2004]
1203 0 : HumRatSatApp = AirInHumRat +
1204 0 : (AirOutHumRat - AirInHumRat) * (HumRatSatIn - AirInHumRat) / (AirOutHumRat - HumRatSatOut + HumRatSatIn - AirInHumRat);
1205 0 : AirOutTemp = AirInTemp + (HumRatSatApp - AirInHumRat) * ((AirOutTemp - AirInTemp) / (AirOutHumRat - AirInHumRat));
1206 : // This point isn't quite on the saturation curve since we made a linear approximation of the curve,
1207 : // but the temperature should be very close to the correct outlet temperature. We will use this temperature
1208 : // as the outlet temperature and move to the saturation curve for the outlet humidity and enthalpy
1209 0 : AirOutHumRat = PsyWFnTdbRhPb(state, AirOutTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1210 0 : AirOutEnthalpy = PsyHFnTdbW(AirOutTemp, AirOutHumRat);
1211 0 : WaterAdd = AirInMassFlowRate * (AirOutHumRat - AirInHumRat);
1212 : }
1213 :
1214 : } else {
1215 0 : WaterAdd = 0.0;
1216 0 : AirOutEnthalpy = AirInEnthalpy;
1217 0 : AirOutTemp = AirInTemp;
1218 0 : AirOutHumRat = AirInHumRat;
1219 : }
1220 2 : if (WaterAdd > 0.0) {
1221 2 : if (InletWaterTempOption == InletWaterTemp::Fixed) {
1222 2 : GasUseRateAtRatedEff = (WaterAdd / NomCap) * NomPower;
1223 0 : } else if (InletWaterTempOption == InletWaterTemp::Variable) {
1224 0 : if (SuppliedByWaterSystem) { // use water use storage tank supply temperature
1225 0 : CurMakeupWaterTemp = state.dataWaterData->WaterStorage(WaterTankID).TwaterSupply(TankSupplyID);
1226 : } else { // use water main temperature
1227 0 : CurMakeupWaterTemp = state.dataEnvrn->WaterMainsTemp;
1228 : }
1229 0 : Tref = CurMakeupWaterTemp;
1230 :
1231 0 : auto *water = Fluid::GetWater(state);
1232 0 : auto *steam = Fluid::GetSteam(state);
1233 0 : SteamSatEnthalpy = steam->getSatEnthalpy(state, TSteam, 1.0, RoutineName);
1234 0 : WaterSatEnthalpy = steam->getSatEnthalpy(state, TSteam, 0.0, RoutineName);
1235 0 : WaterSpecHeatAvg = 0.5 * (water->getSpecificHeat(state, TSteam, RoutineName) + water->getSpecificHeat(state, Tref, RoutineName));
1236 0 : GasUseRateAtRatedEff = WaterAdd * ((SteamSatEnthalpy - WaterSatEnthalpy) + WaterSpecHeatAvg * (TSteam - Tref)) / ThermalEffRated;
1237 : }
1238 2 : PartLoadRatio = GasUseRateAtRatedEff / NomPower;
1239 2 : if (EfficiencyCurvePtr > 0) { // calculate normalized thermal efficiency based on curve object type
1240 1 : ThermEffCurveOutput = CurveValue(state, EfficiencyCurvePtr, PartLoadRatio);
1241 : } else {
1242 1 : ThermEffCurveOutput = 1.0;
1243 : }
1244 2 : ThermalEff = ThermalEffRated * ThermEffCurveOutput;
1245 2 : if (ThermEffCurveOutput != 0.0) {
1246 2 : GasUseRate = GasUseRateAtRatedEff / ThermEffCurveOutput;
1247 : }
1248 2 : AuxElecUseRate = FanPower + StandbyPower;
1249 :
1250 0 : } else if (availSched->getCurrentVal() > 0.0) {
1251 0 : AuxElecUseRate = StandbyPower;
1252 : } else {
1253 0 : AuxElecUseRate = 0.0;
1254 : }
1255 2 : WaterConsRate = WaterAdd / WaterDens;
1256 2 : AirOutMassFlowRate = AirInMassFlowRate;
1257 2 : }
1258 :
1259 3 : void HumidifierData::UpdateReportWaterSystem(EnergyPlusData &state) // number of the current humidifier being simulated
1260 : {
1261 :
1262 : // SUBROUTINE INFORMATION:
1263 : // AUTHOR B. Griffith
1264 : // DATE WRITTEN Aug. 2006
1265 : // MODIFIED na
1266 : // RE-ENGINEERED na
1267 :
1268 : // PURPOSE OF THIS SUBROUTINE:
1269 : // collect water system calculations , update and report them
1270 :
1271 : // Using/Aliasing
1272 3 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
1273 :
1274 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1275 : Real64 AvailTankVdot;
1276 : Real64 TankSupplyVdot;
1277 : Real64 StarvedVdot;
1278 :
1279 : // set demand request in WaterStorage if needed.
1280 3 : if (SuppliedByWaterSystem) {
1281 0 : state.dataWaterData->WaterStorage(WaterTankID).VdotRequestDemand(WaterTankDemandARRID) = WaterConsRate;
1282 :
1283 0 : AvailTankVdot =
1284 0 : state.dataWaterData->WaterStorage(WaterTankID).VdotAvailDemand(WaterTankDemandARRID); // check what tank can currently provide
1285 :
1286 0 : StarvedVdot = 0.0;
1287 0 : TankSupplyVdot = WaterConsRate; // init
1288 0 : if ((AvailTankVdot < WaterConsRate) && (!(state.dataGlobal->BeginTimeStepFlag))) { // calculate starved flow
1289 0 : StarvedVdot = WaterConsRate - AvailTankVdot;
1290 0 : TankSupplyVdot = AvailTankVdot;
1291 : }
1292 :
1293 0 : TankSupplyVol = TankSupplyVdot * TimeStepSysSec;
1294 0 : StarvedSupplyVdot = StarvedVdot;
1295 0 : StarvedSupplyVol = StarvedVdot * TimeStepSysSec;
1296 : }
1297 3 : }
1298 :
1299 3 : void HumidifierData::UpdateHumidifier(EnergyPlusData &state) // number of the current humidifier being simulated
1300 : {
1301 :
1302 : // SUBROUTINE INFORMATION:
1303 : // AUTHOR Fred Buhl
1304 : // DATE WRITTEN September 2000
1305 : // MODIFIED na
1306 : // RE-ENGINEERED na
1307 :
1308 : // PURPOSE OF THIS SUBROUTINE:
1309 : // Moves humidifier output to the outlet nodes.
1310 :
1311 : // Set the outlet air node of the humidifier
1312 3 : state.dataLoopNodes->Node(AirOutNode).MassFlowRate = AirOutMassFlowRate;
1313 3 : state.dataLoopNodes->Node(AirOutNode).Temp = AirOutTemp;
1314 3 : state.dataLoopNodes->Node(AirOutNode).HumRat = AirOutHumRat;
1315 3 : state.dataLoopNodes->Node(AirOutNode).Enthalpy = AirOutEnthalpy;
1316 :
1317 : // Set the outlet nodes for properties that just pass through & not used
1318 3 : state.dataLoopNodes->Node(AirOutNode).Quality = state.dataLoopNodes->Node(AirInNode).Quality;
1319 3 : state.dataLoopNodes->Node(AirOutNode).Press = state.dataLoopNodes->Node(AirInNode).Press;
1320 3 : state.dataLoopNodes->Node(AirOutNode).MassFlowRateMin = state.dataLoopNodes->Node(AirInNode).MassFlowRateMin;
1321 3 : state.dataLoopNodes->Node(AirOutNode).MassFlowRateMax = state.dataLoopNodes->Node(AirInNode).MassFlowRateMax;
1322 3 : state.dataLoopNodes->Node(AirOutNode).MassFlowRateMinAvail = state.dataLoopNodes->Node(AirInNode).MassFlowRateMinAvail;
1323 3 : state.dataLoopNodes->Node(AirOutNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(AirInNode).MassFlowRateMaxAvail;
1324 :
1325 3 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1326 0 : state.dataLoopNodes->Node(AirOutNode).CO2 = state.dataLoopNodes->Node(AirInNode).CO2;
1327 : }
1328 3 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1329 0 : state.dataLoopNodes->Node(AirOutNode).GenContam = state.dataLoopNodes->Node(AirInNode).GenContam;
1330 : }
1331 3 : }
1332 :
1333 4 : void HumidifierData::ReportHumidifier(EnergyPlusData &state) // number of the current humidifier being simulated
1334 : {
1335 :
1336 : // SUBROUTINE INFORMATION:
1337 : // AUTHOR Fred Buhl
1338 : // DATE WRITTEN September 2000
1339 : // MODIFIED na
1340 : // RE-ENGINEERED na
1341 :
1342 : // PURPOSE OF THIS SUBROUTINE:
1343 : // Fill remaining report variables
1344 :
1345 : // Using/Aliasing
1346 4 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
1347 :
1348 4 : ElecUseEnergy = ElecUseRate * TimeStepSysSec;
1349 4 : WaterCons = WaterConsRate * TimeStepSysSec;
1350 4 : GasUseEnergy = GasUseRate * TimeStepSysSec;
1351 4 : AuxElecUseEnergy = AuxElecUseRate * TimeStepSysSec;
1352 4 : }
1353 :
1354 3 : int GetAirInletNodeNum(EnergyPlusData &state, std::string const &HumidifierName, bool &ErrorsFound)
1355 : {
1356 : // FUNCTION INFORMATION:
1357 : // AUTHOR Lixing Gu
1358 : // DATE WRITTEN May 2019
1359 : // MODIFIED na
1360 : // RE-ENGINEERED na
1361 :
1362 : // PURPOSE OF THIS FUNCTION:
1363 : // This function looks up the given humidifier and returns the air inlet node number.
1364 : // If incorrect humidifier name is given, ErrorsFound is returned as true and node number as zero.
1365 :
1366 : // Return value
1367 : int NodeNum; // node number returned
1368 :
1369 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1370 : int WhichHumidifier;
1371 :
1372 : // Obtains and Allocates heat exchanger related parameters from input file
1373 3 : if (state.dataHumidifiers->GetInputFlag) {
1374 3 : GetHumidifierInput(state);
1375 3 : state.dataHumidifiers->GetInputFlag = false;
1376 : }
1377 :
1378 3 : WhichHumidifier = Util::FindItemInList(HumidifierName, state.dataHumidifiers->Humidifier);
1379 3 : if (WhichHumidifier != 0) {
1380 3 : NodeNum = state.dataHumidifiers->Humidifier(WhichHumidifier).AirInNode;
1381 : } else {
1382 0 : ShowSevereError(state, format("GetAirInletNodeNum: Could not find Humidifier = \"{}\"", HumidifierName));
1383 0 : ErrorsFound = true;
1384 0 : NodeNum = 0;
1385 : }
1386 :
1387 3 : return NodeNum;
1388 : }
1389 :
1390 3 : int GetAirOutletNodeNum(EnergyPlusData &state, std::string const &HumidifierName, bool &ErrorsFound)
1391 : {
1392 : // PURPOSE OF THIS FUNCTION:
1393 : // This function looks up the given humidifier and returns the air outlet node number.
1394 : // If incorrect humidifier name is given, ErrorsFound is returned as true and node number as zero.
1395 :
1396 3 : if (state.dataHumidifiers->GetInputFlag) {
1397 0 : GetHumidifierInput(state);
1398 0 : state.dataHumidifiers->GetInputFlag = false;
1399 : }
1400 :
1401 3 : int WhichHumidifier = Util::FindItemInList(HumidifierName, state.dataHumidifiers->Humidifier);
1402 3 : if (WhichHumidifier != 0) {
1403 3 : return state.dataHumidifiers->Humidifier(WhichHumidifier).AirOutNode;
1404 : } else {
1405 0 : ShowSevereError(state, format("GetAirInletNodeNum: Could not find Humidifier = \"{}\"", HumidifierName));
1406 0 : ErrorsFound = true;
1407 0 : return 0;
1408 : }
1409 : }
1410 :
1411 : } // namespace Humidifiers
1412 :
1413 : } // namespace EnergyPlus
|