LCOV - code coverage report
Current view: top level - EnergyPlus - Humidifiers.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 401 592 67.7 %
Date: 2023-01-17 19:17:23 Functions: 12 14 85.7 %

          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

Generated by: LCOV version 1.13