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