LCOV - code coverage report
Current view: top level - EnergyPlus - MoistureBalanceEMPDManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 82.0 % 306 251
Test Date: 2025-06-02 07:23:51 Functions: 83.3 % 6 5

            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              : #include <string>
      51              : 
      52              : // ObjexxFCL Headers
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/Construction.hh>
      57              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      58              : #include <EnergyPlus/DataEnvironment.hh>
      59              : #include <EnergyPlus/DataHeatBalance.hh>
      60              : #include <EnergyPlus/DataIPShortCuts.hh>
      61              : #include <EnergyPlus/DataMoistureBalance.hh>
      62              : #include <EnergyPlus/DataMoistureBalanceEMPD.hh>
      63              : #include <EnergyPlus/DataSurfaces.hh>
      64              : #include <EnergyPlus/General.hh>
      65              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      66              : #include <EnergyPlus/Material.hh>
      67              : #include <EnergyPlus/MoistureBalanceEMPDManager.hh>
      68              : #include <EnergyPlus/OutputProcessor.hh>
      69              : #include <EnergyPlus/Psychrometrics.hh>
      70              : #include <EnergyPlus/UtilityRoutines.hh>
      71              : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      72              : 
      73              : namespace EnergyPlus::MoistureBalanceEMPDManager {
      74              : 
      75              : // Module containing the routines to calculate moisture adsorption and desorption
      76              : // at interior wall surfaces
      77              : 
      78              : // MODULE INFORMATION:
      79              : //   Authors:        Muthusamy Swami and Lixing Gu
      80              : //   Date written:   August, 1999
      81              : //   Modified:       na
      82              : //   Re-engineered:  Jason Woods and Noel Merket, August 2015
      83              : 
      84              : // PURPOSE OF THIS MODULE:
      85              : // To calculate moisture adsorption and desorption at interior wall surfaces
      86              : // using EMPD model (Effective Moisture Penetration Depth) developed by
      87              : // Florida Solar Energy Center. Input consists of interior surface temperatures
      88              : // and sorption curve of interior layer materials. Output consists of moisture
      89              : // fluxes from wall interior surfaces, which will be used in zone moisture balance.
      90              : 
      91              : // METHODOLOGY EMPLOYED:
      92              : // Add something
      93              : // EMPD is a simplified method of analyzing moisture transport in buildings and
      94              : // is easy to incorporate into existing building energy analysis computer codes.
      95              : // The components of the moisture balance equation involving moisture adsorption
      96              : // and desorption are described in detail where the concept of EMPD is discussed.
      97              : // The assumptions. parameters required, and limitations of the model are also discussed.
      98              : // Results of simulation using the model and comparison with measured data are given.
      99              : // Data of isotherms compiled from the literature of some commonly used building materials are also given.
     100              : 
     101              : // REFERENCES:
     102              : // Kerestecioglu A A., Swami M V., Kamel A A., "Theoretical and computational
     103              : // investigation of simultaneous heat and moisture transfer in buildings: 'Effective
     104              : // penetration depth' theory," ASHRAE Trans., 1990, Vol. 96, Part 1, 447-454
     105              : 
     106              : // Using/Aliasing
     107              : using namespace DataHeatBalance;
     108              : using namespace DataMoistureBalanceEMPD;
     109              : 
     110            0 : Real64 MaterialEMPD::calcDepthFromPeriod(EnergyPlusData &state,
     111              :                                          Real64 const period // in seconds
     112              : )
     113              : {
     114              :     // Assume T, RH, P
     115            0 :     Real64 constexpr T = 24.0; // C
     116            0 :     Real64 constexpr RH = 0.45;
     117            0 :     Real64 constexpr P_amb = 101325; // Pa
     118              : 
     119              :     // Calculate saturation vapor pressure at assumed temperature
     120            0 :     Real64 const PV_sat = Psychrometrics::PsyPsatFnTemp(state, T, "CalcDepthFromPeriod");
     121              : 
     122              :     // Calculate slope of moisture sorption curve
     123            0 :     Real64 const slope_MC = this->moistACoeff * this->moistBCoeff * std::pow(RH, this->moistBCoeff - 1) +
     124            0 :                             this->moistCCoeff * this->moistDCoeff * std::pow(RH, this->moistDCoeff - 1);
     125              : 
     126              :     // Equation for the diffusivity of water vapor in air
     127            0 :     Real64 const diffusivity_air = 2.0e-7 * std::pow(T + 273.15, 0.81) / P_amb;
     128              : 
     129              :     // Convert mu to diffusivity [kg/m^2-s-Pa]
     130            0 :     Real64 const EMPDdiffusivity = diffusivity_air / this->mu;
     131              : 
     132              :     // Calculate penetration depth
     133            0 :     return std::sqrt(EMPDdiffusivity * PV_sat * period / (this->Density * slope_MC * Constant::Pi));
     134              : }
     135              : 
     136            2 : void GetMoistureBalanceEMPDInput(EnergyPlusData &state)
     137              : {
     138              : 
     139              :     // SUBROUTINE INFORMATION:
     140              :     //       AUTHOR         Muthusamy V. Swami and Lixing Gu
     141              :     //       DATE WRITTEN   August 2000
     142              :     //       MODIFIED       na
     143              :     //       RE-ENGINEERED  na
     144              : 
     145              :     // PURPOSE OF THIS SUBROUTINE:
     146              :     // This subroutine is the main driver for initializations within the
     147              :     // heat balance using the EMPD model.
     148              : 
     149              :     static constexpr std::string_view routineName = "GetMoistureBalanceEMPDInput";
     150              : 
     151              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     152              :     int IOStat;                       // IO Status when calling get input subroutine
     153            2 :     Array1D_string MaterialNames(3);  // Number of Material Alpha names defined
     154              :     int MaterialNumAlpha;             // Number of material alpha names being passed
     155              :     int MaterialNumProp;              // Number of material properties being passed
     156            2 :     Array1D<Real64> MaterialProps(9); // Temporary array to transfer material properties
     157            2 :     bool ErrorsFound(false);          // If errors detected in input
     158              : 
     159              :     int EMPDMat;           // EMPD Moisture Material additional properties for each base material
     160            2 :     Array1D_bool EMPDzone; // EMPD property check for each zone
     161              : 
     162            2 :     auto &s_ip = state.dataInputProcessing->inputProcessor;
     163            2 :     auto &s_ipsc = state.dataIPShortCut;
     164            2 :     auto &s_mat = state.dataMaterial;
     165              : 
     166              :     // Load the additional EMPD Material properties
     167            2 :     s_ipsc->cCurrentModuleObject = "MaterialProperty:MoisturePenetrationDepth:Settings";
     168            2 :     EMPDMat = s_ip->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     169              : 
     170            2 :     if (EMPDMat == 0) {
     171            0 :         ShowSevereError(state, format("EMPD Solution requested, but no \"{}\" objects were found.", s_ipsc->cCurrentModuleObject));
     172            0 :         ErrorsFound = true;
     173              :     }
     174              : 
     175            8 :     for (int Loop = 1; Loop <= EMPDMat; ++Loop) {
     176              : 
     177              :         // Call Input Get routine to retrieve material data
     178           18 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     179            6 :                                                                  s_ipsc->cCurrentModuleObject,
     180              :                                                                  Loop,
     181              :                                                                  MaterialNames,
     182              :                                                                  MaterialNumAlpha,
     183              :                                                                  MaterialProps,
     184              :                                                                  MaterialNumProp,
     185              :                                                                  IOStat,
     186            6 :                                                                  s_ipsc->lNumericFieldBlanks,
     187            6 :                                                                  s_ipsc->lAlphaFieldBlanks,
     188            6 :                                                                  s_ipsc->cAlphaFieldNames,
     189            6 :                                                                  s_ipsc->cNumericFieldNames);
     190              : 
     191            6 :         ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, MaterialNames(1)};
     192              : 
     193              :         // Load the material derived type from the input data.
     194            6 :         int matNum = Material::GetMaterialNum(state, MaterialNames(1));
     195            6 :         if (matNum == 0) {
     196            0 :             ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(1), MaterialNames(1));
     197            0 :             ErrorsFound = true;
     198            0 :             continue;
     199              :         }
     200              : 
     201            6 :         auto *mat = s_mat->materials(matNum);
     202            6 :         if (mat->group != Material::Group::Regular || mat->ROnly) {
     203            0 :             ShowSevereCustom(state, eoh, "Reference Material is not appropriate type for EMPD properties, must have regular properties (L,Cp,K,D)");
     204            0 :             ErrorsFound = true;
     205            0 :             continue;
     206              :         }
     207              : 
     208              :         // This is a regular material and we need to replace/upgrade it with an opaque material (subclass)
     209            6 :         auto *matEMPD = new MaterialEMPD;
     210            6 :         matEMPD->MaterialBase::operator=(*mat); // deep copy parent object (explicitly call operator=)
     211              : 
     212            6 :         delete mat;
     213            6 :         s_mat->materials(matNum) = matEMPD; // This should work, material name remains the same
     214              : 
     215            6 :         matEMPD->hasEMPD = true;
     216              : 
     217              :         // Once the material derived type number is found then load the additional moisture material properties
     218            6 :         matEMPD->mu = MaterialProps(1);
     219            6 :         matEMPD->moistACoeff = MaterialProps(2);
     220            6 :         matEMPD->moistBCoeff = MaterialProps(3);
     221            6 :         matEMPD->moistCCoeff = MaterialProps(4);
     222            6 :         matEMPD->moistDCoeff = MaterialProps(5);
     223            6 :         if (s_ipsc->lNumericFieldBlanks(6) || MaterialProps(6) == Constant::AutoCalculate) {
     224            0 :             matEMPD->surfaceDepth = matEMPD->calcDepthFromPeriod(state, 24 * 3600); // 1 day
     225              :         } else {
     226            6 :             matEMPD->surfaceDepth = MaterialProps(6);
     227              :         }
     228            6 :         if (s_ipsc->lNumericFieldBlanks(7) || MaterialProps(7) == Constant::AutoCalculate) {
     229            0 :             matEMPD->deepDepth = matEMPD->calcDepthFromPeriod(state, 21 * 24 * 3600); // 3 weeks
     230              :         } else {
     231            6 :             matEMPD->deepDepth = MaterialProps(7);
     232              :         }
     233            6 :         matEMPD->coatingThickness = MaterialProps(8);
     234            6 :         matEMPD->muCoating = MaterialProps(9);
     235              : 
     236            6 :         if (matEMPD->deepDepth <= matEMPD->surfaceDepth && matEMPD->deepDepth != 0.0) {
     237            0 :             ShowWarningError(state, format("{}: material=\"{}\"", s_ipsc->cCurrentModuleObject, matEMPD->Name));
     238            0 :             ShowContinueError(state, "Deep-layer penetration depth should be zero or greater than the surface-layer penetration depth.");
     239              :         }
     240              :     }
     241              : 
     242              :     // Ensure at least one interior EMPD surface for each zone
     243            2 :     EMPDzone.dimension(state.dataGlobal->NumOfZones, false);
     244           58 :     for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     245           56 :         auto const &surf = state.dataSurface->Surface(SurfNum);
     246           56 :         if (!surf.HeatTransSurf || surf.Class == DataSurfaces::SurfaceClass::Window) {
     247           10 :             continue; // Heat transfer surface only and not a window
     248              :         }
     249           46 :         if (surf.HeatTransferAlgorithm != DataSurfaces::HeatTransferModel::EMPD) {
     250            3 :             continue;
     251              :         }
     252              : 
     253           43 :         auto const &constr = state.dataConstruction->Construct(surf.Construction);
     254           43 :         auto const *mat = dynamic_cast<const MaterialEMPD *>(s_mat->materials(constr.LayerPoint(constr.TotLayers)));
     255              :         // assert(mat != nullptr);
     256              : 
     257           43 :         if (mat && mat->mu > 0.0 && surf.Zone > 0) {
     258           43 :             EMPDzone(surf.Zone) = true;
     259              :         } else {
     260            0 :             ++state.dataMoistureBalEMPD->ErrCount;
     261            0 :             if (state.dataMoistureBalEMPD->ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
     262            0 :                 ShowMessage(state, "GetMoistureBalanceEMPDInput: EMPD properties are not assigned to the inside layer of Surfaces");
     263            0 :                 ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
     264              :             }
     265            0 :             if (state.dataGlobal->DisplayExtraWarnings) {
     266            0 :                 ShowMessage(state,
     267            0 :                             format("GetMoistureBalanceEMPDInput: EMPD properties are not assigned to the inside layer in Surface={}", surf.Name));
     268            0 :                 ShowContinueError(state, format("with Construction={}", constr.Name));
     269              :             }
     270              :         }
     271              : 
     272           43 :         if (constr.TotLayers == 1) {
     273           15 :             continue; // One layer construction
     274              :         }
     275              : 
     276              :         // Multiple layer construction
     277           28 :         auto const *mat1 = s_mat->materials(constr.LayerPoint(1));
     278           28 :         if (mat1->hasEMPD && surf.ExtBoundCond <= 0) { // The external layer is not exposed to zone
     279            0 :             ShowSevereError(state, format("{}: EMPD properties are assigned to the outside layer in Construction = {}", routineName, constr.Name));
     280            0 :             ShowContinueError(state, format("..Outside layer material with EMPD properties = {}", mat1->Name));
     281            0 :             ShowContinueError(state, "..A material with EMPD properties must be assigned to the inside layer of a construction.");
     282            0 :             ErrorsFound = true;
     283            0 :             continue;
     284              :         }
     285              : 
     286           68 :         for (int Layer = 2; Layer <= constr.TotLayers - 1; ++Layer) {
     287           40 :             auto const *matL = s_mat->materials(constr.LayerPoint(Layer));
     288           40 :             if (matL->hasEMPD) {
     289            0 :                 ShowSevereError(state, format("{}: EMPD properties are assigned to a middle layer in Construction = {}", routineName, constr.Name));
     290            0 :                 ShowContinueError(state, format("..Middle layer material with EMPD properties = {}", matL->Name));
     291            0 :                 ShowContinueError(state, "..A material with EMPD properties must be assigned to the inside layer of a construction.");
     292            0 :                 ErrorsFound = true;
     293              :             }
     294              :         }
     295              :     }
     296              : 
     297            9 :     for (int Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
     298            7 :         if (!EMPDzone(Loop)) {
     299            0 :             ShowSevereError(state,
     300            0 :                             format("{}: None of the constructions for zone = {} has an inside layer with EMPD properties",
     301              :                                    routineName,
     302            0 :                                    state.dataHeatBal->Zone(Loop).Name));
     303            0 :             ShowContinueError(state, "..For each zone, the inside layer of at least one construction must have EMPD properties");
     304            0 :             ErrorsFound = true;
     305              :         }
     306              :     }
     307              : 
     308            2 :     EMPDzone.deallocate();
     309              : 
     310            2 :     ReportMoistureBalanceEMPD(state);
     311              : 
     312            2 :     if (ErrorsFound) {
     313            0 :         ShowFatalError(state, "GetMoistureBalanceEMPDInput: Errors found getting EMPD material properties, program terminated.");
     314              :     }
     315            2 : }
     316              : 
     317           14 : void InitMoistureBalanceEMPD(EnergyPlusData &state)
     318              : {
     319              : 
     320              :     // SUBROUTINE INFORMATION:
     321              :     //   Authors:        Muthusamy Swami and Lixing Gu
     322              :     //   Date written:   August, 1999
     323              :     //   Modified:       na
     324              :     //   Re-engineered:  na
     325              : 
     326              :     // PURPOSE OF THIS SUBROUTINE:
     327              :     // Create dynamic array for surface moisture calculation
     328              : 
     329              :     // USE STATEMENTS:
     330              :     using Psychrometrics::PsyRhovFnTdbRh;
     331              :     using Psychrometrics::PsyRhovFnTdbWPb_fast;
     332              : 
     333           14 :     if (state.dataMoistureBalEMPD->InitEnvrnFlag) {
     334            2 :         state.dataMstBalEMPD->RVSurfaceOld.allocate(state.dataSurface->TotSurfaces);
     335            2 :         state.dataMstBalEMPD->RVSurface.allocate(state.dataSurface->TotSurfaces);
     336            2 :         state.dataMstBalEMPD->HeatFluxLatent.allocate(state.dataSurface->TotSurfaces);
     337            2 :         state.dataMoistureBalEMPD->EMPDReportVars.allocate(state.dataSurface->TotSurfaces);
     338            2 :         state.dataMstBalEMPD->RVSurfLayer.allocate(state.dataSurface->TotSurfaces);
     339            2 :         state.dataMstBalEMPD->RVSurfLayerOld.allocate(state.dataSurface->TotSurfaces);
     340            2 :         state.dataMstBalEMPD->RVDeepLayer.allocate(state.dataSurface->TotSurfaces);
     341            2 :         state.dataMstBalEMPD->RVdeepOld.allocate(state.dataSurface->TotSurfaces);
     342            2 :         state.dataMstBalEMPD->RVwall.allocate(state.dataSurface->TotSurfaces);
     343              :     }
     344              : 
     345          538 :     for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     346          524 :         int ZoneNum = state.dataSurface->Surface(SurfNum).Zone;
     347          524 :         if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) {
     348           40 :             continue;
     349              :         }
     350              :         Real64 const rv_air_in_initval =
     351          484 :             min(PsyRhovFnTdbWPb_fast(state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT,
     352          484 :                                      max(state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).airHumRat, 1.0e-5),
     353          484 :                                      state.dataEnvrn->OutBaroPress),
     354          484 :                 PsyRhovFnTdbRh(state, state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT, 1.0, "InitMoistureBalanceEMPD"));
     355          484 :         state.dataMstBalEMPD->RVSurfaceOld(SurfNum) = rv_air_in_initval;
     356          484 :         state.dataMstBalEMPD->RVSurface(SurfNum) = rv_air_in_initval;
     357          484 :         state.dataMstBalEMPD->RVSurfLayer(SurfNum) = rv_air_in_initval;
     358          484 :         state.dataMstBalEMPD->RVSurfLayerOld(SurfNum) = rv_air_in_initval;
     359          484 :         state.dataMstBalEMPD->RVDeepLayer(SurfNum) = rv_air_in_initval;
     360          484 :         state.dataMstBalEMPD->RVdeepOld(SurfNum) = rv_air_in_initval;
     361          484 :         state.dataMstBalEMPD->RVwall(SurfNum) = rv_air_in_initval;
     362              :     }
     363           14 :     if (!state.dataMoistureBalEMPD->InitEnvrnFlag) {
     364           12 :         return;
     365              :     }
     366              :     // Initialize the report variable
     367              : 
     368            2 :     GetMoistureBalanceEMPDInput(state);
     369              : 
     370           58 :     for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     371           56 :         if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) {
     372           10 :             continue;
     373              :         }
     374           52 :         if (state.dataSurface->Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) {
     375            6 :             continue;
     376              :         }
     377           46 :         EMPDReportVarsData &rvd = state.dataMoistureBalEMPD->EMPDReportVars(SurfNum);
     378           46 :         const std::string surf_name = state.dataSurface->Surface(SurfNum).Name;
     379           92 :         SetupOutputVariable(state,
     380              :                             "EMPD Surface Inside Face Water Vapor Density",
     381              :                             Constant::Units::kg_m3,
     382           46 :                             rvd.rv_surface,
     383              :                             OutputProcessor::TimeStepType::Zone,
     384              :                             OutputProcessor::StoreType::Average,
     385              :                             surf_name);
     386           92 :         SetupOutputVariable(state,
     387              :                             "EMPD Surface Layer Moisture Content",
     388              :                             Constant::Units::kg_m3,
     389           46 :                             rvd.u_surface_layer,
     390              :                             OutputProcessor::TimeStepType::Zone,
     391              :                             OutputProcessor::StoreType::Average,
     392              :                             surf_name);
     393           92 :         SetupOutputVariable(state,
     394              :                             "EMPD Deep Layer Moisture Content",
     395              :                             Constant::Units::kg_m3,
     396           46 :                             rvd.u_deep_layer,
     397              :                             OutputProcessor::TimeStepType::Zone,
     398              :                             OutputProcessor::StoreType::Average,
     399              :                             surf_name);
     400           92 :         SetupOutputVariable(state,
     401              :                             "EMPD Surface Layer Equivalent Relative Humidity",
     402              :                             Constant::Units::Perc,
     403           46 :                             rvd.RH_surface_layer,
     404              :                             OutputProcessor::TimeStepType::Zone,
     405              :                             OutputProcessor::StoreType::Average,
     406              :                             surf_name);
     407           92 :         SetupOutputVariable(state,
     408              :                             "EMPD Deep Layer Equivalent Relative Humidity",
     409              :                             Constant::Units::Perc,
     410           46 :                             rvd.RH_deep_layer,
     411              :                             OutputProcessor::TimeStepType::Zone,
     412              :                             OutputProcessor::StoreType::Average,
     413              :                             surf_name);
     414           92 :         SetupOutputVariable(state,
     415              :                             "EMPD Surface Layer Equivalent Humidity Ratio",
     416              :                             Constant::Units::kgWater_kgDryAir,
     417           46 :                             rvd.w_surface_layer,
     418              :                             OutputProcessor::TimeStepType::Zone,
     419              :                             OutputProcessor::StoreType::Average,
     420              :                             surf_name);
     421           92 :         SetupOutputVariable(state,
     422              :                             "EMPD Deep Layer Equivalent Humidity Ratio",
     423              :                             Constant::Units::kgWater_kgDryAir,
     424           46 :                             rvd.w_deep_layer,
     425              :                             OutputProcessor::TimeStepType::Zone,
     426              :                             OutputProcessor::StoreType::Average,
     427              :                             surf_name);
     428           92 :         SetupOutputVariable(state,
     429              :                             "EMPD Surface Moisture Flux to Zone",
     430              :                             Constant::Units::kg_m2s,
     431           46 :                             rvd.mass_flux_zone,
     432              :                             OutputProcessor::TimeStepType::Zone,
     433              :                             OutputProcessor::StoreType::Average,
     434              :                             surf_name);
     435           92 :         SetupOutputVariable(state,
     436              :                             "EMPD Deep Layer Moisture Flux",
     437              :                             Constant::Units::kg_m2s,
     438           46 :                             rvd.mass_flux_deep,
     439              :                             OutputProcessor::TimeStepType::Zone,
     440              :                             OutputProcessor::StoreType::Average,
     441              :                             surf_name);
     442           46 :     }
     443              : 
     444            2 :     if (state.dataMoistureBalEMPD->InitEnvrnFlag) {
     445            2 :         state.dataMoistureBalEMPD->InitEnvrnFlag = false;
     446              :     }
     447              : }
     448              : 
     449       703579 : void CalcMoistureBalanceEMPD(EnergyPlusData &state,
     450              :                              int const SurfNum,
     451              :                              Real64 const SurfTempIn, // INSIDE SURFACE TEMPERATURE at current time step
     452              :                              Real64 const TempZone,   // Zone temperature at current time step.
     453              :                              Real64 &TempSat          // Saturated surface temperature.
     454              : )
     455              : {
     456              : 
     457              :     // SUBROUTINE INFORMATION:
     458              :     //   Authors:        Muthusamy Swami and Lixing Gu
     459              :     //   Date written:   August, 1999
     460              :     //   Modified:       na
     461              :     //   Re-engineered:  na
     462              : 
     463              :     // PURPOSE OF THIS SUBROUTINE:
     464              :     // Calculate surface moisture level using EMPD model
     465              : 
     466              :     // Using/Aliasing
     467              :     using DataMoistureBalanceEMPD::Lam;
     468              :     using Psychrometrics::PsyCpAirFnW;
     469              :     using Psychrometrics::PsyPsatFnTemp;
     470              :     using Psychrometrics::PsyRhFnTdbRhov;
     471              :     using Psychrometrics::PsyRhFnTdbRhovLBnd0C;
     472              :     using Psychrometrics::PsyRhFnTdbWPb;
     473              :     using Psychrometrics::PsyRhoAirFnPbTdbW;
     474              :     using Psychrometrics::PsyRhovFnTdbRh;
     475              :     using Psychrometrics::PsyRhovFnTdbWPb;
     476              :     using Psychrometrics::PsyRhovFnTdbWPb_fast;
     477              :     using Psychrometrics::PsyWFnTdbRhPb;
     478              : 
     479              :     static constexpr std::string_view routineName = "CalcMoistureEMPD";
     480              : 
     481              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     482              :     Real64 hm_deep_layer; // Overall deep-layer transfer coefficient
     483              :     Real64 RSurfaceLayer; // Mass transfer resistance between actual surface and surface layer node
     484              :     Real64 Taver;         // Average zone temperature between current time and previous time
     485              :     //    REAL(r64)    :: Waver     ! Average zone humidity ratio between current time and previous time
     486              :     Real64 RHaver; // Average zone relative humidity {0-1} between current time and previous time
     487              :     Real64 RVaver; // Average zone vapor density
     488              :     Real64 dU_dRH;
     489              :     Real64 PVsurf;        // Surface vapor pressure
     490              :     Real64 PV_surf_layer; // Vapor pressure of surface layer
     491              :     Real64 PV_deep_layer;
     492              :     Real64 PVsat; // saturation vapor pressure at the surface
     493              :     Real64 RH_surf_layer_old;
     494              :     Real64 RH_deep_layer_old;
     495              :     Real64 EMPDdiffusivity;
     496              :     Real64 Rcoating;
     497              :     Real64 RH_surf_layer;
     498              :     Real64 RH_surf_layer_tmp;
     499              :     Real64 RH_deep_layer;
     500              : 
     501       703579 :     auto &s_mat = state.dataMaterial;
     502              : 
     503       703579 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataMoistureBalEMPD->OneTimeFlag) {
     504           14 :         InitMoistureBalanceEMPD(state);
     505           14 :         state.dataMoistureBalEMPD->OneTimeFlag = false;
     506              :     }
     507              : 
     508       703579 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     509       700861 :         state.dataMoistureBalEMPD->OneTimeFlag = true;
     510              :     }
     511              : 
     512       703579 :     auto const &surface(state.dataSurface->Surface(SurfNum));                // input
     513       703579 :     auto &rv_surface(state.dataMstBalEMPD->RVSurface(SurfNum));              // output
     514       703579 :     auto const &rv_surface_old(state.dataMstBalEMPD->RVSurfaceOld(SurfNum)); // input
     515       703579 :     auto const &h_mass_conv_in_fd(state.dataMstBal->HMassConvInFD(SurfNum)); // input
     516       703579 :     auto const &rho_vapor_air_in(state.dataMstBal->RhoVaporAirIn(SurfNum));  // input
     517              :     Real64 RHZone;
     518              :     Real64 mass_flux_surf_deep;
     519              :     Real64 mass_flux_surf_deep_max;
     520              :     Real64 mass_flux_zone_surf;
     521              :     Real64 mass_flux_zone_surf_max;
     522              :     Real64 mass_flux_surf_layer;
     523              :     Real64 mass_flux_deep_layer;
     524              :     Real64 mass_flux_zone;
     525       703579 :     auto &rv_surf_layer(state.dataMstBalEMPD->RVSurfLayer(SurfNum));              // output
     526       703579 :     auto const &rv_surf_layer_old(state.dataMstBalEMPD->RVSurfLayerOld(SurfNum)); // input
     527              :     Real64 hm_surf_layer;
     528       703579 :     auto &rv_deep_layer(state.dataMstBalEMPD->RVDeepLayer(SurfNum));       // output
     529       703579 :     auto const &rv_deep_old(state.dataMstBalEMPD->RVdeepOld(SurfNum));     // input
     530       703579 :     auto &heat_flux_latent(state.dataMstBalEMPD->HeatFluxLatent(SurfNum)); // output
     531              : 
     532       703579 :     heat_flux_latent = 0.0;
     533       703579 :     if (!surface.HeatTransSurf) {
     534            0 :         return;
     535              :     }
     536              : 
     537       703579 :     auto const &constr = state.dataConstruction->Construct(surface.Construction);
     538       703579 :     auto const *mat = dynamic_cast<MaterialEMPD const *>(s_mat->materials(constr.LayerPoint(constr.TotLayers)));
     539       703579 :     assert(mat != nullptr);
     540       703579 :     if (mat->mu <= 0.0) {
     541            0 :         rv_surface =
     542            0 :             PsyRhovFnTdbWPb(TempZone, state.dataZoneTempPredictorCorrector->zoneHeatBalance(surface.Zone).airHumRat, state.dataEnvrn->OutBaroPress);
     543            0 :         return;
     544              :     }
     545              : 
     546       703579 :     Taver = SurfTempIn;
     547              :     // Calculate average vapor density [kg/m^3], and RH for use in material property calculations.
     548       703579 :     RVaver = rv_surface_old;
     549       703579 :     RHaver = RVaver * 461.52 * (Taver + Constant::Kelvin) * std::exp(-23.7093 + 4111.0 / (Taver + 237.7));
     550              : 
     551              :     // Calculate the saturated vapor pressure, surface vapor pressure and dewpoint. Used to check for condensation in HeatBalanceSurfaceManager
     552       703579 :     PVsat = PsyPsatFnTemp(state, Taver, routineName);
     553       703579 :     PVsurf = RHaver * std::exp(23.7093 - 4111.0 / (Taver + 237.7));
     554       703579 :     TempSat = 4111.0 / (23.7093 - std::log(PVsurf)) + 35.45 - Constant::Kelvin;
     555              : 
     556              :     // Convert vapor resistance factor (user input) to diffusivity. Evaluate at local surface temperature.
     557              :     // 2e-7*T^0.81/P = vapor diffusivity in air. [kg/m-s-Pa]
     558              :     // 461.52 = universal gas constant for water [J/kg-K]
     559              :     // EMPDdiffusivity = [m^2/s]
     560       703579 :     EMPDdiffusivity = (2.0e-7 * pow(Taver + Constant::Kelvin, 0.81) / state.dataEnvrn->OutBaroPress) / mat->mu * 461.52 * (Taver + Constant::Kelvin);
     561              : 
     562              :     // Calculate slope of moisture sorption curve at current RH. [kg/kg-RH]
     563       703579 :     dU_dRH = mat->moistACoeff * mat->moistBCoeff * pow(RHaver, mat->moistBCoeff - 1) +
     564       703579 :              mat->moistCCoeff * mat->moistDCoeff * pow(RHaver, mat->moistDCoeff - 1);
     565              : 
     566              :     // Convert vapor density and temperature of zone air to RH
     567       703579 :     RHZone = rho_vapor_air_in * 461.52 * (TempZone + Constant::Kelvin) * std::exp(-23.7093 + 4111.0 / ((TempZone + Constant::Kelvin) - 35.45));
     568              : 
     569              :     // Convert stored vapor density from previous timestep to RH.
     570       703579 :     RH_deep_layer_old = PsyRhFnTdbRhov(state, Taver, rv_deep_old);
     571       703579 :     RH_surf_layer_old = PsyRhFnTdbRhov(state, Taver, rv_surf_layer_old);
     572              : 
     573              :     // If coating vapor resistance factor equals 0, coating resistance is zero (avoid divide by zero).
     574              :     // Otherwise, calculate coating resistance with coating vapor resistance factor and thickness. [s/m]
     575       703579 :     if (mat->muCoating <= 0.0) {
     576       703579 :         Rcoating = 0;
     577              :     } else {
     578            0 :         Rcoating = mat->coatingThickness * mat->muCoating * state.dataEnvrn->OutBaroPress /
     579            0 :                    (2.0e-7 * pow(Taver + Constant::Kelvin, 0.81) * 461.52 * (Taver + Constant::Kelvin));
     580              :     }
     581              : 
     582              :     // Calculate mass-transfer coefficient between zone air and center of surface layer. [m/s]
     583       703579 :     hm_surf_layer = 1.0 / (0.5 * mat->surfaceDepth / EMPDdiffusivity + 1.0 / h_mass_conv_in_fd + Rcoating);
     584              :     // Calculate mass-transfer coefficient between center of surface layer and center of deep layer. [m/s]
     585              :     // If deep layer depth = 0, set mass-transfer coefficient to zero (simulates with no deep layer).
     586       703579 :     if (mat->deepDepth <= 0.0) {
     587       123219 :         hm_deep_layer = 0;
     588              :     } else {
     589       580360 :         hm_deep_layer = 2.0 * EMPDdiffusivity / (mat->deepDepth + mat->surfaceDepth);
     590              :     }
     591              :     // Calculate resistance between surface-layer/air interface and center of surface layer. [s/m]
     592              :     // This is the physical surface of the material.
     593       703579 :     RSurfaceLayer = 1.0 / hm_surf_layer - 1.0 / h_mass_conv_in_fd;
     594              : 
     595              :     // Calculate vapor flux leaving surface layer, entering deep layer, and entering zone.
     596       703579 :     mass_flux_surf_deep_max =
     597       703579 :         mat->deepDepth * mat->Density * dU_dRH * (RH_surf_layer_old - RH_deep_layer_old) / (state.dataGlobal->TimeStepZone * 3600.0);
     598       703579 :     mass_flux_surf_deep = hm_deep_layer * (rv_surf_layer_old - rv_deep_old);
     599       703579 :     if (std::abs(mass_flux_surf_deep_max) < std::abs(mass_flux_surf_deep)) {
     600            0 :         mass_flux_surf_deep = mass_flux_surf_deep_max;
     601              :     }
     602              : 
     603       703579 :     mass_flux_zone_surf_max = mat->surfaceDepth * mat->Density * dU_dRH * (RHZone - RH_surf_layer_old) / (state.dataGlobal->TimeStepZone * 3600.0);
     604       703579 :     mass_flux_zone_surf = hm_surf_layer * (rho_vapor_air_in - rv_surf_layer_old);
     605       703579 :     if (std::abs(mass_flux_zone_surf_max) < std::abs(mass_flux_zone_surf)) {
     606        10758 :         mass_flux_zone_surf = mass_flux_zone_surf_max;
     607              :     }
     608              : 
     609              :     // mass_flux_surf_layer = -mass_flux_zone_surf + mass_flux_surf_deep;
     610              :     // mass_flux_deep_layer = mass_flux_surf_deep;
     611              :     // mass_flux_zone = -mass_flux_zone_surf;
     612              : 
     613       703579 :     mass_flux_surf_layer = hm_surf_layer * (rv_surf_layer_old - rho_vapor_air_in) + hm_deep_layer * (rv_surf_layer_old - rv_deep_old);
     614       703579 :     mass_flux_deep_layer = hm_deep_layer * (rv_surf_layer_old - rv_deep_old);
     615       703579 :     mass_flux_zone = hm_surf_layer * (rv_surf_layer_old - rho_vapor_air_in);
     616              : 
     617              :     // Calculate new surface layer RH using mass balance on surface layer
     618       703579 :     RH_surf_layer_tmp =
     619       703579 :         RH_surf_layer_old + state.dataGlobal->TimeStepZone * 3600.0 * (-mass_flux_surf_layer / (mat->Density * mat->surfaceDepth * dU_dRH));
     620              : 
     621              :     //    RH_surf_layer = RH_surf_layer_tmp;
     622              : 
     623       703579 :     if (RH_surf_layer_old < RH_deep_layer_old && RH_surf_layer_old < RHZone) {
     624       199368 :         if (RHZone > RH_deep_layer_old) {
     625       107065 :             if (RH_surf_layer_tmp > RHZone) {
     626            0 :                 RH_surf_layer = RHZone;
     627              :             } else {
     628       107065 :                 RH_surf_layer = RH_surf_layer_tmp;
     629              :             }
     630        92303 :         } else if (RH_surf_layer_tmp > RH_deep_layer_old) {
     631            0 :             RH_surf_layer = RH_deep_layer_old;
     632              :         } else {
     633        92303 :             RH_surf_layer = RH_surf_layer_tmp;
     634              :         }
     635              : 
     636       504211 :     } else if (RH_surf_layer_old < RH_deep_layer_old && RH_surf_layer_old > RHZone) {
     637       210414 :         if (RH_surf_layer_tmp > RH_deep_layer_old) {
     638          180 :             RH_surf_layer = RH_deep_layer_old;
     639       210234 :         } else if (RH_surf_layer_tmp < RHZone) {
     640         1739 :             RH_surf_layer = RHZone;
     641              :         } else {
     642       208495 :             RH_surf_layer = RH_surf_layer_tmp;
     643              :         }
     644       293797 :     } else if (RH_surf_layer_old > RH_deep_layer_old && RH_surf_layer_old < RHZone) {
     645       114713 :         if (RH_surf_layer_tmp > RHZone) {
     646          598 :             RH_surf_layer = RHZone;
     647       114115 :         } else if (RH_surf_layer_tmp < RH_deep_layer_old) {
     648          593 :             RH_surf_layer = RH_deep_layer_old;
     649              :         } else {
     650       113522 :             RH_surf_layer = RH_surf_layer_tmp;
     651              :         }
     652       179084 :     } else if (RHZone < RH_deep_layer_old) {
     653        90985 :         if (RH_surf_layer_tmp < RHZone) {
     654            1 :             RH_surf_layer = RHZone;
     655              :         } else {
     656        90984 :             RH_surf_layer = RH_surf_layer_tmp;
     657              :         }
     658        88099 :     } else if (RH_surf_layer_tmp < RH_deep_layer_old) {
     659          246 :         RH_surf_layer = RH_deep_layer_old;
     660              :     } else {
     661        87853 :         RH_surf_layer = RH_surf_layer_tmp;
     662              :     }
     663              : 
     664              :     // Calculate new deep layer RH using mass balance on deep layer (unless depth <= 0).
     665       703579 :     if (mat->deepDepth <= 0.0) {
     666       123219 :         RH_deep_layer = RH_deep_layer_old;
     667              :     } else {
     668       580360 :         RH_deep_layer = RH_deep_layer_old + state.dataGlobal->TimeStepZone * 3600.0 * mass_flux_deep_layer / (mat->Density * mat->deepDepth * dU_dRH);
     669              :     }
     670              :     // Convert calculated RH back to vapor density of surface and deep layers.
     671       703579 :     rv_surf_layer = PsyRhovFnTdbRh(state, Taver, RH_surf_layer);
     672       703579 :     rv_deep_layer = PsyRhovFnTdbRh(state, Taver, RH_deep_layer);
     673              : 
     674              :     // Calculate surface-layer and deep-layer vapor pressures [Pa]
     675       703579 :     PV_surf_layer = RH_surf_layer * std::exp(23.7093 - 4111.0 / (Taver + 237.7));
     676       703579 :     PV_deep_layer = RH_deep_layer * std::exp(23.7093 - 4111.0 / (Taver + 237.7));
     677              : 
     678              :     // Calculate vapor density at physical material surface (surface-layer/air interface). This is used to calculate total moisture flow terms for
     679              :     // each zone in HeatBalanceSurfaceManager
     680       703579 :     rv_surface = rv_surf_layer - mass_flux_zone * RSurfaceLayer;
     681              : 
     682              :     // Calculate heat flux from latent-sensible conversion due to moisture adsorption [W/m^2]
     683       703579 :     heat_flux_latent = mass_flux_zone * Lam;
     684              : 
     685              :     // Put results in the reporting variables
     686              :     // Will add RH and W of deep layer as outputs
     687              :     // Need to also add moisture content (kg/kg) of surface and deep layers, and moisture flow from each surface (kg/s), per Rongpeng's suggestion
     688       703579 :     EMPDReportVarsData &rvd = state.dataMoistureBalEMPD->EMPDReportVars(SurfNum);
     689       703579 :     rvd.rv_surface = rv_surface;
     690       703579 :     rvd.RH_surface_layer = RH_surf_layer * 100.0;
     691       703579 :     rvd.RH_deep_layer = RH_deep_layer * 100.0;
     692       703579 :     rvd.w_surface_layer = 0.622 * PV_surf_layer / (state.dataEnvrn->OutBaroPress - PV_surf_layer);
     693       703579 :     rvd.w_deep_layer = 0.622 * PV_deep_layer / (state.dataEnvrn->OutBaroPress - PV_deep_layer);
     694       703579 :     rvd.mass_flux_zone = mass_flux_zone;
     695       703579 :     rvd.mass_flux_deep = mass_flux_deep_layer;
     696       703579 :     rvd.u_surface_layer = mat->moistACoeff * pow(RH_surf_layer, mat->moistBCoeff) + mat->moistCCoeff * pow(RH_surf_layer, mat->moistDCoeff);
     697       703579 :     rvd.u_deep_layer = mat->moistACoeff * pow(RH_deep_layer, mat->moistBCoeff) + mat->moistCCoeff * pow(RH_deep_layer, mat->moistDCoeff);
     698              : }
     699              : 
     700       150018 : void UpdateMoistureBalanceEMPD(EnergyPlusData &state, int const SurfNum) // Surface number
     701              : {
     702              : 
     703              :     // SUBROUTINE INFORMATION:
     704              :     //   Authors:        Muthusamy Swami and Lixing Gu
     705              :     //   Date writtenn:  August, 1999
     706              :     //   Modified:       na
     707              :     //   Re-engineered:  na
     708              : 
     709              :     // PURPOSE OF THIS SUBROUTINE:
     710              :     // Update inside surface vapor density
     711              : 
     712       150018 :     state.dataMstBalEMPD->RVSurfaceOld(SurfNum) = state.dataMstBalEMPD->RVSurface(SurfNum);
     713       150018 :     state.dataMstBalEMPD->RVdeepOld(SurfNum) = state.dataMstBalEMPD->RVDeepLayer(SurfNum);
     714       150018 :     state.dataMstBalEMPD->RVSurfLayerOld(SurfNum) = state.dataMstBalEMPD->RVSurfLayer(SurfNum);
     715       150018 : }
     716              : 
     717            2 : void ReportMoistureBalanceEMPD(EnergyPlusData &state)
     718              : {
     719              : 
     720              :     // SUBROUTINE INFORMATION:
     721              :     //       AUTHOR         Lixing Gu
     722              :     //       DATE WRITTEN   August 2005
     723              :     //       MODIFIED       na
     724              :     //       RE-ENGINEERED  na
     725              : 
     726              :     // PURPOSE OF THIS SUBROUTINE:
     727              :     // This routine gives a detailed report to the user about
     728              :     // EMPD Properties of each construction.
     729              : 
     730              :     // Using/Aliasing
     731              :     using General::ScanForReports;
     732              : 
     733              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     734              :     bool DoReport;
     735              : 
     736            2 :     auto &s_mat = state.dataMaterial;
     737              : 
     738            6 :     ScanForReports(state, "Constructions", DoReport, "Constructions");
     739              : 
     740            2 :     if (!DoReport) {
     741            0 :         return;
     742              :     }
     743              :     //   Write Descriptions
     744            2 :     print(state.files.eio,
     745              :           "{}",
     746              :           "! <Construction EMPD>, Construction Name, Inside Layer Material Name, Vapor Resistance Factor, a, b, "
     747              :           "c, d, Surface Penetration Depth {m}, Deep Penetration Depth {m}, Coating Vapor Resistance Factor, "
     748              :           "Coating Thickness {m}\n");
     749              : 
     750           13 :     for (int ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
     751           11 :         auto const &constr = state.dataConstruction->Construct(ConstrNum);
     752           11 :         if (constr.TypeIsWindow) {
     753            2 :             continue;
     754              :         }
     755              : 
     756            9 :         auto const *mat = s_mat->materials(constr.LayerPoint(constr.TotLayers));
     757            9 :         if (!mat->hasEMPD) {
     758            3 :             continue;
     759              :         }
     760              : 
     761            6 :         auto const *matEMPD = dynamic_cast<MaterialEMPD const *>(mat);
     762            6 :         assert(matEMPD != nullptr);
     763              : 
     764              :         static constexpr std::string_view Format_700(
     765              :             " Construction EMPD, {}, {}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}\n");
     766            6 :         print(state.files.eio,
     767              :               Format_700,
     768            6 :               constr.Name,
     769            6 :               matEMPD->Name,
     770            6 :               matEMPD->mu,
     771            6 :               matEMPD->moistACoeff,
     772            6 :               matEMPD->moistBCoeff,
     773            6 :               matEMPD->moistCCoeff,
     774            6 :               matEMPD->moistDCoeff,
     775            6 :               matEMPD->surfaceDepth,
     776            6 :               matEMPD->deepDepth,
     777            6 :               matEMPD->muCoating,
     778            6 :               matEMPD->coatingThickness);
     779              :     }
     780              : } // ReportMoistureBalanceEMPD()
     781              : 
     782              : } // namespace EnergyPlus::MoistureBalanceEMPDManager
        

Generated by: LCOV version 2.0-1