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