LCOV - code coverage report
Current view: top level - EnergyPlus - ZoneDehumidifier.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 302 505 59.8 %
Date: 2024-08-23 23:50:59 Functions: 7 8 87.5 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Fmath.hh>
      53             : 
      54             : // EnergyPlus Headers
      55             : #include <EnergyPlus/CurveManager.hh>
      56             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      57             : #include <EnergyPlus/DataContaminantBalance.hh>
      58             : #include <EnergyPlus/DataEnvironment.hh>
      59             : #include <EnergyPlus/DataHVACGlobals.hh>
      60             : #include <EnergyPlus/DataLoopNode.hh>
      61             : #include <EnergyPlus/DataWater.hh>
      62             : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      63             : #include <EnergyPlus/DataZoneEquipment.hh>
      64             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      65             : #include <EnergyPlus/NodeInputManager.hh>
      66             : #include <EnergyPlus/OutputProcessor.hh>
      67             : #include <EnergyPlus/Psychrometrics.hh>
      68             : #include <EnergyPlus/ScheduleManager.hh>
      69             : #include <EnergyPlus/UtilityRoutines.hh>
      70             : #include <EnergyPlus/WaterManager.hh>
      71             : #include <EnergyPlus/ZoneDehumidifier.hh>
      72             : 
      73             : namespace EnergyPlus {
      74             : 
      75             : namespace ZoneDehumidifier {
      76             : 
      77             :     // Module containing the routines dealing with the ZoneDehumidifier
      78             : 
      79             :     // MODULE INFORMATION:
      80             :     //       AUTHOR         Don Shirey, FSEC
      81             :     //       DATE WRITTEN   July/Aug 2009
      82             :     //       MODIFIED       na
      83             :     //       RE-ENGINEERED  na
      84             : 
      85             :     // PURPOSE OF THIS MODULE:
      86             :     // Calculate the performance of zone (room) air dehumidifiers.  Meant to model
      87             :     // conventional direct expansion (DX) cooling-based room air dehumidifiers
      88             :     // (reject 100% of condenser heat to the zone air), but the approach
      89             :     // might be able to be used to model other room air dehumidifier types.
      90             : 
      91             :     // METHODOLOGY EMPLOYED:
      92             :     // Model as a piece of zone equipment, with inputs for water removal and
      93             :     // energy factor at rated conditions (26.7C, 60% RH). Then provide curve objects
      94             :     // to describe performance at off-rated conditions. A part-load cycling curve
      95             :     // input is also provided. It is assumed that this equipment dehumidifies but
      96             :     // heats the air. If used in tandem with another system that cools and dehumidifies,
      97             :     // then the zone dehumidifier should be specified as the lowest cooling priority
      98             :     // in the ZoneHVAC:EquipmentList object. The cooling and dehumidification system
      99             :     // operates first to meet the temperature setpoint (and possibly the high humidity
     100             :     // setpoint as well). If additional dehumidification is needed, then the zone
     101             :     // dehumidifier operates. The excess sensible heat generated by the dehumidifier
     102             :     // is carried over to the next HVAC time step.
     103             : 
     104             :     // OTHER NOTES:
     105             :     // Example manufacturer's data at:
     106             :     //   http://www.thermastor.com/HI-E-DRY-100/HI-E-DRY-100-Spec.pdf
     107             :     //   http://www.thermastor.com/HI-E-DRY-195/HI-E-DRY-195-Spec.pdf
     108             : 
     109             :     // Using/Aliasing
     110             :     using namespace DataLoopNode;
     111             :     using namespace ScheduleManager;
     112             : 
     113       50989 :     void SimZoneDehumidifier(EnergyPlusData &state,
     114             :                              std::string const &CompName,                    // Name of the zone dehumidifier
     115             :                              int const ZoneNum,                              // Number of zone being served
     116             :                              [[maybe_unused]] bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
     117             :                              Real64 &QSensOut,                               // Sensible capacity delivered to zone (W)
     118             :                              Real64 &QLatOut,                                // Latent capacity delivered to zone (kg/s), dehumidify = negative
     119             :                              int &CompIndex                                  // Index to the zone dehumidifier
     120             :     )
     121             :     {
     122             : 
     123             :         // SUBROUTINE INFORMATION:
     124             :         //       AUTHOR         Don Shirey, FSEC
     125             :         //       DATE WRITTEN   July/Aug 2009
     126             :         //       MODIFIED       na
     127             :         //       RE-ENGINEERED  na
     128             : 
     129             :         // PURPOSE OF THIS SUBROUTINE:
     130             :         // Simulate a zone dehumidifier.
     131             : 
     132             :         // METHODOLOGY EMPLOYED:
     133             :         // Call appropriate subroutines to get input values, initialize variables, model performanc
     134             :         // update node information, report model outputs.
     135             : 
     136             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     137             :         int ZoneDehumidNum;   // Index of zone dehumidifier being simulated
     138             :         Real64 QZnDehumidReq; // Zone dehumidification load required (kg moisture/sec)
     139             : 
     140       50989 :         if (state.dataZoneDehumidifier->GetInputFlag) {
     141           2 :             GetZoneDehumidifierInput(state);
     142           2 :             state.dataZoneDehumidifier->GetInputFlag = false;
     143             :         }
     144             : 
     145             :         // Find the correct zone dehumidifier
     146       50989 :         if (CompIndex == 0) {
     147           2 :             ZoneDehumidNum = Util::FindItemInList(CompName, state.dataZoneDehumidifier->ZoneDehumid);
     148           2 :             if (ZoneDehumidNum == 0) {
     149           0 :                 ShowFatalError(state, format("SimZoneDehumidifier: Unit not found= {}", CompName));
     150             :             }
     151           2 :             CompIndex = ZoneDehumidNum;
     152             :         } else {
     153       50987 :             ZoneDehumidNum = CompIndex;
     154       50987 :             int NumDehumidifiers = (int)state.dataZoneDehumidifier->ZoneDehumid.size();
     155       50987 :             if (ZoneDehumidNum > NumDehumidifiers || ZoneDehumidNum < 1) {
     156           0 :                 ShowFatalError(state,
     157           0 :                                format("SimZoneDehumidifier:  Invalid CompIndex passed= {}, Number of Units= {}, Entered Unit name= {}",
     158             :                                       ZoneDehumidNum,
     159             :                                       NumDehumidifiers,
     160             :                                       CompName));
     161             :             }
     162       50987 :             if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidNum).CheckEquipName) {
     163           2 :                 if (CompName != state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidNum).Name) {
     164           0 :                     ShowFatalError(state,
     165           0 :                                    format("SimZoneDehumidifier: Invalid CompIndex passed={}, Unit name= {}, stored Unit Name for that index= {}",
     166             :                                           ZoneDehumidNum,
     167             :                                           CompName,
     168           0 :                                           state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidNum).Name));
     169             :                 }
     170           2 :                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidNum).CheckEquipName = false;
     171             :             }
     172             :         }
     173             : 
     174       50989 :         QZnDehumidReq = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(ZoneNum).RemainingOutputReqToDehumidSP; // Negative means dehumidify
     175             : 
     176       50989 :         InitZoneDehumidifier(state, ZoneDehumidNum);
     177             : 
     178       50989 :         CalcZoneDehumidifier(state, ZoneDehumidNum, QZnDehumidReq, QSensOut, QLatOut);
     179             : 
     180       50989 :         UpdateZoneDehumidifier(state, ZoneDehumidNum);
     181             : 
     182       50989 :         ReportZoneDehumidifier(state, ZoneDehumidNum);
     183       50989 :     }
     184             : 
     185          24 :     void GetZoneDehumidifierInput(EnergyPlusData &state)
     186             :     {
     187             : 
     188             :         // SUBROUTINE INFORMATION:
     189             :         //       AUTHOR         Don Shirey, FSEC
     190             :         //       DATE WRITTEN   July/Aug 2009
     191             :         //       MODIFIED       na
     192             :         //       RE-ENGINEERED  na
     193             : 
     194             :         // PURPOSE OF THIS SUBROUTINE:
     195             :         // Retrieve the inputs from the input data file (idf) being simulated.
     196             : 
     197             :         // METHODOLOGY EMPLOYED:
     198             :         // Standard EnergyPlus methodology using available utility routines where appropriate.
     199             : 
     200             :         // Using/Aliasing
     201             :         using Curve::CurveValue;
     202             :         using Curve::GetCurveIndex;
     203             :         using NodeInputManager::GetOnlySingleNode;
     204             :         using WaterManager::SetupTankSupplyComponent;
     205             : 
     206             :         // SUBROUTINE PARAMETER DEFINITIONS:
     207             :         static constexpr std::string_view RoutineName("GetZoneDehumidifierInput");
     208          24 :         static std::string const CurrentModuleObject("ZoneHVAC:Dehumidifier:DX");
     209          24 :         Real64 constexpr RatedInletAirTemp(26.7);
     210          24 :         Real64 constexpr RatedInletAirRH(60.0);
     211             : 
     212             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     213             :         int ZoneDehumidIndex;          // Loop index
     214          24 :         int NumAlphas(0);              // Number of Alphas to allocate arrays, then used for each GetObjectItem call
     215          24 :         int NumNumbers(0);             // Number of Numbers to allocate arrays, then used for each GetObjectItem call
     216             :         int IOStatus;                  // Used in GetObjectItem
     217          24 :         bool ErrorsFound(false);       // Set to true if errors in input, fatal at end of routine
     218          24 :         Array1D_string Alphas;         // Alpha input items for object
     219          24 :         Array1D_string cAlphaFields;   // Alpha field names
     220          24 :         Array1D_string cNumericFields; // Numeric field names
     221          24 :         Array1D<Real64> Numbers;       // Numeric input items for object
     222          24 :         Array1D_bool lAlphaBlanks;     // Logical array, alpha field input BLANK = .TRUE.
     223          24 :         Array1D_bool lNumericBlanks;   // Logical array, numeric field input BLANK = .TRUE.
     224          24 :         int TotalArgs(0);              // Total number of alpha and numeric arguments (max)
     225             :         Real64 CurveVal;               // Output from curve object (water removal or energy factor curves)
     226             : 
     227          24 :         int NumDehumidifiers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     228             : 
     229          24 :         state.dataZoneDehumidifier->ZoneDehumid.allocate(NumDehumidifiers);
     230             : 
     231          24 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, TotalArgs, NumAlphas, NumNumbers);
     232             : 
     233          24 :         Alphas.allocate(NumAlphas);
     234          24 :         cAlphaFields.allocate(NumAlphas);
     235          24 :         cNumericFields.allocate(NumNumbers);
     236          24 :         Numbers.dimension(NumNumbers, 0.0);
     237          24 :         lAlphaBlanks.dimension(NumAlphas, true);
     238          24 :         lNumericBlanks.dimension(NumNumbers, true);
     239             : 
     240          26 :         for (ZoneDehumidIndex = 1; ZoneDehumidIndex <= NumDehumidifiers; ++ZoneDehumidIndex) {
     241             : 
     242           2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     243             :                                                                      CurrentModuleObject,
     244             :                                                                      ZoneDehumidIndex,
     245             :                                                                      Alphas,
     246             :                                                                      NumAlphas,
     247             :                                                                      Numbers,
     248             :                                                                      NumNumbers,
     249             :                                                                      IOStatus,
     250             :                                                                      lNumericBlanks,
     251             :                                                                      lAlphaBlanks,
     252             :                                                                      cAlphaFields,
     253             :                                                                      cNumericFields);
     254           2 :             Util::IsNameEmpty(state, Alphas(1), CurrentModuleObject, ErrorsFound);
     255             : 
     256             :             // A1,  \field Name
     257           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name = Alphas(1);
     258           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).UnitType = CurrentModuleObject; // 'ZoneHVAC:Dehumidifier:DX'
     259             : 
     260             :             // A2,  \field Availability Schedule Name
     261           2 :             if (lAlphaBlanks(2)) {
     262           0 :                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).SchedPtr = ScheduleManager::ScheduleAlwaysOn;
     263             :             } else {
     264           2 :                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).SchedPtr =
     265           2 :                     GetScheduleIndex(state, Alphas(2)); // Convert schedule name to pointer
     266           2 :                 if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).SchedPtr == 0) {
     267           0 :                     ShowSevereError(state, format("{} not found = {}", cAlphaFields(2), Alphas(2)));
     268           0 :                     ShowContinueError(
     269           0 :                         state, format("Occurs in {} = {}", CurrentModuleObject, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     270           0 :                     ErrorsFound = true;
     271             :                 }
     272             :             }
     273             : 
     274             :             // A3 , \field Air Inlet Node Name
     275           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).AirInletNodeNum =
     276           4 :                 GetOnlySingleNode(state,
     277           2 :                                   Alphas(3),
     278             :                                   ErrorsFound,
     279             :                                   DataLoopNode::ConnectionObjectType::ZoneHVACDehumidifierDX,
     280           2 :                                   Alphas(1),
     281             :                                   DataLoopNode::NodeFluidType::Air,
     282             :                                   DataLoopNode::ConnectionType::Inlet,
     283             :                                   NodeInputManager::CompFluidStream::Primary,
     284             :                                   ObjectIsNotParent);
     285             : 
     286             :             // A4 , \field Air Outlet Node Name
     287           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).AirOutletNodeNum =
     288           4 :                 GetOnlySingleNode(state,
     289           2 :                                   Alphas(4),
     290             :                                   ErrorsFound,
     291             :                                   DataLoopNode::ConnectionObjectType::ZoneHVACDehumidifierDX,
     292           2 :                                   Alphas(1),
     293             :                                   DataLoopNode::NodeFluidType::Air,
     294             :                                   DataLoopNode::ConnectionType::Outlet,
     295             :                                   NodeInputManager::CompFluidStream::Primary,
     296             :                                   ObjectIsNotParent);
     297             : 
     298             :             // N1,  \field Rated Water Removal
     299           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).RatedWaterRemoval = Numbers(1);
     300           2 :             if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).RatedWaterRemoval <= 0.0) {
     301           0 :                 ShowSevereError(state, format("{} must be greater than zero.", cNumericFields(1)));
     302           0 :                 ShowContinueError(state, format("Value specified = {:.5T}", Numbers(1)));
     303           0 :                 ShowContinueError(state,
     304           0 :                                   format("Occurs in {} = {}", CurrentModuleObject, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     305           0 :                 ErrorsFound = true;
     306             :             }
     307             : 
     308             :             // N2,  \field Rated Energy Factor
     309           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).RatedEnergyFactor = Numbers(2);
     310           2 :             if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).RatedEnergyFactor <= 0.0) {
     311           0 :                 ShowSevereError(state, format("{} must be greater than zero.", cNumericFields(2)));
     312           0 :                 ShowContinueError(state, format("Value specified = {:.5T}", Numbers(2)));
     313           0 :                 ShowContinueError(state,
     314           0 :                                   format("Occurs in {} = {}", CurrentModuleObject, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     315           0 :                 ErrorsFound = true;
     316             :             }
     317             : 
     318             :             // N3,  \field Rated Air Flow Rate
     319           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).RatedAirVolFlow = Numbers(3);
     320           2 :             if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).RatedAirVolFlow <= 0.0) {
     321           0 :                 ShowSevereError(state, format("{} must be greater than zero.", cNumericFields(3)));
     322           0 :                 ShowContinueError(state, format("Value specified = {:.5T}", Numbers(3)));
     323           0 :                 ShowContinueError(state,
     324           0 :                                   format("Occurs in {} = {}", CurrentModuleObject, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     325           0 :                 ErrorsFound = true;
     326             :             }
     327             : 
     328             :             // A5,  \field Water Removal Curve Name
     329           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).WaterRemovalCurveIndex =
     330           2 :                 GetCurveIndex(state, Alphas(5)); // Convert curve name to index number
     331           2 :             if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).WaterRemovalCurveIndex == 0) {
     332           0 :                 if (lAlphaBlanks(5)) {
     333           0 :                     ShowSevereError(state,
     334           0 :                                     format("{}:{}=\"{}\" is required, missing for {} = {}",
     335             :                                            RoutineName,
     336             :                                            CurrentModuleObject,
     337             :                                            cAlphaFields(5),
     338             :                                            cAlphaFields(1),
     339           0 :                                            state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     340             :                 } else {
     341           0 :                     ShowSevereError(state, format("{} not found = {}", cAlphaFields(5), Alphas(5)));
     342           0 :                     ShowContinueError(
     343           0 :                         state, format("Occurs in {} = {}", CurrentModuleObject, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     344             :                 }
     345           0 :                 ErrorsFound = true;
     346             :             } else {
     347             :                 // Verify Curve object, only legal type is BiQuadratic
     348           4 :                 ErrorsFound |= Curve::CheckCurveDims(state,
     349           2 :                                                      state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).WaterRemovalCurveIndex, // Curve index
     350             :                                                      {2},                                                            // Valid dimensions
     351             :                                                      RoutineName,                                                    // Routine name
     352             :                                                      CurrentModuleObject,                                            // Object Type
     353           2 :                                                      state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name, // Object Name
     354           2 :                                                      cAlphaFields(5));                                               // Field Name
     355             : 
     356           2 :                 if (!ErrorsFound) {
     357           4 :                     CurveVal = CurveValue(
     358           2 :                         state, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).WaterRemovalCurveIndex, RatedInletAirTemp, RatedInletAirRH);
     359           2 :                     if (CurveVal > 1.10 || CurveVal < 0.90) {
     360           0 :                         ShowWarningError(state, format("{} output is not equal to 1.0", cAlphaFields(5)));
     361           0 :                         ShowContinueError(state, format("(+ or -10%) at rated conditions for {} = {}", CurrentModuleObject, Alphas(1)));
     362           0 :                         ShowContinueError(state, format("Curve output at rated conditions = {:.3T}", CurveVal));
     363             :                     }
     364             :                 }
     365             :             }
     366             : 
     367             :             // A6,  \field Energy Factor Curve Name
     368           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).EnergyFactorCurveIndex =
     369           2 :                 GetCurveIndex(state, Alphas(6)); // convert curve name to number
     370           2 :             if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).EnergyFactorCurveIndex == 0) {
     371           0 :                 if (lAlphaBlanks(6)) {
     372           0 :                     ShowSevereError(state,
     373           0 :                                     format("{}:{}=\"{}\" is required, missing for {} = {}",
     374             :                                            RoutineName,
     375             :                                            CurrentModuleObject,
     376             :                                            cAlphaFields(6),
     377             :                                            cAlphaFields(1),
     378           0 :                                            state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     379             :                 } else {
     380           0 :                     ShowSevereError(state, format("{} not found = {}", cAlphaFields(6), Alphas(6)));
     381           0 :                     ShowContinueError(
     382           0 :                         state, format("Occurs in {} = {}", CurrentModuleObject, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     383             :                 }
     384           0 :                 ErrorsFound = true;
     385             :             } else {
     386             :                 // Verify Curve Object, only legal type is BiQuadratic
     387           4 :                 ErrorsFound |= Curve::CheckCurveDims(state,
     388           2 :                                                      state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).EnergyFactorCurveIndex, // Curve index
     389             :                                                      {2},                                                            // Valid dimensions
     390             :                                                      RoutineName,                                                    // Routine name
     391             :                                                      CurrentModuleObject,                                            // Object Type
     392           2 :                                                      state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name, // Object Name
     393           2 :                                                      cAlphaFields(6));                                               // Field Name
     394             : 
     395           2 :                 if (!ErrorsFound) {
     396           4 :                     CurveVal = CurveValue(
     397           2 :                         state, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).EnergyFactorCurveIndex, RatedInletAirTemp, RatedInletAirRH);
     398           2 :                     if (CurveVal > 1.10 || CurveVal < 0.90) {
     399           0 :                         ShowWarningError(state, format("{} output is not equal to 1.0", cAlphaFields(6)));
     400           0 :                         ShowContinueError(state, format("(+ or -10%) at rated conditions for {} = {}", CurrentModuleObject, Alphas(1)));
     401           0 :                         ShowContinueError(state, format("Curve output at rated conditions = {:.3T}", CurveVal));
     402             :                     }
     403             :                 }
     404             :             }
     405             : 
     406             :             // A7,  \field Part Load Fraction Correlation Curve Name
     407           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).PartLoadCurveIndex =
     408           2 :                 GetCurveIndex(state, Alphas(7)); // convert curve name to number
     409           2 :             if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).PartLoadCurveIndex == 0) {
     410           0 :                 if (lAlphaBlanks(7)) {
     411           0 :                     ShowSevereError(state,
     412           0 :                                     format("{}:{}=\"{}\" is required, missing for {} = {}",
     413             :                                            RoutineName,
     414             :                                            CurrentModuleObject,
     415             :                                            cAlphaFields(7),
     416             :                                            cAlphaFields(1),
     417           0 :                                            state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     418             :                 } else {
     419           0 :                     ShowSevereError(state, format("{} not found = {}", cAlphaFields(7), Alphas(7)));
     420           0 :                     ShowContinueError(
     421           0 :                         state, format("Occurs in {} = {}", CurrentModuleObject, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     422             :                 }
     423           0 :                 ErrorsFound = true;
     424             :             } else {
     425             :                 // Verify Curve Object, legal types are Quadratic and Cubic
     426           4 :                 ErrorsFound |= Curve::CheckCurveDims(state,
     427           2 :                                                      state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).PartLoadCurveIndex, // Curve index
     428             :                                                      {1},                                                                          // Valid dimensions
     429             :                                                      RoutineName,                                                                  // Routine name
     430             :                                                      CurrentModuleObject,                                                          // Object Type
     431           2 :                                                      state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name,               // Object Name
     432           2 :                                                      cAlphaFields(7));                                                             // Field Name
     433             :             }
     434             : 
     435             :             // N4,  \field Minimum Dry-Bulb Temperature for Dehumidifier Operation
     436             :             // N5,  \field Maximum Dry-Bulb Temperature for Dehumidifier Operation
     437           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).MinInletAirTemp = Numbers(4);
     438           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).MaxInletAirTemp = Numbers(5);
     439             : 
     440           2 :             if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).MinInletAirTemp >=
     441           2 :                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).MaxInletAirTemp) {
     442           0 :                 ShowSevereError(state, format("{} must be greater than {}", cNumericFields(5), cNumericFields(4)));
     443           0 :                 ShowContinueError(state, format("{} specified = {:.1T}", cNumericFields(5), Numbers(5)));
     444           0 :                 ShowContinueError(state, format("{} specified = {:.1T}", cNumericFields(4), Numbers(4)));
     445           0 :                 ShowContinueError(state,
     446           0 :                                   format("Occurs in {} = {}", CurrentModuleObject, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     447           0 :                 ErrorsFound = true;
     448             :             }
     449             : 
     450             :             // N6,  \field Off Cycle Parasitic Electric Load
     451           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).OffCycleParasiticLoad = Numbers(6); // Off Cycle Parasitic Load [W]
     452             : 
     453           2 :             if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).OffCycleParasiticLoad < 0.0) {
     454           0 :                 ShowSevereError(state, format("{} must be >= zero.", cNumericFields(6)));
     455           0 :                 ShowContinueError(state, format("Value specified = {:.2T}", Numbers(6)));
     456           0 :                 ShowContinueError(state,
     457           0 :                                   format("Occurs in {} = {}", CurrentModuleObject, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name));
     458           0 :                 ErrorsFound = true;
     459             :             }
     460             : 
     461             :             // A8;  \field Condensate Collection Water Storage Tank Name
     462           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).CondensateCollectName = Alphas(8);
     463           2 :             if (lAlphaBlanks(8)) {
     464           2 :                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).CondensateCollectMode = CondensateOutlet::Discarded;
     465             :             } else {
     466           0 :                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).CondensateCollectMode = CondensateOutlet::ToTank;
     467           0 :                 SetupTankSupplyComponent(state,
     468           0 :                                          state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name,
     469             :                                          CurrentModuleObject,
     470           0 :                                          state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).CondensateCollectName,
     471             :                                          ErrorsFound,
     472           0 :                                          state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).CondensateTankID,
     473           0 :                                          state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).CondensateTankSupplyARRID);
     474             :             }
     475             : 
     476             :         } //   DO ZoneDehumidIndex=1,NumDehumidifiers
     477             : 
     478          24 :         Alphas.deallocate();
     479          24 :         cAlphaFields.deallocate();
     480          24 :         cNumericFields.deallocate();
     481          24 :         Numbers.deallocate();
     482          24 :         lAlphaBlanks.deallocate();
     483          24 :         lNumericBlanks.deallocate();
     484             : 
     485          24 :         if (ErrorsFound) {
     486           0 :             ShowFatalError(state, format("{}:{}: Errors found in input.", RoutineName, CurrentModuleObject));
     487             :         }
     488             : 
     489          26 :         for (ZoneDehumidIndex = 1; ZoneDehumidIndex <= NumDehumidifiers; ++ZoneDehumidIndex) {
     490             :             // Set up report variables for the dehumidifiers
     491           4 :             SetupOutputVariable(state,
     492             :                                 "Zone Dehumidifier Sensible Heating Rate",
     493             :                                 Constant::Units::W,
     494           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).SensHeatingRate,
     495             :                                 OutputProcessor::TimeStepType::System,
     496             :                                 OutputProcessor::StoreType::Average,
     497           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     498           4 :             SetupOutputVariable(state,
     499             :                                 "Zone Dehumidifier Sensible Heating Energy",
     500             :                                 Constant::Units::J,
     501           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).SensHeatingEnergy,
     502             :                                 OutputProcessor::TimeStepType::System,
     503             :                                 OutputProcessor::StoreType::Sum,
     504           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     505           4 :             SetupOutputVariable(state,
     506             :                                 "Zone Dehumidifier Removed Water Mass Flow Rate",
     507             :                                 Constant::Units::kg_s,
     508           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).WaterRemovalRate,
     509             :                                 OutputProcessor::TimeStepType::System,
     510             :                                 OutputProcessor::StoreType::Average,
     511           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     512           4 :             SetupOutputVariable(state,
     513             :                                 "Zone Dehumidifier Removed Water Mass",
     514             :                                 Constant::Units::kg,
     515           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).WaterRemoved,
     516             :                                 OutputProcessor::TimeStepType::System,
     517             :                                 OutputProcessor::StoreType::Sum,
     518           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     519           4 :             SetupOutputVariable(state,
     520             :                                 "Zone Dehumidifier Electricity Rate",
     521             :                                 Constant::Units::W,
     522           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).ElecPower,
     523             :                                 OutputProcessor::TimeStepType::System,
     524             :                                 OutputProcessor::StoreType::Average,
     525           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     526           4 :             SetupOutputVariable(state,
     527             :                                 "Zone Dehumidifier Electricity Energy",
     528             :                                 Constant::Units::J,
     529           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).ElecConsumption,
     530             :                                 OutputProcessor::TimeStepType::System,
     531             :                                 OutputProcessor::StoreType::Sum,
     532           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name,
     533             :                                 Constant::eResource::Electricity,
     534             :                                 OutputProcessor::Group::HVAC,
     535             :                                 OutputProcessor::EndUseCat::Cooling);
     536           4 :             SetupOutputVariable(state,
     537             :                                 "Zone Dehumidifier Off Cycle Parasitic Electricity Rate",
     538             :                                 Constant::Units::W,
     539           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).OffCycleParasiticElecPower,
     540             :                                 OutputProcessor::TimeStepType::System,
     541             :                                 OutputProcessor::StoreType::Average,
     542           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     543           4 :             SetupOutputVariable(state,
     544             :                                 "Zone Dehumidifier Off Cycle Parasitic Electricity Energy",
     545             :                                 Constant::Units::J,
     546           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).OffCycleParasiticElecCons,
     547             :                                 OutputProcessor::TimeStepType::System,
     548             :                                 OutputProcessor::StoreType::Sum,
     549           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     550           4 :             SetupOutputVariable(state,
     551             :                                 "Zone Dehumidifier Part Load Ratio",
     552             :                                 Constant::Units::None,
     553           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).DehumidPLR,
     554             :                                 OutputProcessor::TimeStepType::System,
     555             :                                 OutputProcessor::StoreType::Average,
     556           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     557           4 :             SetupOutputVariable(state,
     558             :                                 "Zone Dehumidifier Runtime Fraction",
     559             :                                 Constant::Units::None,
     560           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).DehumidRTF,
     561             :                                 OutputProcessor::TimeStepType::System,
     562             :                                 OutputProcessor::StoreType::Average,
     563           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     564           4 :             SetupOutputVariable(state,
     565             :                                 "Zone Dehumidifier Outlet Air Temperature",
     566             :                                 Constant::Units::C,
     567           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).OutletAirTemp,
     568             :                                 OutputProcessor::TimeStepType::System,
     569             :                                 OutputProcessor::StoreType::Average,
     570           2 :                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     571             : 
     572           2 :             if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).CondensateCollectMode == CondensateOutlet::ToTank) {
     573           0 :                 SetupOutputVariable(state,
     574             :                                     "Zone Dehumidifier Condensate Volume Flow Rate",
     575             :                                     Constant::Units::m3_s,
     576           0 :                                     state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).DehumidCondVolFlowRate,
     577             :                                     OutputProcessor::TimeStepType::System,
     578             :                                     OutputProcessor::StoreType::Average,
     579           0 :                                     state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name);
     580           0 :                 SetupOutputVariable(state,
     581             :                                     "Zone Dehumidifier Condensate Volume",
     582             :                                     Constant::Units::m3,
     583           0 :                                     state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).DehumidCondVol,
     584             :                                     OutputProcessor::TimeStepType::System,
     585             :                                     OutputProcessor::StoreType::Sum,
     586           0 :                                     state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).Name,
     587             :                                     Constant::eResource::OnSiteWater,
     588             :                                     OutputProcessor::Group::HVAC,
     589             :                                     OutputProcessor::EndUseCat::Condensate);
     590             :             }
     591             :         }
     592          24 :     }
     593             : 
     594       50989 :     void InitZoneDehumidifier(EnergyPlusData &state, int const ZoneDehumNum) // Number of the current zone dehumidifier being simulated
     595             :     {
     596             : 
     597             :         // SUBROUTINE INFORMATION:
     598             :         //       AUTHOR         Don Shirey, FSEC
     599             :         //       DATE WRITTEN   July/Aug 2009
     600             :         //       MODIFIED       na
     601             :         //       RE-ENGINEERED  na
     602             : 
     603             :         // PURPOSE OF THIS SUBROUTINE:
     604             :         // This subroutine initializes information for the zone dehumidifier model
     605             : 
     606             :         // METHODOLOGY EMPLOYED:
     607             :         // Use status flags to trigger various initializations
     608             : 
     609             :         // Using/Aliasing
     610             :         using DataZoneEquipment::CheckZoneEquipmentList;
     611             :         using Psychrometrics::PsyRhoAirFnPbTdbW;
     612             :         using Psychrometrics::PsyWFnTdbRhPb;
     613             : 
     614             :         // SUBROUTINE PARAMETER DEFINITIONS:
     615             :         static constexpr std::string_view RoutineName("InitZoneDehumidifier");
     616             : 
     617             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     618             :         int AirInletNode;      // Inlet air node number
     619             :         Real64 RatedAirHumrat; // Humidity ratio (kg/kg) at rated inlet air conditions of 26.6667C, 60% RH
     620             :         Real64 RatedAirDBTemp; // Dry-bulb air temperature at rated conditions 26.6667C
     621             :         Real64 RatedAirRH;     // Relative humidity of air (0.6 --> 60%) at rated conditions
     622             : 
     623             :         // Need to check all dehumidifiers to see if they are on Zone Equipment List or issue warning
     624       50989 :         if (!state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
     625           2 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).ZoneEquipmentListChecked = true;
     626           4 :             if (!CheckZoneEquipmentList(state,
     627           2 :                                         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType,
     628           2 :                                         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name)) {
     629           0 :                 ShowSevereError(
     630             :                     state,
     631           0 :                     format("InitZoneDehumidifier: Zone Dehumidifier=\"{},{}\" is not on any ZoneHVAC:EquipmentList.  It will not be simulated.",
     632           0 :                            state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType,
     633           0 :                            state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name));
     634             :             }
     635             :         }
     636             : 
     637       50989 :         AirInletNode = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).AirInletNodeNum;
     638             :         // Do the Begin Environment initializations
     639       50989 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).MyEnvrnFlag) {
     640             : 
     641             :             // Set the mass flow rates from the input volume flow rates, at rated conditions of 26.6667C, 60% RH
     642             :             // Might default back to STP later after discussion with M. Witte, use StdRhoAir instead of calc'd RhoAir at rated conditions
     643          11 :             RatedAirDBTemp = 26.6667; // 26.6667 C, 80F
     644          11 :             RatedAirRH = 0.6;         // 60% RH
     645          11 :             RatedAirHumrat = PsyWFnTdbRhPb(state, RatedAirDBTemp, RatedAirRH, state.dataEnvrn->StdBaroPress, RoutineName);
     646          11 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).RatedAirMassFlow =
     647          11 :                 PsyRhoAirFnPbTdbW(state, state.dataEnvrn->StdBaroPress, RatedAirDBTemp, RatedAirHumrat, RoutineName) *
     648          11 :                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).RatedAirVolFlow;
     649             : 
     650             :             // Set the node max and min mass flow rates on inlet node... outlet node gets updated in UPDATE subroutine
     651          11 :             state.dataLoopNodes->Node(AirInletNode).MassFlowRateMax = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).RatedAirMassFlow;
     652          11 :             state.dataLoopNodes->Node(AirInletNode).MassFlowRateMaxAvail = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).RatedAirMassFlow;
     653          11 :             state.dataLoopNodes->Node(AirInletNode).MassFlowRateMinAvail = 0.0;
     654          11 :             state.dataLoopNodes->Node(AirInletNode).MassFlowRateMin = 0.0;
     655             : 
     656          11 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).MyEnvrnFlag = false;
     657             :         } // End one time inits
     658             : 
     659       50989 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     660       50749 :             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).MyEnvrnFlag = true;
     661             :         }
     662             : 
     663             :         // These initializations are done every iteration
     664       50989 :         state.dataLoopNodes->Node(AirInletNode).MassFlowRate = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).RatedAirMassFlow;
     665             : 
     666             :         // Zero out the report variables
     667       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).SensHeatingRate = 0.0;   // Zone Dehumidifier Sensible Heating Rate [W]
     668       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).SensHeatingEnergy = 0.0; // Zone Dehumidifier Sensible Heating Energy [J]
     669       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).WaterRemovalRate = 0.0;  // Zone Dehumidifier Water Removal Rate [kg/s]
     670       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).WaterRemoved = 0.0;      // Zone Dehumidifier Water Removed [kg]
     671       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).ElecPower = 0.0;         // Zone Dehumidifier Electric Power [W]
     672       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).ElecConsumption = 0.0;   // Zone Dehumidifier Electric Consumption [J]
     673       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).DehumidPLR = 0.0;        // Zone Dehumidifier Part-Load Ratio [-]
     674       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).DehumidRTF = 0.0;        // Zone Dehumidifier Runtime Fraction [-]
     675       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OffCycleParasiticElecPower =
     676             :             0.0; // Zone Dehumidifier Off-Cycle Parasitic Electric Power [W]
     677       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OffCycleParasiticElecCons =
     678             :             0.0; // Zone Dehumidifier Off-Cycle Parasitic Electric Consumption [J]
     679       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).DehumidCondVolFlowRate =
     680             :             0.0;                                                                    // Zone Dehumidifier Condensate Volumetric Flow Rate [m3/s]
     681       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).DehumidCondVol = 0.0; // Zone Dehumidifier Condensate Volume [m3]
     682       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OutletAirTemp =
     683       50989 :             state.dataLoopNodes->Node(AirInletNode).Temp; // Zone Dehumidifier Outlet Air Temperature [C]
     684       50989 :     }
     685             : 
     686       50989 :     void CalcZoneDehumidifier(EnergyPlusData &state,
     687             :                               int const ZoneDehumNum,     // Index number of the current zone dehumidifier being simulated
     688             :                               Real64 const QZnDehumidReq, // Dehumidification load to be met (kg/s), negative value means dehumidification load
     689             :                               Real64 &SensibleOutput,     // Sensible (heating) output (W), sent to load predictor for next simulation time step
     690             :                               Real64 &LatentOutput        // Latent (dehumidification) output provided (kg/s)
     691             :     )
     692             :     {
     693             : 
     694             :         // SUBROUTINE INFORMATION:
     695             :         //       AUTHOR         Don Shirey, FSEC
     696             :         //       DATE WRITTEN   July/Aug 2009
     697             :         //       MODIFIED       na
     698             :         //       RE-ENGINEERED  na
     699             : 
     700             :         // PURPOSE OF THIS SUBROUTINE:
     701             :         // Calculate the delivered capacity, electric energy consumption and water/condensate
     702             :         // removal rates for the zone dehumidifier.
     703             : 
     704             :         // METHODOLOGY EMPLOYED:
     705             :         // Cycle the dehumidifier as needed to meet the remaining zone dehumidification load.
     706             :         // Send excess sensible heat to zone energy balance (via SensibleOutput) for next HVAC time step,
     707             :         // so set the dehumidifier outlet air temp = inlet air temp to avoid double counting excess sensible.
     708             : 
     709             :         // REFERENCES:
     710             :         // na
     711             : 
     712             :         // Using/Aliasing
     713             :         using Curve::CurveValue;
     714             :         using Psychrometrics::PsyCpAirFnW;
     715             :         using Psychrometrics::PsyHfgAirFnWTdb;
     716             :         using Psychrometrics::PsyHFnTdbW;
     717             :         using Psychrometrics::PsyRhFnTdbWPb;
     718             :         using Psychrometrics::RhoH2O;
     719             : 
     720             :         // Locals
     721             :         // SUBROUTINE ARGUMENT DEFINITIONS:
     722             : 
     723             :         // SUBROUTINE PARAMETER DEFINITIONS:
     724             :         static constexpr std::string_view RoutineName("CalcZoneDehumidifier");
     725             : 
     726             :         // INTERFACE BLOCK SPECIFICATIONS:
     727             :         // na
     728             : 
     729             :         // DERIVED TYPE DEFINITIONS:
     730             :         // na
     731             : 
     732             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     733             :         Real64 WaterRemovalRateFactor; // Adjustment to  Rate Water Removal as a function of inlet air T and RH
     734             :         Real64 WaterRemovalVolRate;    // Actual water removal rate at current inlet air conditions (L/day)
     735             :         Real64 WaterRemovalMassRate;   // Actual water removal rate at current inlet air conditions (kg/s)
     736             :         Real64 EnergyFactorAdjFactor;  // Adjustment to Rate Energy Factor as a function of inlet air T and RH
     737             :         Real64 EnergyFactor;           // Actual Energy Factor as a function of inlet air T and RH
     738             :         Real64 InletAirTemp;           // Dry-bulb temperature of air entering the dehumidifier (C)
     739             :         Real64 InletAirHumRat;         // Humidity ratio of the air entering the dehumidifier (kg/kg)
     740             :         Real64 InletAirRH;             // Relative humidity of air entering the dehumidifier (%)
     741             :         Real64 OutletAirTemp;          // Dry-bulb temperature of air leaving the dehumidifier (C)
     742             :         Real64 OutletAirHumRat;        // Humidity ratio of air leaving the dehumidifier (kg/kg)
     743             :         Real64 PLR;                    // Part-load ratio = (dehumid load to be met)/(dehumid capacity of the dehumidifier)
     744             :         Real64 PLF;                    // Part-load fraction (-), RuntimeFraction = PLR/PLF
     745             :         Real64 RunTimeFraction;        // Dehumidifier runtime fraction (-)
     746             :         Real64 ElectricPowerOnCycle;   // Electric power when dehumidifier is operating (W)
     747             :         Real64 ElectricPowerAvg;       // Average electric power for this dehumidifier (W)
     748             :         Real64 hfg;                    // Enthalpy of evaporation of inlet air (J/kg)
     749             :         Real64 AirMassFlowRate;        // Air mass flow rate through this dehumidifier (kg/s)
     750             :         Real64 Cp;                     // Heat capacity of inlet air (J/kg-C)
     751       50989 :         int AirInletNodeNum(0);        // Node number for the inlet air to the dehumidifier
     752       50989 :         int AirOutletNodeNum(0);       // Node number for the outlet air from the dehumidifier
     753             : 
     754       50989 :         SensibleOutput = 0.0;
     755       50989 :         LatentOutput = 0.0;
     756       50989 :         WaterRemovalRateFactor = 0.0;
     757       50989 :         AirMassFlowRate = 0.0;
     758       50989 :         PLR = 0.0;
     759       50989 :         PLF = 0.0;
     760       50989 :         EnergyFactorAdjFactor = 0.0;
     761       50989 :         RunTimeFraction = 0.0;
     762       50989 :         ElectricPowerAvg = 0.0;
     763       50989 :         ElectricPowerOnCycle = 0.0;
     764             : 
     765       50989 :         AirInletNodeNum = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).AirInletNodeNum;
     766       50989 :         AirOutletNodeNum = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).AirOutletNodeNum;
     767             : 
     768       50989 :         InletAirTemp = state.dataLoopNodes->Node(AirInletNodeNum).Temp;
     769       50989 :         InletAirHumRat = state.dataLoopNodes->Node(AirInletNodeNum).HumRat;
     770       50989 :         InletAirRH = 100.0 * PsyRhFnTdbWPb(state, InletAirTemp, InletAirHumRat, state.dataEnvrn->OutBaroPress, RoutineName); // RH in percent (%)
     771             : 
     772        2371 :         if (QZnDehumidReq < 0.0 && GetCurrentScheduleValue(state, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).SchedPtr) > 0.0 &&
     773       55731 :             InletAirTemp >= state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).MinInletAirTemp &&
     774        2371 :             InletAirTemp <= state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).MaxInletAirTemp) {
     775             :             // A dehumidification load is being requested and dehumidifier is available (schedule value > 0)
     776             :             //  and the inlet air temperature is within the min/max values specified by user input
     777             : 
     778        2371 :             WaterRemovalRateFactor =
     779        2371 :                 CurveValue(state, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).WaterRemovalCurveIndex, InletAirTemp, InletAirRH);
     780             :             // Warn user if curve output goes negative
     781        2371 :             if (WaterRemovalRateFactor <= 0.0) {
     782           0 :                 if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).WaterRemovalCurveErrorCount < 1) {
     783           0 :                     ++state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).WaterRemovalCurveErrorCount;
     784           0 :                     ShowWarningError(state,
     785           0 :                                      format("{} \"{}\":",
     786           0 :                                             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType,
     787           0 :                                             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name));
     788           0 :                     ShowContinueError(state, format(" Water Removal Rate Curve output is <= 0.0 ({:.5T}).", WaterRemovalRateFactor));
     789           0 :                     ShowContinueError(
     790             :                         state,
     791           0 :                         format(
     792             :                             " Negative value occurs using an inlet air dry-bulb temperature of {:.2T} and an inlet air relative humidity of {:.1T}.",
     793             :                             InletAirTemp,
     794             :                             InletAirRH));
     795           0 :                     ShowContinueErrorTimeStamp(state, " Dehumidifier turned off for this time step but simulation continues.");
     796             :                 } else {
     797           0 :                     ShowRecurringWarningErrorAtEnd(state,
     798           0 :                                                    state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType + " \"" +
     799           0 :                                                        state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name +
     800             :                                                        "\": Water Removal Rate Curve output is <= 0.0 warning continues...",
     801           0 :                                                    state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).WaterRemovalCurveErrorIndex,
     802             :                                                    WaterRemovalRateFactor,
     803             :                                                    WaterRemovalRateFactor);
     804             :                 }
     805           0 :                 WaterRemovalRateFactor = 0.0;
     806             :             }
     807             : 
     808        2371 :             WaterRemovalVolRate = WaterRemovalRateFactor * state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).RatedWaterRemoval;
     809             : 
     810        2371 :             WaterRemovalMassRate =
     811        2371 :                 WaterRemovalVolRate / (24.0 * Constant::SecInHour * 1000.0) *
     812        2371 :                 RhoH2O(max((InletAirTemp - 11.0), 1.0)); //(L/d)/(24 hr/day *3600 sec/hr * 1000 L/m3) | Density of water, minimum temp = 1.0C
     813             : 
     814        2371 :             if (WaterRemovalMassRate > 0.0) {
     815        2371 :                 PLR = max(0.0, min(1.0, -QZnDehumidReq / WaterRemovalMassRate));
     816             :             } else {
     817           0 :                 PLR = 0.0;
     818           0 :                 RunTimeFraction = 0.0;
     819             :             }
     820             : 
     821        2371 :             EnergyFactorAdjFactor =
     822        2371 :                 CurveValue(state, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).EnergyFactorCurveIndex, InletAirTemp, InletAirRH);
     823             : 
     824             :             // Warn user if curve output goes negative
     825        2371 :             if (EnergyFactorAdjFactor <= 0.0) {
     826           0 :                 if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).EnergyFactorCurveErrorCount < 1) {
     827           0 :                     ++state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).EnergyFactorCurveErrorCount;
     828           0 :                     ShowWarningError(state,
     829           0 :                                      format("{} \"{}\":",
     830           0 :                                             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType,
     831           0 :                                             state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name));
     832           0 :                     ShowContinueError(state, format(" Energy Factor Curve output is <= 0.0 ({:.5T}).", EnergyFactorAdjFactor));
     833           0 :                     ShowContinueError(
     834             :                         state,
     835           0 :                         format(
     836             :                             " Negative value occurs using an inlet air dry-bulb temperature of {:.2T} and an inlet air relative humidity of {:.1T}.",
     837             :                             InletAirTemp,
     838             :                             InletAirRH));
     839           0 :                     ShowContinueErrorTimeStamp(state, " Dehumidifier turned off for this time step but simulation continues.");
     840             :                 } else {
     841           0 :                     ShowRecurringWarningErrorAtEnd(state,
     842           0 :                                                    state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType + " \"" +
     843           0 :                                                        state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name +
     844             :                                                        "\": Energy Factor Curve output is <= 0.0 warning continues...",
     845           0 :                                                    state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).EnergyFactorCurveErrorIndex,
     846             :                                                    EnergyFactorAdjFactor,
     847             :                                                    EnergyFactorAdjFactor);
     848             :                 }
     849           0 :                 ElectricPowerAvg = 0.0;
     850           0 :                 PLR = 0.0;
     851           0 :                 RunTimeFraction = 0.0;
     852             :             } else {
     853             :                 // EnergyFactorAdjFactor is not negative, so proceed with calculations
     854        2371 :                 EnergyFactor = EnergyFactorAdjFactor * state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).RatedEnergyFactor;
     855             : 
     856        2371 :                 if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).PartLoadCurveIndex > 0) {
     857        2371 :                     PLF = CurveValue(
     858        2371 :                         state, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).PartLoadCurveIndex, PLR); // Calculate part load fraction
     859             :                 } else {
     860           0 :                     PLF = 1.0;
     861             :                 }
     862             : 
     863        2371 :                 if (PLF < 0.7) {
     864           0 :                     if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).LowPLFErrorCount < 1) {
     865           0 :                         ++state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).LowPLFErrorCount;
     866           0 :                         ShowWarningError(state,
     867           0 :                                          format("{} \"{}\":",
     868           0 :                                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType,
     869           0 :                                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name));
     870           0 :                         ShowContinueError(
     871           0 :                             state, format(" The Part Load Fraction Correlation Curve output is ({:.2T}) at a part-load ratio ={:.3T}", PLF, PLR));
     872           0 :                         ShowContinueErrorTimeStamp(state,
     873             :                                                    " PLF curve values must be >= 0.7.  PLF has been reset to 0.7 and simulation is continuing.");
     874             :                     } else {
     875           0 :                         ShowRecurringWarningErrorAtEnd(state,
     876           0 :                                                        state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType + " \"" +
     877           0 :                                                            state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name +
     878             :                                                            "\": Part Load Fraction Correlation Curve output < 0.7 warning continues...",
     879           0 :                                                        state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).LowPLFErrorIndex,
     880             :                                                        PLF,
     881             :                                                        PLF);
     882             :                     }
     883           0 :                     PLF = 0.7;
     884             :                 }
     885             : 
     886        2371 :                 if (PLF > 1.0) {
     887           0 :                     if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).HighPLFErrorCount < 1) {
     888           0 :                         ++state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).HighPLFErrorCount;
     889           0 :                         ShowWarningError(state,
     890           0 :                                          format("{} \"{}\":",
     891           0 :                                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType,
     892           0 :                                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name));
     893           0 :                         ShowContinueError(
     894           0 :                             state, format(" The Part Load Fraction Correlation Curve output is ({:.2T}) at a part-load ratio ={:.3T}", PLF, PLR));
     895           0 :                         ShowContinueErrorTimeStamp(state,
     896             :                                                    " PLF curve values must be < 1.0.  PLF has been reset to 1.0 and simulation is continuing.");
     897             :                     } else {
     898           0 :                         ShowRecurringWarningErrorAtEnd(state,
     899           0 :                                                        state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType + " \"" +
     900           0 :                                                            state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name +
     901             :                                                            "\": Part Load Fraction Correlation Curve output > 1.0 warning continues...",
     902           0 :                                                        state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).HighPLFErrorIndex,
     903             :                                                        PLF,
     904             :                                                        PLF);
     905             :                     }
     906           0 :                     PLF = 1.0;
     907             :                 }
     908             : 
     909        2371 :                 if (PLF > 0.0 && PLF >= PLR) {
     910        2371 :                     RunTimeFraction = PLR / PLF; // Calculate dehumidifier runtime fraction
     911             :                 } else {
     912           0 :                     if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).PLFPLRErrorCount < 1) {
     913           0 :                         ++state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).PLFPLRErrorCount;
     914           0 :                         ShowWarningError(state,
     915           0 :                                          format("{} \"{}\":",
     916           0 :                                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType,
     917           0 :                                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name));
     918           0 :                         ShowContinueError(
     919             :                             state,
     920           0 :                             format("The part load fraction was less than the part load ratio calculated for this time step [PLR={:.4T}, PLF={:.4T}].",
     921             :                                    PLR,
     922             :                                    PLF));
     923           0 :                         ShowContinueError(state, "Runtime fraction reset to 1 and the simulation will continue.");
     924           0 :                         ShowContinueErrorTimeStamp(state, "");
     925             :                     } else {
     926           0 :                         ShowRecurringWarningErrorAtEnd(state,
     927           0 :                                                        state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType + " \"" +
     928           0 :                                                            state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name +
     929             :                                                            "\": Part load fraction less than part load ratio warning continues...",
     930           0 :                                                        state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).PLFPLRErrorIndex);
     931             :                     }
     932           0 :                     RunTimeFraction = 1.0;
     933             :                 }
     934             : 
     935        2371 :                 if (RunTimeFraction > 1.0 && std::abs(RunTimeFraction - 1.0) > 0.001) {
     936           0 :                     if (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).HighRTFErrorCount < 1) {
     937           0 :                         ++state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).HighRTFErrorCount;
     938           0 :                         ShowWarningError(state,
     939           0 :                                          format("{} \"{}\":",
     940           0 :                                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType,
     941           0 :                                                 state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name));
     942           0 :                         ShowContinueError(state, format("The runtime fraction for this zone dehumidifier exceeded 1.0 [{:.4T}].", RunTimeFraction));
     943           0 :                         ShowContinueError(state, "Runtime fraction reset to 1 and the simulation will continue.");
     944           0 :                         ShowContinueErrorTimeStamp(state, "");
     945             :                     } else {
     946           0 :                         ShowRecurringWarningErrorAtEnd(state,
     947           0 :                                                        state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).UnitType + " \"" +
     948           0 :                                                            state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).Name +
     949             :                                                            "\": Runtime fraction for zone dehumidifier exceeded 1.0 warning continues...",
     950           0 :                                                        state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).HighRTFErrorIndex,
     951             :                                                        RunTimeFraction,
     952             :                                                        RunTimeFraction);
     953             :                     }
     954           0 :                     RunTimeFraction = 1.0;
     955             :                 }
     956             : 
     957             :                 // ElectricPowerOnCycle = Water removal volumetric rate (L/day) / (Energy Factor(L/kWh) * 24 hrs/day ) * 1000 Wh/kWh
     958        2371 :                 ElectricPowerOnCycle = WaterRemovalVolRate / (EnergyFactor * 24.0) * 1000.0; // Watts
     959             :                 // ElectricPowerAvg     = ElectricPowerOnCycle * RTF + (1-RTF)*OffCycleParsiticLoad
     960        2371 :                 ElectricPowerAvg =
     961        2371 :                     ElectricPowerOnCycle * RunTimeFraction +
     962        2371 :                     (1.0 - RunTimeFraction) * state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OffCycleParasiticLoad; // average Watts
     963             :             }
     964             : 
     965        2371 :             LatentOutput = WaterRemovalMassRate * PLR; // Average moisture removal rate, kg/s, for this timestep
     966        2371 :             hfg = PsyHfgAirFnWTdb(InletAirHumRat, InletAirTemp);
     967        2371 :             SensibleOutput = (LatentOutput * hfg) + ElectricPowerAvg; // Average sensible output, Watts
     968             :             // Send SensibleOutput to zone air heat balance via SysDepZoneLoads in ZoneEquipmentManager
     969             : 
     970        2371 :             state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRate = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).RatedAirMassFlow * PLR;
     971        2371 :             AirMassFlowRate = state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRate; // Average air mass flow for this timestep
     972        2371 :             Cp = PsyCpAirFnW(InletAirHumRat);                                          // Heat capacity of air
     973        2371 :             if (AirMassFlowRate > 0.0 && Cp > 0.0) {
     974        4742 :                 OutletAirTemp = InletAirTemp + (ElectricPowerOnCycle + (WaterRemovalMassRate * hfg)) /
     975        2371 :                                                    (state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).RatedAirMassFlow * Cp);
     976        2371 :                 OutletAirHumRat = InletAirHumRat - LatentOutput / AirMassFlowRate;
     977             :             } else {
     978           0 :                 OutletAirTemp = InletAirTemp;
     979           0 :                 OutletAirHumRat = InletAirHumRat;
     980             :             }
     981             : 
     982             :         } else {
     983             : 
     984             :             // No load or not available or inlet air temps beyond min/max limits, then set outlet conditions
     985             :             // equal to inlet conditions and PLR = RTF = 0.0
     986       48618 :             OutletAirTemp = InletAirTemp;
     987       48618 :             OutletAirHumRat = InletAirHumRat;
     988       48618 :             PLR = 0.0;
     989       48618 :             RunTimeFraction = 0.0;
     990       48618 :             state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRate = 0.0;
     991             :             // If available but didn't operate, then set electric power = off cycle parasitic load.
     992             :             // Else, electric power = 0.0
     993       48618 :             if (GetCurrentScheduleValue(state, state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).SchedPtr) > 0.0) {
     994       48618 :                 ElectricPowerAvg =
     995       48618 :                     state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OffCycleParasiticLoad; // off cycle parasitic is on entire timestep
     996             :             } else {
     997           0 :                 ElectricPowerAvg = 0.0;
     998             :             }
     999             :         }
    1000             : 
    1001       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OutletAirTemp =
    1002             :             OutletAirTemp; // Update report variable here. Node outlet Temp set equal
    1003             :         //   to Node inlet Temp in Update subroutine
    1004       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OutletAirHumRat =
    1005             :             OutletAirHumRat; // Store in structure, updated outlet node in Update subroutine
    1006             : 
    1007             :         // Use inlet air temperature in outlet air enthalpy calculation... since the sensible heat output
    1008             :         // from the dehumidifier is being sent directly to the zone air heat balance for next hvac simulation time step
    1009       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OutletAirEnthalpy = PsyHFnTdbW(InletAirTemp, OutletAirHumRat);
    1010             : 
    1011       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).SensHeatingRate =
    1012       50989 :             SensibleOutput; // Report variable update, W,  avg sens output when unit is 'on'
    1013       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).WaterRemovalRate = LatentOutput; // Report variable update, kg/s
    1014       50989 :         LatentOutput = -LatentOutput; // change sign... negative is dehumidification in zone air balance
    1015             : 
    1016       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OffCycleParasiticElecPower =
    1017       50989 :             (1.0 - RunTimeFraction) * state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OffCycleParasiticLoad;
    1018       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).ElecPower = ElectricPowerAvg;
    1019       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).DehumidPLR = PLR;
    1020       50989 :         state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).DehumidRTF = RunTimeFraction;
    1021       50989 :     }
    1022             : 
    1023       50989 :     void UpdateZoneDehumidifier(EnergyPlusData &state, int const ZoneDehumNum) // Number of the current zone dehumidifier being simulated
    1024             :     {
    1025             : 
    1026             :         // SUBROUTINE INFORMATION:
    1027             :         //       AUTHOR         Don Shirey, FSEC
    1028             :         //       DATE WRITTEN   August 2009
    1029             :         //       MODIFIED       na
    1030             :         //       RE-ENGINEERED  na
    1031             : 
    1032             :         // PURPOSE OF THIS SUBROUTINE:
    1033             :         // This subroutine is for passing results to the outlet air node.
    1034             : 
    1035             :         // METHODOLOGY EMPLOYED:
    1036             :         // na
    1037             : 
    1038             :         // REFERENCES:
    1039             :         // na
    1040             : 
    1041             :         // Using/Aliasing
    1042             :         // Locals
    1043             :         // SUBROUTINE ARGUMENT DEFINITIONS:
    1044             : 
    1045             :         // SUBROUTINE PARAMETER DEFINITIONS:
    1046             :         // na
    1047             : 
    1048             :         // INTERFACE BLOCK SPECIFICATIONS:
    1049             :         // na
    1050             : 
    1051             :         // DERIVED TYPE DEFINITIONS:
    1052             :         // na
    1053             : 
    1054             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1055             :         int AirInletNodeNum;  // Node number corresponding to the air entering dehumidifier
    1056             :         int AirOutletNodeNum; // Node number corresponding to the air leaving dehumidifier
    1057             : 
    1058       50989 :         AirInletNodeNum = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).AirInletNodeNum;
    1059       50989 :         AirOutletNodeNum = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).AirOutletNodeNum;
    1060             : 
    1061             :         // Changed outlet node properties
    1062       50989 :         state.dataLoopNodes->Node(AirOutletNodeNum).Enthalpy = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OutletAirEnthalpy;
    1063       50989 :         state.dataLoopNodes->Node(AirOutletNodeNum).HumRat = state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumNum).OutletAirHumRat;
    1064             :         // Set outlet temp = inlet temp; send excess sensible heat directly to air heat balance
    1065             :         // (via SensibleOutput and QSensOut) for the next hvac simulation time step.
    1066       50989 :         state.dataLoopNodes->Node(AirOutletNodeNum).Temp = state.dataLoopNodes->Node(AirInletNodeNum).Temp;
    1067             : 
    1068             :         // Pass through output node properties
    1069       50989 :         state.dataLoopNodes->Node(AirOutletNodeNum).Quality = state.dataLoopNodes->Node(AirInletNodeNum).Quality;
    1070       50989 :         state.dataLoopNodes->Node(AirOutletNodeNum).Press = state.dataLoopNodes->Node(AirInletNodeNum).Press;
    1071       50989 :         state.dataLoopNodes->Node(AirOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRate;
    1072       50989 :         state.dataLoopNodes->Node(AirOutletNodeNum).MassFlowRateMin = state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRateMin;
    1073       50989 :         state.dataLoopNodes->Node(AirOutletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRateMax;
    1074       50989 :         state.dataLoopNodes->Node(AirOutletNodeNum).MassFlowRateMinAvail = state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRateMinAvail;
    1075       50989 :         state.dataLoopNodes->Node(AirOutletNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(AirInletNodeNum).MassFlowRateMaxAvail;
    1076             : 
    1077       50989 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1078           0 :             state.dataLoopNodes->Node(AirOutletNodeNum).CO2 = state.dataLoopNodes->Node(AirInletNodeNum).CO2;
    1079             :         }
    1080       50989 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1081           0 :             state.dataLoopNodes->Node(AirOutletNodeNum).GenContam = state.dataLoopNodes->Node(AirInletNodeNum).GenContam;
    1082             :         }
    1083       50989 :     }
    1084             : 
    1085       50989 :     void ReportZoneDehumidifier(EnergyPlusData &state, int const DehumidNum) // Index of the current zone dehumidifier being simulated
    1086             :     {
    1087             : 
    1088             :         // SUBROUTINE INFORMATION:
    1089             :         //       AUTHOR         Don Shirey, FSEC
    1090             :         //       DATE WRITTEN   August 2009
    1091             :         //       MODIFIED       na
    1092             :         //       RE-ENGINEERED  na
    1093             : 
    1094             :         // PURPOSE OF THIS SUBROUTINE:
    1095             :         // Fills some of the report variables for the zone dehumidifiers
    1096             : 
    1097             :         // Using/Aliasing
    1098       50989 :         Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    1099             :         using Psychrometrics::RhoH2O;
    1100             : 
    1101             :         // DERIVED TYPE DEFINITIONS:
    1102             :         // na
    1103             : 
    1104             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1105             :         Real64 RhoWater;      // Density of condensate (water) being removed (kg/m3)
    1106             :         Real64 InletAirTemp;  // Dry-bulb temperature of air entering the dehumidifier (C)
    1107             :         Real64 OutletAirTemp; // Dry-bulb temperature of air leaving the dehumidifier (C)
    1108             :         int AirInletNodeNum;  // Node number corresponding to the air entering dehumidifier
    1109             : 
    1110       50989 :         state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).SensHeatingEnergy =
    1111       50989 :             state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).SensHeatingRate * TimeStepSysSec;
    1112       50989 :         state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).WaterRemoved =
    1113       50989 :             state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).WaterRemovalRate * TimeStepSysSec;
    1114       50989 :         state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).ElecConsumption =
    1115       50989 :             state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).ElecPower * TimeStepSysSec;
    1116       50989 :         state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).OffCycleParasiticElecCons =
    1117       50989 :             state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).OffCycleParasiticElecPower * TimeStepSysSec;
    1118             : 
    1119             :         // Dehumidifier water collection to water storage tank (if needed)
    1120       50989 :         if (state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).CondensateCollectMode == CondensateOutlet::ToTank) {
    1121             :             // Calculate and report condensation rate (how much water extracted from the air stream)
    1122             :             // Volumetric flow of water in m3/s for water system interactions
    1123             : 
    1124           0 :             AirInletNodeNum = state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).AirInletNodeNum;
    1125           0 :             InletAirTemp = state.dataLoopNodes->Node(AirInletNodeNum).Temp;
    1126           0 :             OutletAirTemp = max((InletAirTemp - 11.0), 1.0); // Assume coil outlet air is 11C (20F) lower than inlet air temp
    1127           0 :             RhoWater = RhoH2O(OutletAirTemp);                // Density of water, minimum temp = 1.0 C
    1128             : 
    1129           0 :             if (RhoWater > 0.0) {
    1130           0 :                 state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).DehumidCondVolFlowRate =
    1131           0 :                     state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).WaterRemovalRate / RhoWater;
    1132             :             }
    1133             : 
    1134           0 :             state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).DehumidCondVol =
    1135           0 :                 state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).DehumidCondVolFlowRate * TimeStepSysSec;
    1136             : 
    1137           0 :             state.dataWaterData->WaterStorage(state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).CondensateTankID)
    1138           0 :                 .VdotAvailSupply(state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).CondensateTankSupplyARRID) =
    1139           0 :                 state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).DehumidCondVolFlowRate;
    1140             :             // Assume water outlet temp = air outlet temp.... same assumption in other places in code (e.g., water coil component)
    1141           0 :             state.dataWaterData->WaterStorage(state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).CondensateTankID)
    1142           0 :                 .TwaterSupply(state.dataZoneDehumidifier->ZoneDehumid(DehumidNum).CondensateTankSupplyARRID) = OutletAirTemp;
    1143             :         }
    1144       50989 :     }
    1145             : 
    1146          79 :     bool GetZoneDehumidifierNodeNumber(EnergyPlusData &state, int const NodeNumber) // Node being tested
    1147             :     {
    1148             : 
    1149             :         // FUNCTION INFORMATION:
    1150             :         //       AUTHOR         Lixing Gu
    1151             :         //       DATE WRITTEN   August 2009
    1152             :         //       MODIFIED       na
    1153             :         //       RE-ENGINEERED  na
    1154             : 
    1155             :         // PURPOSE OF THIS FUNCTION:
    1156             :         // After making sure get input is done, the node number of indicated
    1157             :         // zone dehumidifier is returned.
    1158             : 
    1159             :         // Return value
    1160             :         bool FindZoneDehumidifierNodeNumber; // Zone Dehumidifier Node Number Check
    1161             : 
    1162          79 :         if (state.dataZoneDehumidifier->GetInputFlag) {
    1163          22 :             GetZoneDehumidifierInput(state);
    1164          22 :             state.dataZoneDehumidifier->GetInputFlag = false;
    1165             :         }
    1166             : 
    1167          79 :         FindZoneDehumidifierNodeNumber = false;
    1168          86 :         for (int ZoneDehumidIndex = 1; ZoneDehumidIndex <= (int)state.dataZoneDehumidifier->ZoneDehumid.size(); ++ZoneDehumidIndex) {
    1169           9 :             if (NodeNumber == state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).AirInletNodeNum) {
    1170           1 :                 FindZoneDehumidifierNodeNumber = true;
    1171           1 :                 break;
    1172             :             }
    1173           8 :             if (NodeNumber == state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidIndex).AirOutletNodeNum) {
    1174           1 :                 FindZoneDehumidifierNodeNumber = true;
    1175           1 :                 break;
    1176             :             }
    1177             :         }
    1178             : 
    1179          79 :         return FindZoneDehumidifierNodeNumber;
    1180             :     }
    1181             : 
    1182           0 :     int getZoneDehumidifierIndex(EnergyPlusData &state, std::string_view CompName)
    1183             :     {
    1184           0 :         if (state.dataZoneDehumidifier->GetInputFlag) {
    1185           0 :             GetZoneDehumidifierInput(state);
    1186           0 :             state.dataZoneDehumidifier->GetInputFlag = false;
    1187             :         }
    1188             : 
    1189           0 :         for (int ZoneDehumidNum = 1; ZoneDehumidNum <= (int)state.dataZoneDehumidifier->ZoneDehumid.size(); ++ZoneDehumidNum) {
    1190           0 :             if (Util::SameString(state.dataZoneDehumidifier->ZoneDehumid(ZoneDehumidNum).Name, CompName)) {
    1191           0 :                 return ZoneDehumidNum;
    1192             :             }
    1193             :         }
    1194             : 
    1195           0 :         return 0;
    1196             :     }
    1197             : 
    1198             : } // namespace ZoneDehumidifier
    1199             : 
    1200             : } // namespace EnergyPlus

Generated by: LCOV version 1.14