LCOV - code coverage report
Current view: top level - EnergyPlus - ZoneDehumidifier.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 63.4 % 429 272
Test Date: 2025-05-22 16:09:37 Functions: 100.0 % 8 8

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

Generated by: LCOV version 2.0-1