LCOV - code coverage report
Current view: top level - EnergyPlus - Humidifiers.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 67.0 % 560 375
Test Date: 2025-05-22 16:09:37 Functions: 100.0 % 12 12

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

Generated by: LCOV version 2.0-1