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) NomCapVolDes = 0.0; // No humidity demand
816 :
817 3 : if (IsAutoSize) {
818 1 : NomCapVol = NomCapVolDes;
819 3 : BaseSizer::reportSizerOutput(
820 2 : state, format(HumidifierType[static_cast<int>(HumType)]), Name, "Design Size Nominal Capacity Volume [m3/s]", NomCapVolDes);
821 : } else {
822 2 : if (NomCapVol > 0.0) {
823 2 : NomCapVolUser = NomCapVol;
824 6 : BaseSizer::reportSizerOutput(state,
825 4 : format(HumidifierType[static_cast<int>(HumType)]),
826 : Name,
827 : "Design Size Nominal Capacity Volume [m3/s]",
828 : NomCapVolDes,
829 : "User-Specified Nominal Capacity Volume [m3/s]",
830 : NomCapVolUser);
831 2 : if (state.dataGlobal->DisplayExtraWarnings) {
832 0 : if ((std::abs(NomCapVolDes - NomCapVolUser) / NomCapVolUser) > state.dataSize->AutoVsHardSizingThreshold) {
833 0 : ShowMessage(state,
834 0 : format("SizeHumidifier: Potential issue with equipment sizing for {} = \"{}\".",
835 0 : format(HumidifierType[static_cast<int>(HumType)]),
836 0 : Name));
837 0 : ShowContinueError(state, format("User-Specified Nominal Capacity Volume of {:.2R} [Wm3/s]", NomCapVolUser));
838 0 : ShowContinueError(state, format("differs from Design Size Nominal Capacity Volume of {:.2R} [m3/s]", NomCapVolDes));
839 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
840 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
841 : }
842 : }
843 : }
844 : }
845 : }
846 :
847 4 : NomCap = RhoH2O(Constant::InitConvTemp) * NomCapVol;
848 :
849 4 : auto *water = Fluid::GetWater(state);
850 4 : auto *steam = Fluid::GetSteam(state);
851 4 : SteamSatEnthalpy = steam->getSatEnthalpy(state, TSteam, 1.0, CalledFrom);
852 4 : WaterSatEnthalpy = steam->getSatEnthalpy(state, TSteam, 0.0, CalledFrom);
853 4 : WaterSpecHeatAvg = 0.5 * (water->getSpecificHeat(state, TSteam, CalledFrom) + water->getSpecificHeat(state, Tref, CalledFrom));
854 4 : NominalPower = NomCap * ((SteamSatEnthalpy - WaterSatEnthalpy) + WaterSpecHeatAvg * (TSteam - Tref));
855 :
856 4 : if (NomPower == AutoSize) {
857 2 : IsAutoSize = true;
858 : }
859 :
860 4 : if (HumType == HumidType::Gas) {
861 :
862 3 : if (!IsAutoSize) {
863 : // override user specified rated thermal efficiency
864 1 : if (NomPower >= NominalPower) {
865 0 : ThermalEffRated = NominalPower / NomPower;
866 : } else {
867 2 : ShowMessage(state,
868 2 : format("{}: capacity and thermal efficiency mismatch for {} =\"{}\".",
869 : CalledFrom,
870 2 : format(HumidifierType[static_cast<int>(HumType)]),
871 1 : Name));
872 1 : ShowContinueError(state, format("User-Specified Rated Gas Use Rate of {:.2R} [W]", NomPower));
873 1 : ShowContinueError(state, format("User-Specified or Autosized Rated Capacity of {:.2R} [m3/s]", NomCapVol));
874 2 : ShowContinueError(state,
875 2 : format("Rated Gas Use Rate at the Rated Capacity of {:.2R} [m3/s] must be greater than the ideal, i.e., "
876 : "100% thermal efficiency gas use rate of {:.2R} [W]",
877 1 : NomCapVol,
878 : NomPowerDes));
879 2 : ShowContinueError(state,
880 : "Resize the Rated Gas Use Rate by dividing the ideal gas use rate with expected thermal efficiency. ");
881 : // Changing this from a hard-stop condition to just a limiting condition of eta=1.0
882 : // ErrorsFound = true;
883 1 : ThermalEffRated = 1.0;
884 : }
885 : } else {
886 2 : if (ThermalEffRated > 0.0) {
887 2 : NominalPower = NominalPower / ThermalEffRated;
888 : }
889 : }
890 :
891 : // gas fired steam humidifier's nominal gas use rate is always autosized
892 3 : IsAutoSize = true;
893 : }
894 :
895 4 : NomPowerDes = NominalPower;
896 4 : if (IsAutoSize) {
897 3 : NomPower = NomPowerDes;
898 9 : BaseSizer::reportSizerOutput(
899 6 : state, format(HumidifierType[static_cast<int>(HumType)]), Name, "Design Size Rated Power [W]", NomPowerDes);
900 : } else {
901 1 : if (NomPower >= 0.0 && NomCap > 0.0) {
902 1 : NomPowerUser = NomPower;
903 3 : BaseSizer::reportSizerOutput(state,
904 2 : format(HumidifierType[static_cast<int>(HumType)]),
905 : Name,
906 : "Design Size Rated Power [W]",
907 : NomPowerDes,
908 : "User-Specified Rated Power [W]",
909 : NomPowerUser);
910 1 : if (state.dataGlobal->DisplayExtraWarnings) {
911 0 : if ((std::abs(NomPowerDes - NomPowerUser) / NomPowerUser) > state.dataSize->AutoVsHardSizingThreshold) {
912 0 : ShowMessage(state,
913 0 : format("SizeHumidifier: Potential issue with equipment sizing for {} =\"{}\".",
914 0 : format(HumidifierType[static_cast<int>(HumType)]),
915 0 : Name));
916 0 : ShowContinueError(state, format("User-Specified Rated Power of {:.2R} [W]", NomPowerUser));
917 0 : ShowContinueError(state, format("differs from Design Size Rated Power of {:.2R} [W]", NomPowerDes));
918 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
919 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
920 : }
921 : }
922 1 : if (NomPower < NominalPower) {
923 0 : ShowWarningError(state,
924 0 : format(HumidifierType[static_cast<int>(HumType)]) +
925 0 : ": specified Rated Power is less than nominal Rated Power for " + ModuleObjectType +
926 0 : " steam humidifier = " + Name + ". ");
927 0 : ShowContinueError(state, format(" specified Rated Power = {:.2R}", NomPower));
928 0 : ShowContinueError(state, format(" while expecting a minimum Rated Power = {:.2R}", NominalPower));
929 : }
930 : } else {
931 0 : ShowWarningError(state,
932 0 : format(HumidifierType[static_cast<int>(HumType)]) + ": specified nominal capacity is zero for " +
933 0 : ModuleObjectType + " steam humidifier = " + Name + ". ");
934 0 : ShowContinueError(state, " For zero nominal capacity humidifier the rated power is zero.");
935 : }
936 : }
937 4 : }
938 :
939 4 : if (ErrorsFound) {
940 0 : ShowFatalError(state,
941 0 : format("{}: Mismatch was found in the Rated Gas Use Rate and Thermal Efficiency for gas fired steam humidifier = {}. ",
942 : CalledFrom,
943 0 : Name));
944 : }
945 4 : }
946 :
947 3 : void HumidifierData::ControlHumidifier(EnergyPlusData &state,
948 : Real64 &WaterAddNeeded // moisture addition rate needed to meet minimum humidity ratio setpoint [kg/s]
949 : )
950 : {
951 :
952 : // SUBROUTINE INFORMATION:
953 : // AUTHOR Fred Buhl
954 : // DATE WRITTEN September 2000
955 : // MODIFIED February 2015, B. Nigusse, FSEC, - transitioned the code to OO approach
956 : // RE-ENGINEERED na
957 :
958 : // PURPOSE OF THIS SUBROUTINE:
959 : // This subroutine sets the output required from the humidifier
960 :
961 : // METHODOLOGY EMPLOYED:
962 : // Uses a minimum humidity setpoint and water mass balance to calculate moisture addition needed
963 :
964 : // REFERENCES:
965 : // na
966 :
967 : // Using/Aliasing
968 : using Psychrometrics::PsyWFnTdbRhPb;
969 :
970 : // Locals
971 : // SUBROUTINE ARGUMENT DEFINITIONS:
972 : static constexpr std::string_view RoutineName("ControlHumidifier");
973 :
974 : // SUBROUTINE PARAMETER DEFINITIONS:
975 : // na
976 :
977 : // INTERFACE BLOCK SPECIFICATIONS
978 : // na
979 :
980 : // DERIVED TYPE DEFINITIONS
981 : // na
982 :
983 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
984 : bool UnitOn; // unit on flag
985 : Real64 HumRatSatIn; // humidity ratio at saturation at the inlet temperature [kgWater/kgDryAir]
986 :
987 3 : UnitOn = true;
988 3 : if (HumRatSet <= 0.0) UnitOn = false;
989 3 : if (AirInMassFlowRate <= SmallMassFlow) UnitOn = false;
990 3 : if (availSched->getCurrentVal() <= 0.0) UnitOn = false;
991 3 : if (AirInHumRat >= HumRatSet) UnitOn = false;
992 3 : HumRatSatIn = PsyWFnTdbRhPb(state, AirInTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
993 3 : if (AirInHumRat >= HumRatSatIn) UnitOn = false;
994 3 : if (UnitOn) {
995 : // AirMassFlowRate*AirInHumRat + WaterAddNeeded = AirMassFlowRate*HumRatSet
996 1 : WaterAddNeeded = AirInMassFlowRate * (HumRatSet - AirInHumRat);
997 : } else {
998 2 : WaterAddNeeded = 0.0;
999 : }
1000 3 : }
1001 :
1002 3 : void HumidifierData::CalcElecSteamHumidifier(EnergyPlusData &state, Real64 const WaterAddNeeded // moisture addition rate set by controller [kg/s]
1003 : )
1004 : {
1005 :
1006 : // SUBROUTINE INFORMATION:
1007 : // AUTHOR Fred Buhl
1008 : // DATE WRITTEN September 2000
1009 : // MODIFIED February 2015, B. Nigusse, FSEC, - transitioned the code to OO approach
1010 : // RE-ENGINEERED na
1011 :
1012 : // PURPOSE OF THIS SUBROUTINE:
1013 : // Calculate the electricity consumption and the outlet conditions for an electric steam
1014 : // humidifier, given the inlet conditions and the steam addition rate.
1015 :
1016 : // METHODOLOGY EMPLOYED:
1017 : // Uses energy and mass balance as well as pschrometric relations.
1018 :
1019 : // REFERENCES:
1020 : // ASHRAE HVAC 2 Toolkit, page 4-112
1021 : // 1997 ASHRAE Handbook Fundamentals, page 6.18
1022 :
1023 : // Using/Aliasing
1024 : using Psychrometrics::PsyHFnTdbW;
1025 : using Psychrometrics::PsyTdbFnHW;
1026 : using Psychrometrics::PsyWFnTdbRhPb;
1027 : using Psychrometrics::RhoH2O;
1028 :
1029 : // Locals
1030 : // SUBROUTINE ARGUMENT DEFINITIONS:
1031 :
1032 : // SUBROUTINE PARAMETER DEFINITIONS:
1033 : static constexpr std::string_view RoutineName("CalcElecSteamHumidifier");
1034 :
1035 : // INTERFACE BLOCK SPECIFICATIONS
1036 : // na
1037 :
1038 : // DERIVED TYPE DEFINITIONS
1039 : // na
1040 :
1041 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1042 :
1043 : Real64 HumRatSatOut; // humidity ratio at saturation at the outlet temperature [kgWater/kgDryAir]
1044 : Real64 HumRatSatIn; // humidity ratio at saturation at the inlet temperature [kgWater/kgDryAir]
1045 : Real64 WaterAddNeededMax; // moisture addition rate set by controller, limited by humidifier capacity
1046 : Real64 WaterInEnthalpy; // enthalpy of the inlet steam [J/kg]
1047 : Real64 HumRatSatApp; // the approximate humidity ratio where the line drawn between inlet and desired outlet conditions
1048 : // crosses the saturation line.
1049 : Real64 WaterDens; // density of liquid water [kg/m3]
1050 :
1051 3 : HumRatSatIn = PsyWFnTdbRhPb(state, AirInTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1052 3 : HumRatSatOut = 0.0;
1053 3 : HumRatSatApp = 0.0;
1054 3 : WaterInEnthalpy = 2676125.0; // At 100 C
1055 3 : WaterDens = RhoH2O(Constant::InitConvTemp);
1056 3 : WaterAddNeededMax = min(WaterAddNeeded, NomCap);
1057 3 : if (WaterAddNeededMax > 0.0) {
1058 : // ma*W1 + mw = ma*W2
1059 : // ma*h1 + mw*hw = ma*h2
1060 : // where ma is air mass flow rate; h1,W1 are the inlet enthalpy and humidity ratio; h2 and W2 are
1061 : // the outlet enthalpy and humidity ratio; mw is the steam mass flow rate; hw is the steam enthalpy.
1062 : // Setting mw equal to the desired water addition rate, use the above 2 equations to calculate the
1063 : // outlet conditions
1064 1 : AirOutEnthalpy = (AirInMassFlowRate * AirInEnthalpy + WaterAddNeededMax * WaterInEnthalpy) / AirInMassFlowRate;
1065 1 : AirOutHumRat = (AirInMassFlowRate * AirInHumRat + WaterAddNeededMax) / AirInMassFlowRate;
1066 1 : AirOutTemp = PsyTdbFnHW(AirOutEnthalpy, AirOutHumRat);
1067 1 : HumRatSatOut = PsyWFnTdbRhPb(state, AirOutTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1068 1 : if (AirOutHumRat <= HumRatSatOut) {
1069 : // If the outlet condition is below the saturation curve, the desired moisture addition rate can be met.
1070 1 : WaterAdd = WaterAddNeededMax;
1071 : } else {
1072 : // The desired moisture addition rate results in an outlet state above the saturation curve. We need to
1073 : // find the point where the line drawn between state 1 (inlet) and state 2 (our desired outlet) crosses
1074 : // the saturation curve. This will be the new outlet condition. Rather than iterate to obtain this point,
1075 : // we find it approximately by solving for the point where 2 lines cross: the first drawn from
1076 : // state 1 to state 2, the second from T1, W1s to T2, W2s; where T1 is the inlet temperature, W1s is
1077 : // the humidity ratio at saturation at temperature T1; and T2 is the desired outlet temperature, W2s
1078 : // is the humidity ratio at saturation at temperature T2. The 2 lines are given by the equations:
1079 : // W = W1 + ((W2-W1)/(T2-T1))*(T-T1)
1080 : // W = W1s + ((W2s-W1s)/(T2-T1))*(T-T1)
1081 : // Solving for the point where the line cross (T3,W3):
1082 : // W3 = W1 + ((W2-W1)*(W1s-W1))/(W2-W2s + W1s-W1)
1083 : // T3 = T1 + (W3-W1)*((T2-T1)/(W2-W1)) ! "T1 +" added by Shirey 8/12/04 That's correct! [WFB 9/29/2004]
1084 0 : HumRatSatApp = AirInHumRat +
1085 0 : (AirOutHumRat - AirInHumRat) * (HumRatSatIn - AirInHumRat) / (AirOutHumRat - HumRatSatOut + HumRatSatIn - AirInHumRat);
1086 0 : AirOutTemp = AirInTemp + (HumRatSatApp - AirInHumRat) * ((AirOutTemp - AirInTemp) / (AirOutHumRat - AirInHumRat));
1087 : // This point isn't quite on the saturation curve since we made a linear approximation of the curve,
1088 : // but the temperature should be very close to the correct outlet temperature. We will use this temperature
1089 : // as the outlet temperature and move to the saturation curve for the outlet humidity and enthalpy
1090 0 : AirOutHumRat = PsyWFnTdbRhPb(state, AirOutTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1091 0 : AirOutEnthalpy = PsyHFnTdbW(AirOutTemp, AirOutHumRat);
1092 0 : WaterAdd = AirInMassFlowRate * (AirOutHumRat - AirInHumRat);
1093 : }
1094 :
1095 : } else {
1096 2 : WaterAdd = 0.0;
1097 2 : AirOutEnthalpy = AirInEnthalpy;
1098 2 : AirOutTemp = AirInTemp;
1099 2 : AirOutHumRat = AirInHumRat;
1100 : }
1101 3 : if (WaterAdd > 0.0) {
1102 1 : ElecUseRate = (WaterAdd / NomCap) * NomPower + FanPower + StandbyPower;
1103 2 : } else if (availSched->getCurrentVal() > 0.0) {
1104 2 : ElecUseRate = StandbyPower;
1105 : } else {
1106 0 : ElecUseRate = 0.0;
1107 : }
1108 3 : WaterConsRate = WaterAdd / WaterDens;
1109 3 : AirOutMassFlowRate = AirInMassFlowRate;
1110 3 : }
1111 :
1112 2 : void HumidifierData::CalcGasSteamHumidifier(EnergyPlusData &state, Real64 const WaterAddNeeded // moisture addition rate set by controller [kg/s]
1113 : )
1114 : {
1115 :
1116 : // SUBROUTINE INFORMATION:
1117 : // AUTHOR Bereket Nigusse, FSEC/UCF
1118 : // DATE WRITTEN February 2015
1119 : // MODIFIED na
1120 : // RE-ENGINEERED na
1121 :
1122 : // PURPOSE OF THIS SUBROUTINE:
1123 : // Calculate the gas consumption and the outlet conditions for a gas fired steam
1124 : // humidifier, given the inlet conditions and the steam addition rate.
1125 :
1126 : // METHODOLOGY EMPLOYED:
1127 : // Uses energy and mass balance as well as pschrometric relations. Adopted
1128 : // from routine CalcElecSteamHumidifier by Fred Buhl
1129 :
1130 : // Using/Aliasing
1131 : using Curve::CurveValue;
1132 : using Psychrometrics::PsyHFnTdbW;
1133 : using Psychrometrics::PsyTdbFnHW;
1134 : using Psychrometrics::PsyWFnTdbRhPb;
1135 : using Psychrometrics::RhoH2O;
1136 :
1137 : // SUBROUTINE PARAMETER DEFINITIONS:
1138 : static constexpr std::string_view RoutineName("CalcGasSteamHumidifier");
1139 2 : Real64 constexpr TSteam(100.0); // saturated steam temperature generated by Humidifier [C]
1140 :
1141 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1142 :
1143 : Real64 HumRatSatOut; // humidity ratio at saturation at the outlet temperature [kgWater/kgDryAir]
1144 : Real64 HumRatSatIn; // humidity ratio at saturation at the inlet temperature [kgWater/kgDryAir]
1145 : Real64 WaterAddNeededMax; // moisture addition rate set by controller, limited by humidifier capacity
1146 : Real64 WaterInEnthalpy; // enthalpy of the inlet steam [J/kg]
1147 : Real64 HumRatSatApp; // the approximate humidity ratio where the line drawn between inlet and desired outlet conditions
1148 : // crosses the saturation line.
1149 : Real64 WaterDens; // density of liquid water [kg/m3]
1150 2 : Real64 ThermEffCurveOutput(0); // thermal efficiency modifier normalized curve output value [-]
1151 : Real64 PartLoadRatio; // gas fired humidifier part load ratio [-]
1152 2 : Real64 GasUseRateAtRatedEff(0); // gas use rate at rated thermal efficiency [W]
1153 : Real64 WaterSpecHeatAvg; // specific heat of water [J/kgK]
1154 : Real64 SteamSatEnthalpy; // enthalpy of saturated steam at 100C [J/kg]
1155 : Real64 WaterSatEnthalpy; // enthalpy of saturated water at 100C [J/kg]
1156 : Real64 Tref; // humidifier entering water temperature [C]
1157 :
1158 2 : HumRatSatIn = PsyWFnTdbRhPb(state, AirInTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1159 2 : HumRatSatOut = 0.0;
1160 2 : HumRatSatApp = 0.0;
1161 2 : WaterInEnthalpy = 2676125.0; // At 100 C
1162 2 : WaterDens = RhoH2O(Constant::InitConvTemp);
1163 2 : WaterAddNeededMax = min(WaterAddNeeded, NomCap);
1164 2 : if (WaterAddNeededMax > 0.0) {
1165 : // ma*W1 + mw = ma*W2
1166 : // ma*h1 + mw*hw = ma*h2
1167 : // where ma is air mass flow rate; h1,W1 are the inlet enthalpy and humidity ratio; h2 and W2 are
1168 : // the outlet enthalpy and humidity ratio; mw is the steam mass flow rate; hw is the steam enthalpy.
1169 : // Setting mw equal to the desired water addition rate, use the above 2 equations to calculate the
1170 : // outlet conditions
1171 2 : AirOutEnthalpy = (AirInMassFlowRate * AirInEnthalpy + WaterAddNeededMax * WaterInEnthalpy) / AirInMassFlowRate;
1172 2 : AirOutHumRat = (AirInMassFlowRate * AirInHumRat + WaterAddNeededMax) / AirInMassFlowRate;
1173 2 : AirOutTemp = PsyTdbFnHW(AirOutEnthalpy, AirOutHumRat);
1174 2 : HumRatSatOut = PsyWFnTdbRhPb(state, AirOutTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1175 2 : if (AirOutHumRat <= HumRatSatOut) {
1176 : // If the outlet condition is below the saturation curve, the desired moisture addition rate can be met.
1177 2 : WaterAdd = WaterAddNeededMax;
1178 : } else {
1179 : // The desired moisture addition rate results in an outlet state above the saturation curve. We need to
1180 : // find the point where the line drawn between state 1 (inlet) and state 2 (our desired outlet) crosses
1181 : // the saturation curve. This will be the new outlet condition. Rather than iterate to obtain this point,
1182 : // we find it approximately by solving for the point where 2 lines cross: the first drawn from
1183 : // state 1 to state 2, the second from T1, W1s to T2, W2s; where T1 is the inlet temperature, W1s is
1184 : // the humidity ratio at saturation at temperature T1; and T2 is the desired outlet temperature, W2s
1185 : // is the humidity ratio at saturation at temperature T2. The 2 lines are given by the equations:
1186 : // W = W1 + ((W2-W1)/(T2-T1))*(T-T1)
1187 : // W = W1s + ((W2s-W1s)/(T2-T1))*(T-T1)
1188 : // Solving for the point where the line cross (T3,W3):
1189 : // W3 = W1 + ((W2-W1)*(W1s-W1))/(W2-W2s + W1s-W1)
1190 : // T3 = T1 + (W3-W1)*((T2-T1)/(W2-W1)) ! "T1 +" added by Shirey 8/12/04 That's correct! [WFB 9/29/2004]
1191 0 : HumRatSatApp = AirInHumRat +
1192 0 : (AirOutHumRat - AirInHumRat) * (HumRatSatIn - AirInHumRat) / (AirOutHumRat - HumRatSatOut + HumRatSatIn - AirInHumRat);
1193 0 : AirOutTemp = AirInTemp + (HumRatSatApp - AirInHumRat) * ((AirOutTemp - AirInTemp) / (AirOutHumRat - AirInHumRat));
1194 : // This point isn't quite on the saturation curve since we made a linear approximation of the curve,
1195 : // but the temperature should be very close to the correct outlet temperature. We will use this temperature
1196 : // as the outlet temperature and move to the saturation curve for the outlet humidity and enthalpy
1197 0 : AirOutHumRat = PsyWFnTdbRhPb(state, AirOutTemp, 1.0, state.dataEnvrn->OutBaroPress, RoutineName);
1198 0 : AirOutEnthalpy = PsyHFnTdbW(AirOutTemp, AirOutHumRat);
1199 0 : WaterAdd = AirInMassFlowRate * (AirOutHumRat - AirInHumRat);
1200 : }
1201 :
1202 : } else {
1203 0 : WaterAdd = 0.0;
1204 0 : AirOutEnthalpy = AirInEnthalpy;
1205 0 : AirOutTemp = AirInTemp;
1206 0 : AirOutHumRat = AirInHumRat;
1207 : }
1208 2 : if (WaterAdd > 0.0) {
1209 2 : if (InletWaterTempOption == InletWaterTemp::Fixed) {
1210 2 : GasUseRateAtRatedEff = (WaterAdd / NomCap) * NomPower;
1211 0 : } else if (InletWaterTempOption == InletWaterTemp::Variable) {
1212 0 : if (SuppliedByWaterSystem) { // use water use storage tank supply temperature
1213 0 : CurMakeupWaterTemp = state.dataWaterData->WaterStorage(WaterTankID).TwaterSupply(TankSupplyID);
1214 : } else { // use water main temperature
1215 0 : CurMakeupWaterTemp = state.dataEnvrn->WaterMainsTemp;
1216 : }
1217 0 : Tref = CurMakeupWaterTemp;
1218 :
1219 0 : auto *water = Fluid::GetWater(state);
1220 0 : auto *steam = Fluid::GetSteam(state);
1221 0 : SteamSatEnthalpy = steam->getSatEnthalpy(state, TSteam, 1.0, RoutineName);
1222 0 : WaterSatEnthalpy = steam->getSatEnthalpy(state, TSteam, 0.0, RoutineName);
1223 0 : WaterSpecHeatAvg = 0.5 * (water->getSpecificHeat(state, TSteam, RoutineName) + water->getSpecificHeat(state, Tref, RoutineName));
1224 0 : GasUseRateAtRatedEff = WaterAdd * ((SteamSatEnthalpy - WaterSatEnthalpy) + WaterSpecHeatAvg * (TSteam - Tref)) / ThermalEffRated;
1225 : }
1226 2 : PartLoadRatio = GasUseRateAtRatedEff / NomPower;
1227 2 : if (EfficiencyCurvePtr > 0) { // calculate normalized thermal efficiency based on curve object type
1228 1 : ThermEffCurveOutput = CurveValue(state, EfficiencyCurvePtr, PartLoadRatio);
1229 : } else {
1230 1 : ThermEffCurveOutput = 1.0;
1231 : }
1232 2 : ThermalEff = ThermalEffRated * ThermEffCurveOutput;
1233 2 : if (ThermEffCurveOutput != 0.0) {
1234 2 : GasUseRate = GasUseRateAtRatedEff / ThermEffCurveOutput;
1235 : }
1236 2 : AuxElecUseRate = FanPower + StandbyPower;
1237 :
1238 0 : } else if (availSched->getCurrentVal() > 0.0) {
1239 0 : AuxElecUseRate = StandbyPower;
1240 : } else {
1241 0 : AuxElecUseRate = 0.0;
1242 : }
1243 2 : WaterConsRate = WaterAdd / WaterDens;
1244 2 : AirOutMassFlowRate = AirInMassFlowRate;
1245 2 : }
1246 :
1247 3 : void HumidifierData::UpdateReportWaterSystem(EnergyPlusData &state) // number of the current humidifier being simulated
1248 : {
1249 :
1250 : // SUBROUTINE INFORMATION:
1251 : // AUTHOR B. Griffith
1252 : // DATE WRITTEN Aug. 2006
1253 : // MODIFIED na
1254 : // RE-ENGINEERED na
1255 :
1256 : // PURPOSE OF THIS SUBROUTINE:
1257 : // collect water system calculations , update and report them
1258 :
1259 : // Using/Aliasing
1260 3 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
1261 :
1262 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1263 : Real64 AvailTankVdot;
1264 : Real64 TankSupplyVdot;
1265 : Real64 StarvedVdot;
1266 :
1267 : // set demand request in WaterStorage if needed.
1268 3 : if (SuppliedByWaterSystem) {
1269 0 : state.dataWaterData->WaterStorage(WaterTankID).VdotRequestDemand(WaterTankDemandARRID) = WaterConsRate;
1270 :
1271 0 : AvailTankVdot =
1272 0 : state.dataWaterData->WaterStorage(WaterTankID).VdotAvailDemand(WaterTankDemandARRID); // check what tank can currently provide
1273 :
1274 0 : StarvedVdot = 0.0;
1275 0 : TankSupplyVdot = WaterConsRate; // init
1276 0 : if ((AvailTankVdot < WaterConsRate) && (!(state.dataGlobal->BeginTimeStepFlag))) { // calculate starved flow
1277 0 : StarvedVdot = WaterConsRate - AvailTankVdot;
1278 0 : TankSupplyVdot = AvailTankVdot;
1279 : }
1280 :
1281 0 : TankSupplyVol = TankSupplyVdot * TimeStepSysSec;
1282 0 : StarvedSupplyVdot = StarvedVdot;
1283 0 : StarvedSupplyVol = StarvedVdot * TimeStepSysSec;
1284 : }
1285 3 : }
1286 :
1287 3 : void HumidifierData::UpdateHumidifier(EnergyPlusData &state) // number of the current humidifier being simulated
1288 : {
1289 :
1290 : // SUBROUTINE INFORMATION:
1291 : // AUTHOR Fred Buhl
1292 : // DATE WRITTEN September 2000
1293 : // MODIFIED na
1294 : // RE-ENGINEERED na
1295 :
1296 : // PURPOSE OF THIS SUBROUTINE:
1297 : // Moves humidifier output to the outlet nodes.
1298 :
1299 : // Set the outlet air node of the humidifier
1300 3 : state.dataLoopNodes->Node(AirOutNode).MassFlowRate = AirOutMassFlowRate;
1301 3 : state.dataLoopNodes->Node(AirOutNode).Temp = AirOutTemp;
1302 3 : state.dataLoopNodes->Node(AirOutNode).HumRat = AirOutHumRat;
1303 3 : state.dataLoopNodes->Node(AirOutNode).Enthalpy = AirOutEnthalpy;
1304 :
1305 : // Set the outlet nodes for properties that just pass through & not used
1306 3 : state.dataLoopNodes->Node(AirOutNode).Quality = state.dataLoopNodes->Node(AirInNode).Quality;
1307 3 : state.dataLoopNodes->Node(AirOutNode).Press = state.dataLoopNodes->Node(AirInNode).Press;
1308 3 : state.dataLoopNodes->Node(AirOutNode).MassFlowRateMin = state.dataLoopNodes->Node(AirInNode).MassFlowRateMin;
1309 3 : state.dataLoopNodes->Node(AirOutNode).MassFlowRateMax = state.dataLoopNodes->Node(AirInNode).MassFlowRateMax;
1310 3 : state.dataLoopNodes->Node(AirOutNode).MassFlowRateMinAvail = state.dataLoopNodes->Node(AirInNode).MassFlowRateMinAvail;
1311 3 : state.dataLoopNodes->Node(AirOutNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(AirInNode).MassFlowRateMaxAvail;
1312 :
1313 3 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1314 0 : state.dataLoopNodes->Node(AirOutNode).CO2 = state.dataLoopNodes->Node(AirInNode).CO2;
1315 : }
1316 3 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1317 0 : state.dataLoopNodes->Node(AirOutNode).GenContam = state.dataLoopNodes->Node(AirInNode).GenContam;
1318 : }
1319 3 : }
1320 :
1321 4 : void HumidifierData::ReportHumidifier(EnergyPlusData &state) // number of the current humidifier being simulated
1322 : {
1323 :
1324 : // SUBROUTINE INFORMATION:
1325 : // AUTHOR Fred Buhl
1326 : // DATE WRITTEN September 2000
1327 : // MODIFIED na
1328 : // RE-ENGINEERED na
1329 :
1330 : // PURPOSE OF THIS SUBROUTINE:
1331 : // Fill remaining report variables
1332 :
1333 : // Using/Aliasing
1334 4 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
1335 :
1336 4 : ElecUseEnergy = ElecUseRate * TimeStepSysSec;
1337 4 : WaterCons = WaterConsRate * TimeStepSysSec;
1338 4 : GasUseEnergy = GasUseRate * TimeStepSysSec;
1339 4 : AuxElecUseEnergy = AuxElecUseRate * TimeStepSysSec;
1340 4 : }
1341 :
1342 3 : int GetAirInletNodeNum(EnergyPlusData &state, std::string const &HumidifierName, bool &ErrorsFound)
1343 : {
1344 : // FUNCTION INFORMATION:
1345 : // AUTHOR Lixing Gu
1346 : // DATE WRITTEN May 2019
1347 : // MODIFIED na
1348 : // RE-ENGINEERED na
1349 :
1350 : // PURPOSE OF THIS FUNCTION:
1351 : // This function looks up the given humidifier and returns the air inlet node number.
1352 : // If incorrect humidifier name is given, ErrorsFound is returned as true and node number as zero.
1353 :
1354 : // Return value
1355 : int NodeNum; // node number returned
1356 :
1357 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1358 : int WhichHumidifier;
1359 :
1360 : // Obtains and Allocates heat exchanger related parameters from input file
1361 3 : if (state.dataHumidifiers->GetInputFlag) {
1362 3 : GetHumidifierInput(state);
1363 3 : state.dataHumidifiers->GetInputFlag = false;
1364 : }
1365 :
1366 3 : WhichHumidifier = Util::FindItemInList(HumidifierName, state.dataHumidifiers->Humidifier);
1367 3 : if (WhichHumidifier != 0) {
1368 3 : NodeNum = state.dataHumidifiers->Humidifier(WhichHumidifier).AirInNode;
1369 : } else {
1370 0 : ShowSevereError(state, format("GetAirInletNodeNum: Could not find Humidifier = \"{}\"", HumidifierName));
1371 0 : ErrorsFound = true;
1372 0 : NodeNum = 0;
1373 : }
1374 :
1375 3 : return NodeNum;
1376 : }
1377 :
1378 3 : int GetAirOutletNodeNum(EnergyPlusData &state, std::string const &HumidifierName, bool &ErrorsFound)
1379 : {
1380 : // PURPOSE OF THIS FUNCTION:
1381 : // This function looks up the given humidifier and returns the air outlet node number.
1382 : // If incorrect humidifier name is given, ErrorsFound is returned as true and node number as zero.
1383 :
1384 3 : if (state.dataHumidifiers->GetInputFlag) {
1385 0 : GetHumidifierInput(state);
1386 0 : state.dataHumidifiers->GetInputFlag = false;
1387 : }
1388 :
1389 3 : int WhichHumidifier = Util::FindItemInList(HumidifierName, state.dataHumidifiers->Humidifier);
1390 3 : if (WhichHumidifier != 0) {
1391 3 : return state.dataHumidifiers->Humidifier(WhichHumidifier).AirOutNode;
1392 : } else {
1393 0 : ShowSevereError(state, format("GetAirInletNodeNum: Could not find Humidifier = \"{}\"", HumidifierName));
1394 0 : ErrorsFound = true;
1395 0 : return 0;
1396 : }
1397 : }
1398 :
1399 : } // namespace Humidifiers
1400 :
1401 : } // namespace EnergyPlus
|