LCOV - code coverage report
Current view: top level - EnergyPlus - MoistureBalanceEMPDManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 232 314 73.9 %
Date: 2024-08-24 18:31:18 Functions: 5 6 83.3 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : #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 CalcDepthFromPeriod(EnergyPlusData &state,
     111             :                            Real64 const period,                  // in seconds
     112             :                            Material::MaterialBase const *matBase // material
     113             : )
     114             : {
     115             : 
     116             :     // Assume T, RH, P
     117           0 :     Real64 constexpr T = 24.0; // C
     118           0 :     Real64 constexpr RH = 0.45;
     119           0 :     Real64 constexpr P_amb = 101325; // Pa
     120             : 
     121             :     // Calculate saturation vapor pressure at assumed temperature
     122           0 :     Real64 const PV_sat = Psychrometrics::PsyPsatFnTemp(state, T, "CalcDepthFromPeriod");
     123             : 
     124           0 :     auto const *mat = dynamic_cast<const Material::MaterialChild *>(matBase);
     125           0 :     assert(mat != nullptr);
     126             :     // Calculate slope of moisture sorption curve
     127           0 :     Real64 const slope_MC = mat->MoistACoeff * mat->MoistBCoeff * std::pow(RH, mat->MoistBCoeff - 1) +
     128           0 :                             mat->MoistCCoeff * mat->MoistDCoeff * std::pow(RH, mat->MoistDCoeff - 1);
     129             : 
     130             :     // Equation for the diffusivity of water vapor in air
     131           0 :     Real64 const diffusivity_air = 2.0e-7 * std::pow(T + 273.15, 0.81) / P_amb;
     132             : 
     133             :     // Convert mu to diffusivity [kg/m^2-s-Pa]
     134           0 :     Real64 const EMPDdiffusivity = diffusivity_air / mat->EMPDmu;
     135             : 
     136             :     // Calculate penetration depth
     137           0 :     Real64 const PenetrationDepth = std::sqrt(EMPDdiffusivity * PV_sat * period / (mat->Density * slope_MC * Constant::Pi));
     138             : 
     139           0 :     return PenetrationDepth;
     140             : }
     141             : 
     142           2 : void GetMoistureBalanceEMPDInput(EnergyPlusData &state)
     143             : {
     144             : 
     145             :     // SUBROUTINE INFORMATION:
     146             :     //       AUTHOR         Muthusamy V. Swami and Lixing Gu
     147             :     //       DATE WRITTEN   August 2000
     148             :     //       MODIFIED       na
     149             :     //       RE-ENGINEERED  na
     150             : 
     151             :     // PURPOSE OF THIS SUBROUTINE:
     152             :     // This subroutine is the main driver for initializations within the
     153             :     // heat balance using the EMPD model.
     154             : 
     155             :     // Using/Aliasing
     156             : 
     157             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     158             :     int IOStat;                       // IO Status when calling get input subroutine
     159           2 :     Array1D_string MaterialNames(3);  // Number of Material Alpha names defined
     160             :     int MaterNum;                     // Counter to keep track of the material number
     161             :     int MaterialNumAlpha;             // Number of material alpha names being passed
     162             :     int MaterialNumProp;              // Number of material properties being passed
     163           2 :     Array1D<Real64> MaterialProps(9); // Temporary array to transfer material properties
     164           2 :     bool ErrorsFound(false);          // If errors detected in input
     165             : 
     166             :     int EMPDMat; // EMPD Moisture Material additional properties for each base material
     167             :     int Loop;
     168             :     int Layer;
     169             :     int SurfNum;           // Surface number
     170             :     int MatNum;            // Material number at interior layer
     171             :     int ConstrNum;         // Construction number
     172           2 :     Array1D_bool EMPDzone; // EMPD property check for each zone
     173             : 
     174           2 :     auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
     175             : 
     176             :     // Load the additional EMPD Material properties
     177           2 :     cCurrentModuleObject = "MaterialProperty:MoisturePenetrationDepth:Settings";
     178           2 :     EMPDMat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     179             : 
     180           2 :     if (EMPDMat == 0) {
     181           0 :         ShowSevereError(state, format("EMPD Solution requested, but no \"{}\" objects were found.", cCurrentModuleObject));
     182           0 :         ErrorsFound = true;
     183             :     }
     184             : 
     185           8 :     for (Loop = 1; Loop <= EMPDMat; ++Loop) {
     186             : 
     187             :         // Call Input Get routine to retrieve material data
     188          12 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     189             :                                                                  cCurrentModuleObject,
     190             :                                                                  Loop,
     191             :                                                                  MaterialNames,
     192             :                                                                  MaterialNumAlpha,
     193             :                                                                  MaterialProps,
     194             :                                                                  MaterialNumProp,
     195             :                                                                  IOStat,
     196           6 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     197           6 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     198           6 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     199           6 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     200             : 
     201             :         // Load the material derived type from the input data.
     202           6 :         MaterNum = Util::FindItemInPtrList(MaterialNames(1), state.dataMaterial->Material);
     203           6 :         if (MaterNum == 0) {
     204           0 :             ShowSevereError(state,
     205           0 :                             format("{}: invalid {} entered={}, must match to a valid Material name.",
     206             :                                    cCurrentModuleObject,
     207           0 :                                    state.dataIPShortCut->cAlphaFieldNames(1),
     208             :                                    MaterialNames(1)));
     209           0 :             ErrorsFound = true;
     210           0 :             continue;
     211             :         }
     212             : 
     213           6 :         auto *material(dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(MaterNum)));
     214           6 :         assert(material != nullptr);
     215             :         // See if Material was defined with R only.  (No density is defined then and not applicable for EMPD).
     216             :         //  What about materials other than "regular materials" (e.g. Glass, Air, etc)
     217           6 :         if (material->group == Material::Group::Regular && MaterialProps(1) > 0.0) {
     218           6 :             if (material->ROnly) {
     219             :                 //        CALL ShowSevereError('EMPD base material = "'//TRIM(dataMaterial.Material(MaterNum)%Name)//  &
     220             :                 //                             '" was Material:NoMass. It cannot be used for EMPD calculations.')
     221           0 :                 ShowSevereError(state, "..Only Material base materials are allowed to have EMPD properties.");
     222           0 :                 ShowContinueError(
     223             :                     state,
     224           0 :                     format("{}: Reference Material is not appropriate type for EMPD properties, material={}, must have regular properties (L,Cp,K,D)",
     225             :                            cCurrentModuleObject,
     226           0 :                            material->Name));
     227           0 :                 ErrorsFound = true;
     228             :             }
     229             :         }
     230           6 :         if (material->group != Material::Group::Regular) {
     231             :             //      CALL ShowSevereError('GetMoistureBalanceEMPDInput: Only Material:Regular base materials are allowed '// &
     232             :             //                           'to have EMPD properties, material = '// TRIM(dataMaterial.Material(MaterNum)%Name))
     233           0 :             ShowSevereError(
     234             :                 state,
     235           0 :                 format("{}: Reference Material is not appropriate type for EMPD properties, material={}, must have regular properties (L,Cp,K,D)",
     236             :                        cCurrentModuleObject,
     237           0 :                        material->Name));
     238           0 :             ErrorsFound = true;
     239             :         }
     240             : 
     241             :         // Once the material derived type number is found then load the additional moisture material properties
     242           6 :         material->EMPDmu = MaterialProps(1);
     243           6 :         material->MoistACoeff = MaterialProps(2);
     244           6 :         material->MoistBCoeff = MaterialProps(3);
     245           6 :         material->MoistCCoeff = MaterialProps(4);
     246           6 :         material->MoistDCoeff = MaterialProps(5);
     247           6 :         if (state.dataIPShortCut->lNumericFieldBlanks(6) || MaterialProps(6) == Constant::AutoCalculate) {
     248           0 :             material->EMPDSurfaceDepth = CalcDepthFromPeriod(state, 24 * 3600, material); // 1 day
     249             :         } else {
     250           6 :             material->EMPDSurfaceDepth = MaterialProps(6);
     251             :         }
     252           6 :         if (state.dataIPShortCut->lNumericFieldBlanks(7) || MaterialProps(7) == Constant::AutoCalculate) {
     253           0 :             material->EMPDDeepDepth = CalcDepthFromPeriod(state, 21 * 24 * 3600, material); // 3 weeks
     254             :         } else {
     255           6 :             material->EMPDDeepDepth = MaterialProps(7);
     256             :         }
     257           6 :         material->EMPDCoatingThickness = MaterialProps(8);
     258           6 :         material->EMPDmuCoating = MaterialProps(9);
     259             : 
     260           6 :         if (material->EMPDDeepDepth <= material->EMPDSurfaceDepth && material->EMPDDeepDepth != 0.0) {
     261           0 :             ShowWarningError(state, format("{}: material=\"{}\"", cCurrentModuleObject, material->Name));
     262           0 :             ShowContinueError(state, "Deep-layer penetration depth should be zero or greater than the surface-layer penetration depth.");
     263             :         }
     264             :     }
     265             : 
     266             :     // Ensure at least one interior EMPD surface for each zone
     267           2 :     EMPDzone.dimension(state.dataGlobal->NumOfZones, false);
     268          58 :     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     269          56 :         if (!state.dataSurface->Surface(SurfNum).HeatTransSurf || state.dataSurface->Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window)
     270          10 :             continue; // Heat transfer surface only and not a window
     271          46 :         if (state.dataSurface->Surface(SurfNum).HeatTransferAlgorithm != DataSurfaces::HeatTransferModel::EMPD) continue;
     272          43 :         ConstrNum = state.dataSurface->Surface(SurfNum).Construction;
     273          43 :         auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
     274          43 :         MatNum = thisConstruct.LayerPoint(state.dataConstruction->Construct(ConstrNum).TotLayers);
     275          43 :         auto const *thisMaterial = dynamic_cast<const Material::MaterialChild *>(state.dataMaterial->Material(MatNum));
     276          43 :         assert(thisMaterial != nullptr);
     277          43 :         if (thisMaterial->EMPDmu > 0.0 && state.dataSurface->Surface(SurfNum).Zone > 0) {
     278          43 :             EMPDzone(state.dataSurface->Surface(SurfNum).Zone) = true;
     279             :         } else {
     280           0 :             ++state.dataMoistureBalEMPD->ErrCount;
     281           0 :             if (state.dataMoistureBalEMPD->ErrCount == 1 && !state.dataGlobal->DisplayExtraWarnings) {
     282           0 :                 ShowMessage(state, "GetMoistureBalanceEMPDInput: EMPD properties are not assigned to the inside layer of Surfaces");
     283           0 :                 ShowContinueError(state, "...use Output:Diagnostics,DisplayExtraWarnings; to show more details on individual surfaces.");
     284             :             }
     285           0 :             if (state.dataGlobal->DisplayExtraWarnings) {
     286           0 :                 ShowMessage(state,
     287           0 :                             format("GetMoistureBalanceEMPDInput: EMPD properties are not assigned to the inside layer in Surface={}",
     288           0 :                                    state.dataSurface->Surface(SurfNum).Name));
     289           0 :                 ShowContinueError(state, format("with Construction={}", thisConstruct.Name));
     290             :             }
     291             :         }
     292          43 :         if (thisConstruct.TotLayers == 1) { // One layer construction
     293          15 :             continue;
     294             :         } else { // Multiple layer construction
     295          28 :             if (dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(1)))->EMPDMaterialProps &&
     296           0 :                 state.dataSurface->Surface(SurfNum).ExtBoundCond <= 0) { // The external layer is not exposed to zone
     297           0 :                 ShowSevereError(
     298           0 :                     state, "GetMoistureBalanceEMPDInput: EMPD properties are assigned to the outside layer in Construction=" + thisConstruct.Name);
     299           0 :                 ShowContinueError(
     300           0 :                     state, "..Outside layer material with EMPD properties = " + state.dataMaterial->Material(thisConstruct.LayerPoint(1))->Name);
     301           0 :                 ShowContinueError(state, "..A material with EMPD properties must be assigned to the inside layer of a construction.");
     302           0 :                 ErrorsFound = true;
     303             :             }
     304          68 :             for (Layer = 2; Layer <= thisConstruct.TotLayers - 1; ++Layer) {
     305          40 :                 if (dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(Layer)))->EMPDMaterialProps) {
     306           0 :                     ShowSevereError(
     307           0 :                         state, "GetMoistureBalanceEMPDInput: EMPD properties are assigned to a middle layer in Construction=" + thisConstruct.Name);
     308           0 :                     ShowContinueError(state,
     309           0 :                                       "..Middle layer material with EMPD properties = " +
     310           0 :                                           state.dataMaterial->Material(thisConstruct.LayerPoint(Layer))->Name);
     311           0 :                     ShowContinueError(state, "..A material with EMPD properties must be assigned to the inside layer of a construction.");
     312           0 :                     ErrorsFound = true;
     313             :                 }
     314             :             }
     315             :         }
     316             :     }
     317             : 
     318           9 :     for (Loop = 1; Loop <= state.dataGlobal->NumOfZones; ++Loop) {
     319           7 :         if (!EMPDzone(Loop)) {
     320           0 :             ShowSevereError(state,
     321           0 :                             format("GetMoistureBalanceEMPDInput: None of the constructions for zone = {} has an inside layer with EMPD properties",
     322           0 :                                    state.dataHeatBal->Zone(Loop).Name));
     323           0 :             ShowContinueError(state, "..For each zone, the inside layer of at least one construction must have EMPD properties");
     324           0 :             ErrorsFound = true;
     325             :         }
     326             :     }
     327             : 
     328           2 :     EMPDzone.deallocate();
     329             : 
     330           2 :     ReportMoistureBalanceEMPD(state);
     331             : 
     332           2 :     if (ErrorsFound) {
     333           0 :         ShowFatalError(state, "GetMoistureBalanceEMPDInput: Errors found getting EMPD material properties, program terminated.");
     334             :     }
     335           2 : }
     336             : 
     337          14 : void InitMoistureBalanceEMPD(EnergyPlusData &state)
     338             : {
     339             : 
     340             :     // SUBROUTINE INFORMATION:
     341             :     //   Authors:        Muthusamy Swami and Lixing Gu
     342             :     //   Date written:   August, 1999
     343             :     //   Modified:       na
     344             :     //   Re-engineered:  na
     345             : 
     346             :     // PURPOSE OF THIS SUBROUTINE:
     347             :     // Create dynamic array for surface moisture calculation
     348             : 
     349             :     // USE STATEMENTS:
     350             :     using Psychrometrics::PsyRhovFnTdbRh;
     351             :     using Psychrometrics::PsyRhovFnTdbWPb_fast;
     352             : 
     353             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     354             :     int ZoneNum;
     355             :     int SurfNum;
     356             : 
     357          14 :     if (state.dataMoistureBalEMPD->InitEnvrnFlag) {
     358           2 :         state.dataMstBalEMPD->RVSurfaceOld.allocate(state.dataSurface->TotSurfaces);
     359           2 :         state.dataMstBalEMPD->RVSurface.allocate(state.dataSurface->TotSurfaces);
     360           2 :         state.dataMstBalEMPD->HeatFluxLatent.allocate(state.dataSurface->TotSurfaces);
     361           2 :         state.dataMoistureBalEMPD->EMPDReportVars.allocate(state.dataSurface->TotSurfaces);
     362           2 :         state.dataMstBalEMPD->RVSurfLayer.allocate(state.dataSurface->TotSurfaces);
     363           2 :         state.dataMstBalEMPD->RVSurfLayerOld.allocate(state.dataSurface->TotSurfaces);
     364           2 :         state.dataMstBalEMPD->RVDeepLayer.allocate(state.dataSurface->TotSurfaces);
     365           2 :         state.dataMstBalEMPD->RVdeepOld.allocate(state.dataSurface->TotSurfaces);
     366           2 :         state.dataMstBalEMPD->RVwall.allocate(state.dataSurface->TotSurfaces);
     367             :     }
     368             : 
     369         538 :     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     370         524 :         ZoneNum = state.dataSurface->Surface(SurfNum).Zone;
     371         524 :         if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) continue;
     372             :         Real64 const rv_air_in_initval =
     373         484 :             min(PsyRhovFnTdbWPb_fast(state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT,
     374         484 :                                      max(state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).airHumRat, 1.0e-5),
     375         484 :                                      state.dataEnvrn->OutBaroPress),
     376         484 :                 PsyRhovFnTdbRh(state, state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum).MAT, 1.0, "InitMoistureBalanceEMPD"));
     377         484 :         state.dataMstBalEMPD->RVSurfaceOld(SurfNum) = rv_air_in_initval;
     378         484 :         state.dataMstBalEMPD->RVSurface(SurfNum) = rv_air_in_initval;
     379         484 :         state.dataMstBalEMPD->RVSurfLayer(SurfNum) = rv_air_in_initval;
     380         484 :         state.dataMstBalEMPD->RVSurfLayerOld(SurfNum) = rv_air_in_initval;
     381         484 :         state.dataMstBalEMPD->RVDeepLayer(SurfNum) = rv_air_in_initval;
     382         484 :         state.dataMstBalEMPD->RVdeepOld(SurfNum) = rv_air_in_initval;
     383         484 :         state.dataMstBalEMPD->RVwall(SurfNum) = rv_air_in_initval;
     384             :     }
     385          14 :     if (!state.dataMoistureBalEMPD->InitEnvrnFlag) return;
     386             :     // Initialize the report variable
     387             : 
     388           2 :     GetMoistureBalanceEMPDInput(state);
     389             : 
     390          58 :     for (SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
     391          62 :         if (!state.dataSurface->Surface(SurfNum).HeatTransSurf) continue;
     392          52 :         if (state.dataSurface->Surface(SurfNum).Class == DataSurfaces::SurfaceClass::Window) continue;
     393          46 :         EMPDReportVarsData &rvd = state.dataMoistureBalEMPD->EMPDReportVars(SurfNum);
     394          46 :         const std::string surf_name = state.dataSurface->Surface(SurfNum).Name;
     395          92 :         SetupOutputVariable(state,
     396             :                             "EMPD Surface Inside Face Water Vapor Density",
     397             :                             Constant::Units::kg_m3,
     398          46 :                             rvd.rv_surface,
     399             :                             OutputProcessor::TimeStepType::Zone,
     400             :                             OutputProcessor::StoreType::Average,
     401             :                             surf_name);
     402          92 :         SetupOutputVariable(state,
     403             :                             "EMPD Surface Layer Moisture Content",
     404             :                             Constant::Units::kg_m3,
     405          46 :                             rvd.u_surface_layer,
     406             :                             OutputProcessor::TimeStepType::Zone,
     407             :                             OutputProcessor::StoreType::Average,
     408             :                             surf_name);
     409          92 :         SetupOutputVariable(state,
     410             :                             "EMPD Deep Layer Moisture Content",
     411             :                             Constant::Units::kg_m3,
     412          46 :                             rvd.u_deep_layer,
     413             :                             OutputProcessor::TimeStepType::Zone,
     414             :                             OutputProcessor::StoreType::Average,
     415             :                             surf_name);
     416          92 :         SetupOutputVariable(state,
     417             :                             "EMPD Surface Layer Equivalent Relative Humidity",
     418             :                             Constant::Units::Perc,
     419          46 :                             rvd.RH_surface_layer,
     420             :                             OutputProcessor::TimeStepType::Zone,
     421             :                             OutputProcessor::StoreType::Average,
     422             :                             surf_name);
     423          92 :         SetupOutputVariable(state,
     424             :                             "EMPD Deep Layer Equivalent Relative Humidity",
     425             :                             Constant::Units::Perc,
     426          46 :                             rvd.RH_deep_layer,
     427             :                             OutputProcessor::TimeStepType::Zone,
     428             :                             OutputProcessor::StoreType::Average,
     429             :                             surf_name);
     430          92 :         SetupOutputVariable(state,
     431             :                             "EMPD Surface Layer Equivalent Humidity Ratio",
     432             :                             Constant::Units::kgWater_kgDryAir,
     433          46 :                             rvd.w_surface_layer,
     434             :                             OutputProcessor::TimeStepType::Zone,
     435             :                             OutputProcessor::StoreType::Average,
     436             :                             surf_name);
     437          92 :         SetupOutputVariable(state,
     438             :                             "EMPD Deep Layer Equivalent Humidity Ratio",
     439             :                             Constant::Units::kgWater_kgDryAir,
     440          46 :                             rvd.w_deep_layer,
     441             :                             OutputProcessor::TimeStepType::Zone,
     442             :                             OutputProcessor::StoreType::Average,
     443             :                             surf_name);
     444          92 :         SetupOutputVariable(state,
     445             :                             "EMPD Surface Moisture Flux to Zone",
     446             :                             Constant::Units::kg_m2s,
     447          46 :                             rvd.mass_flux_zone,
     448             :                             OutputProcessor::TimeStepType::Zone,
     449             :                             OutputProcessor::StoreType::Average,
     450             :                             surf_name);
     451          92 :         SetupOutputVariable(state,
     452             :                             "EMPD Deep Layer Moisture Flux",
     453             :                             Constant::Units::kg_m2s,
     454          46 :                             rvd.mass_flux_deep,
     455             :                             OutputProcessor::TimeStepType::Zone,
     456             :                             OutputProcessor::StoreType::Average,
     457             :                             surf_name);
     458          46 :     }
     459             : 
     460           2 :     if (state.dataMoistureBalEMPD->InitEnvrnFlag) state.dataMoistureBalEMPD->InitEnvrnFlag = false;
     461             : }
     462             : 
     463      699139 : void CalcMoistureBalanceEMPD(EnergyPlusData &state,
     464             :                              int const SurfNum,
     465             :                              Real64 const SurfTempIn, // INSIDE SURFACE TEMPERATURE at current time step
     466             :                              Real64 const TempZone,   // Zone temperature at current time step.
     467             :                              Real64 &TempSat          // Saturated surface temperature.
     468             : )
     469             : {
     470             : 
     471             :     // SUBROUTINE INFORMATION:
     472             :     //   Authors:        Muthusamy Swami and Lixing Gu
     473             :     //   Date written:   August, 1999
     474             :     //   Modified:       na
     475             :     //   Re-engineered:  na
     476             : 
     477             :     // PURPOSE OF THIS SUBROUTINE:
     478             :     // Calculate surface moisture level using EMPD model
     479             : 
     480             :     // Using/Aliasing
     481             :     using DataMoistureBalanceEMPD::Lam;
     482             :     using Psychrometrics::PsyCpAirFnW;
     483             :     using Psychrometrics::PsyPsatFnTemp;
     484             :     using Psychrometrics::PsyRhFnTdbRhov;
     485             :     using Psychrometrics::PsyRhFnTdbRhovLBnd0C;
     486             :     using Psychrometrics::PsyRhFnTdbWPb;
     487             :     using Psychrometrics::PsyRhoAirFnPbTdbW;
     488             :     using Psychrometrics::PsyRhovFnTdbRh;
     489             :     using Psychrometrics::PsyRhovFnTdbWPb;
     490             :     using Psychrometrics::PsyRhovFnTdbWPb_fast;
     491             :     using Psychrometrics::PsyWFnTdbRhPb;
     492             : 
     493             :     static constexpr std::string_view RoutineName("CalcMoistureEMPD");
     494             : 
     495             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     496             :     int NOFITR;           // Number of iterations
     497             :     int MatNum;           // Material number at interior layer
     498             :     int ConstrNum;        // Construction number
     499             :     Real64 hm_deep_layer; // Overall deep-layer transfer coefficient
     500             :     Real64 RSurfaceLayer; // Mass transfer resistance between actual surface and surface layer node
     501             :     Real64 Taver;         // Average zone temperature between current time and previous time
     502             :     //    REAL(r64)    :: Waver     ! Average zone humidity ratio between current time and previous time
     503             :     Real64 RHaver; // Average zone relative humidity {0-1} between current time and previous time
     504             :     Real64 RVaver; // Average zone vapor density
     505             :     Real64 dU_dRH;
     506             :     int Flag;             // Convergence flag (0 - converged)
     507             :     Real64 PVsurf;        // Surface vapor pressure
     508             :     Real64 PV_surf_layer; // Vapor pressure of surface layer
     509             :     Real64 PV_deep_layer;
     510             :     Real64 PVsat; // saturation vapor pressure at the surface
     511             :     Real64 RH_surf_layer_old;
     512             :     Real64 RH_deep_layer_old;
     513             :     Real64 EMPDdiffusivity;
     514             :     Real64 Rcoating;
     515             :     Real64 RH_surf_layer;
     516             :     Real64 RH_surf_layer_tmp;
     517             :     Real64 RH_deep_layer;
     518             : 
     519      699139 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataMoistureBalEMPD->OneTimeFlag) {
     520          14 :         InitMoistureBalanceEMPD(state);
     521          14 :         state.dataMoistureBalEMPD->OneTimeFlag = false;
     522             :     }
     523             : 
     524      699139 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     525      696421 :         state.dataMoistureBalEMPD->OneTimeFlag = true;
     526             :     }
     527             : 
     528      699139 :     auto const &surface(state.dataSurface->Surface(SurfNum));                // input
     529      699139 :     auto &rv_surface(state.dataMstBalEMPD->RVSurface(SurfNum));              // output
     530      699139 :     auto const &rv_surface_old(state.dataMstBalEMPD->RVSurfaceOld(SurfNum)); // input
     531      699139 :     auto const &h_mass_conv_in_fd(state.dataMstBal->HMassConvInFD(SurfNum)); // input
     532      699139 :     auto const &rho_vapor_air_in(state.dataMstBal->RhoVaporAirIn(SurfNum));  // input
     533             :     Real64 RHZone;
     534             :     Real64 mass_flux_surf_deep;
     535             :     Real64 mass_flux_surf_deep_max;
     536             :     Real64 mass_flux_zone_surf;
     537             :     Real64 mass_flux_zone_surf_max;
     538             :     Real64 mass_flux_surf_layer;
     539             :     Real64 mass_flux_deep_layer;
     540             :     Real64 mass_flux_zone;
     541      699139 :     auto &rv_surf_layer(state.dataMstBalEMPD->RVSurfLayer(SurfNum));              // output
     542      699139 :     auto const &rv_surf_layer_old(state.dataMstBalEMPD->RVSurfLayerOld(SurfNum)); // input
     543             :     Real64 hm_surf_layer;
     544      699139 :     auto &rv_deep_layer(state.dataMstBalEMPD->RVDeepLayer(SurfNum));       // output
     545      699139 :     auto const &rv_deep_old(state.dataMstBalEMPD->RVdeepOld(SurfNum));     // input
     546      699139 :     auto &heat_flux_latent(state.dataMstBalEMPD->HeatFluxLatent(SurfNum)); // output
     547             : 
     548      699139 :     heat_flux_latent = 0.0;
     549      699139 :     Flag = 1;
     550      699139 :     NOFITR = 0;
     551      699139 :     if (!surface.HeatTransSurf) {
     552           0 :         return;
     553             :     }
     554      699139 :     ConstrNum = surface.Construction;
     555      699139 :     MatNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(
     556      699139 :         state.dataConstruction->Construct(ConstrNum).TotLayers); // Then find the material pointer
     557             : 
     558      699139 :     auto const *material(dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(MatNum)));
     559      699139 :     assert(material != nullptr);
     560      699139 :     if (material->EMPDmu <= 0.0) {
     561           0 :         rv_surface =
     562           0 :             PsyRhovFnTdbWPb(TempZone, state.dataZoneTempPredictorCorrector->zoneHeatBalance(surface.Zone).airHumRat, state.dataEnvrn->OutBaroPress);
     563           0 :         return;
     564             :     }
     565             : 
     566      699139 :     Taver = SurfTempIn;
     567             :     // Calculate average vapor density [kg/m^3], and RH for use in material property calculations.
     568      699139 :     RVaver = rv_surface_old;
     569      699139 :     RHaver = RVaver * 461.52 * (Taver + Constant::Kelvin) * std::exp(-23.7093 + 4111.0 / (Taver + 237.7));
     570             : 
     571             :     // Calculate the saturated vapor pressure, surface vapor pressure and dewpoint. Used to check for condensation in HeatBalanceSurfaceManager
     572      699139 :     PVsat = PsyPsatFnTemp(state, Taver, RoutineName);
     573      699139 :     PVsurf = RHaver * std::exp(23.7093 - 4111.0 / (Taver + 237.7));
     574      699139 :     TempSat = 4111.0 / (23.7093 - std::log(PVsurf)) + 35.45 - Constant::Kelvin;
     575             : 
     576             :     // Convert vapor resistance factor (user input) to diffusivity. Evaluate at local surface temperature.
     577             :     // 2e-7*T^0.81/P = vapor diffusivity in air. [kg/m-s-Pa]
     578             :     // 461.52 = universal gas constant for water [J/kg-K]
     579             :     // EMPDdiffusivity = [m^2/s]
     580      699139 :     EMPDdiffusivity =
     581      699139 :         (2.0e-7 * pow(Taver + Constant::Kelvin, 0.81) / state.dataEnvrn->OutBaroPress) / material->EMPDmu * 461.52 * (Taver + Constant::Kelvin);
     582             : 
     583             :     // Calculate slope of moisture sorption curve at current RH. [kg/kg-RH]
     584      699139 :     dU_dRH = material->MoistACoeff * material->MoistBCoeff * pow(RHaver, material->MoistBCoeff - 1) +
     585      699139 :              material->MoistCCoeff * material->MoistDCoeff * pow(RHaver, material->MoistDCoeff - 1);
     586             : 
     587             :     // Convert vapor density and temperature of zone air to RH
     588      699139 :     RHZone = rho_vapor_air_in * 461.52 * (TempZone + Constant::Kelvin) * std::exp(-23.7093 + 4111.0 / ((TempZone + Constant::Kelvin) - 35.45));
     589             : 
     590             :     // Convert stored vapor density from previous timestep to RH.
     591      699139 :     RH_deep_layer_old = PsyRhFnTdbRhov(state, Taver, rv_deep_old);
     592      699139 :     RH_surf_layer_old = PsyRhFnTdbRhov(state, Taver, rv_surf_layer_old);
     593             : 
     594             :     // If coating vapor resistance factor equals 0, coating resistance is zero (avoid divide by zero).
     595             :     // Otherwise, calculate coating resistance with coating vapor resistance factor and thickness. [s/m]
     596      699139 :     if (material->EMPDmuCoating <= 0.0) {
     597      699139 :         Rcoating = 0;
     598             :     } else {
     599           0 :         Rcoating = material->EMPDCoatingThickness * material->EMPDmuCoating * state.dataEnvrn->OutBaroPress /
     600           0 :                    (2.0e-7 * pow(Taver + Constant::Kelvin, 0.81) * 461.52 * (Taver + Constant::Kelvin));
     601             :     }
     602             : 
     603             :     // Calculate mass-transfer coefficient between zone air and center of surface layer. [m/s]
     604      699139 :     hm_surf_layer = 1.0 / (0.5 * material->EMPDSurfaceDepth / EMPDdiffusivity + 1.0 / h_mass_conv_in_fd + Rcoating);
     605             :     // Calculate mass-transfer coefficient between center of surface layer and center of deep layer. [m/s]
     606             :     // If deep layer depth = 0, set mass-transfer coefficient to zero (simulates with no deep layer).
     607      699139 :     if (material->EMPDDeepDepth <= 0.0) {
     608      123219 :         hm_deep_layer = 0;
     609             :     } else {
     610      575920 :         hm_deep_layer = 2.0 * EMPDdiffusivity / (material->EMPDDeepDepth + material->EMPDSurfaceDepth);
     611             :     }
     612             :     // Calculate resistance between surface-layer/air interface and center of surface layer. [s/m]
     613             :     // This is the physical surface of the material.
     614      699139 :     RSurfaceLayer = 1.0 / hm_surf_layer - 1.0 / h_mass_conv_in_fd;
     615             : 
     616             :     // Calculate vapor flux leaving surface layer, entering deep layer, and entering zone.
     617      699139 :     mass_flux_surf_deep_max =
     618      699139 :         material->EMPDDeepDepth * material->Density * dU_dRH * (RH_surf_layer_old - RH_deep_layer_old) / (state.dataGlobal->TimeStepZone * 3600.0);
     619      699139 :     mass_flux_surf_deep = hm_deep_layer * (rv_surf_layer_old - rv_deep_old);
     620      699139 :     if (std::abs(mass_flux_surf_deep_max) < std::abs(mass_flux_surf_deep)) {
     621           0 :         mass_flux_surf_deep = mass_flux_surf_deep_max;
     622             :     }
     623             : 
     624      699139 :     mass_flux_zone_surf_max =
     625      699139 :         material->EMPDSurfaceDepth * material->Density * dU_dRH * (RHZone - RH_surf_layer_old) / (state.dataGlobal->TimeStepZone * 3600.0);
     626      699139 :     mass_flux_zone_surf = hm_surf_layer * (rho_vapor_air_in - rv_surf_layer_old);
     627      699139 :     if (std::abs(mass_flux_zone_surf_max) < std::abs(mass_flux_zone_surf)) {
     628       10629 :         mass_flux_zone_surf = mass_flux_zone_surf_max;
     629             :     }
     630             : 
     631             :     // mass_flux_surf_layer = -mass_flux_zone_surf + mass_flux_surf_deep;
     632             :     // mass_flux_deep_layer = mass_flux_surf_deep;
     633             :     // mass_flux_zone = -mass_flux_zone_surf;
     634             : 
     635      699139 :     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);
     636      699139 :     mass_flux_deep_layer = hm_deep_layer * (rv_surf_layer_old - rv_deep_old);
     637      699139 :     mass_flux_zone = hm_surf_layer * (rv_surf_layer_old - rho_vapor_air_in);
     638             : 
     639             :     // Calculate new surface layer RH using mass balance on surface layer
     640      699139 :     RH_surf_layer_tmp = RH_surf_layer_old +
     641      699139 :                         state.dataGlobal->TimeStepZone * 3600.0 * (-mass_flux_surf_layer / (material->Density * material->EMPDSurfaceDepth * dU_dRH));
     642             : 
     643             :     //    RH_surf_layer = RH_surf_layer_tmp;
     644             : 
     645      699139 :     if (RH_surf_layer_old < RH_deep_layer_old && RH_surf_layer_old < RHZone) {
     646      199473 :         if (RHZone > RH_deep_layer_old) {
     647      107142 :             if (RH_surf_layer_tmp > RHZone) {
     648           3 :                 RH_surf_layer = RHZone;
     649             :             } else {
     650      107139 :                 RH_surf_layer = RH_surf_layer_tmp;
     651             :             }
     652       92331 :         } else if (RH_surf_layer_tmp > RH_deep_layer_old) {
     653           0 :             RH_surf_layer = RH_deep_layer_old;
     654             :         } else {
     655       92331 :             RH_surf_layer = RH_surf_layer_tmp;
     656             :         }
     657             : 
     658      499666 :     } else if (RH_surf_layer_old < RH_deep_layer_old && RH_surf_layer_old > RHZone) {
     659      211188 :         if (RH_surf_layer_tmp > RH_deep_layer_old) {
     660         184 :             RH_surf_layer = RH_deep_layer_old;
     661      211004 :         } else if (RH_surf_layer_tmp < RHZone) {
     662        1738 :             RH_surf_layer = RHZone;
     663             :         } else {
     664      209266 :             RH_surf_layer = RH_surf_layer_tmp;
     665             :         }
     666      288478 :     } else if (RH_surf_layer_old > RH_deep_layer_old && RH_surf_layer_old < RHZone) {
     667      109106 :         if (RH_surf_layer_tmp > RHZone) {
     668         537 :             RH_surf_layer = RHZone;
     669      108569 :         } else if (RH_surf_layer_tmp < RH_deep_layer_old) {
     670         593 :             RH_surf_layer = RH_deep_layer_old;
     671             :         } else
     672      107976 :             RH_surf_layer = RH_surf_layer_tmp;
     673      179372 :     } else if (RHZone < RH_deep_layer_old) {
     674       92472 :         if (RH_surf_layer_tmp < RHZone) {
     675           1 :             RH_surf_layer = RHZone;
     676             :         } else {
     677       92471 :             RH_surf_layer = RH_surf_layer_tmp;
     678             :         }
     679       86900 :     } else if (RH_surf_layer_tmp < RH_deep_layer_old) {
     680         246 :         RH_surf_layer = RH_deep_layer_old;
     681             :     } else {
     682       86654 :         RH_surf_layer = RH_surf_layer_tmp;
     683             :     }
     684             : 
     685             :     // Calculate new deep layer RH using mass balance on deep layer (unless depth <= 0).
     686      699139 :     if (material->EMPDDeepDepth <= 0.0) {
     687      123219 :         RH_deep_layer = RH_deep_layer_old;
     688             :     } else {
     689      575920 :         RH_deep_layer = RH_deep_layer_old +
     690      575920 :                         state.dataGlobal->TimeStepZone * 3600.0 * mass_flux_deep_layer / (material->Density * material->EMPDDeepDepth * dU_dRH);
     691             :     }
     692             :     // Convert calculated RH back to vapor density of surface and deep layers.
     693      699139 :     rv_surf_layer = PsyRhovFnTdbRh(state, Taver, RH_surf_layer);
     694      699139 :     rv_deep_layer = PsyRhovFnTdbRh(state, Taver, RH_deep_layer);
     695             : 
     696             :     // Calculate surface-layer and deep-layer vapor pressures [Pa]
     697      699139 :     PV_surf_layer = RH_surf_layer * std::exp(23.7093 - 4111.0 / (Taver + 237.7));
     698      699139 :     PV_deep_layer = RH_deep_layer * std::exp(23.7093 - 4111.0 / (Taver + 237.7));
     699             : 
     700             :     // Calculate vapor density at physical material surface (surface-layer/air interface). This is used to calculate total moisture flow terms for
     701             :     // each zone in HeatBalanceSurfaceManager
     702      699139 :     rv_surface = rv_surf_layer - mass_flux_zone * RSurfaceLayer;
     703             : 
     704             :     // Calculate heat flux from latent-sensible conversion due to moisture adsorption [W/m^2]
     705      699139 :     heat_flux_latent = mass_flux_zone * Lam;
     706             : 
     707             :     // Put results in the reporting variables
     708             :     // Will add RH and W of deep layer as outputs
     709             :     // 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
     710      699139 :     EMPDReportVarsData &rvd = state.dataMoistureBalEMPD->EMPDReportVars(SurfNum);
     711      699139 :     rvd.rv_surface = rv_surface;
     712      699139 :     rvd.RH_surface_layer = RH_surf_layer * 100.0;
     713      699139 :     rvd.RH_deep_layer = RH_deep_layer * 100.0;
     714      699139 :     rvd.w_surface_layer = 0.622 * PV_surf_layer / (state.dataEnvrn->OutBaroPress - PV_surf_layer);
     715      699139 :     rvd.w_deep_layer = 0.622 * PV_deep_layer / (state.dataEnvrn->OutBaroPress - PV_deep_layer);
     716      699139 :     rvd.mass_flux_zone = mass_flux_zone;
     717      699139 :     rvd.mass_flux_deep = mass_flux_deep_layer;
     718      699139 :     rvd.u_surface_layer =
     719      699139 :         material->MoistACoeff * pow(RH_surf_layer, material->MoistBCoeff) + material->MoistCCoeff * pow(RH_surf_layer, material->MoistDCoeff);
     720      699139 :     rvd.u_deep_layer =
     721      699139 :         material->MoistACoeff * pow(RH_deep_layer, material->MoistBCoeff) + material->MoistCCoeff * pow(RH_deep_layer, material->MoistDCoeff);
     722             : }
     723             : 
     724      150018 : void UpdateMoistureBalanceEMPD(EnergyPlusData &state, int const SurfNum) // Surface number
     725             : {
     726             : 
     727             :     // SUBROUTINE INFORMATION:
     728             :     //   Authors:        Muthusamy Swami and Lixing Gu
     729             :     //   Date writtenn:  August, 1999
     730             :     //   Modified:       na
     731             :     //   Re-engineered:  na
     732             : 
     733             :     // PURPOSE OF THIS SUBROUTINE:
     734             :     // Update inside surface vapor density
     735             : 
     736      150018 :     state.dataMstBalEMPD->RVSurfaceOld(SurfNum) = state.dataMstBalEMPD->RVSurface(SurfNum);
     737      150018 :     state.dataMstBalEMPD->RVdeepOld(SurfNum) = state.dataMstBalEMPD->RVDeepLayer(SurfNum);
     738      150018 :     state.dataMstBalEMPD->RVSurfLayerOld(SurfNum) = state.dataMstBalEMPD->RVSurfLayer(SurfNum);
     739      150018 : }
     740             : 
     741           2 : void ReportMoistureBalanceEMPD(EnergyPlusData &state)
     742             : {
     743             : 
     744             :     // SUBROUTINE INFORMATION:
     745             :     //       AUTHOR         Lixing Gu
     746             :     //       DATE WRITTEN   August 2005
     747             :     //       MODIFIED       na
     748             :     //       RE-ENGINEERED  na
     749             : 
     750             :     // PURPOSE OF THIS SUBROUTINE:
     751             :     // This routine gives a detailed report to the user about
     752             :     // EMPD Properties of each construction.
     753             : 
     754             :     // Using/Aliasing
     755             :     using General::ScanForReports;
     756             : 
     757             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     758             :     bool DoReport;
     759             : 
     760             :     int ConstrNum;
     761             :     int MatNum;
     762             : 
     763           2 :     ScanForReports(state, "Constructions", DoReport, "Constructions");
     764             : 
     765           2 :     if (!DoReport) return;
     766             :     //   Write Descriptions
     767           2 :     print(state.files.eio,
     768             :           "{}",
     769             :           "! <Construction EMPD>, Construction Name, Inside Layer Material Name, Vapor Resistance Factor, a, b, "
     770             :           "c, d, Surface Penetration Depth {m}, Deep Penetration Depth {m}, Coating Vapor Resistance Factor, "
     771             :           "Coating Thickness {m}\n");
     772             : 
     773          13 :     for (ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
     774          11 :         if (state.dataConstruction->Construct(ConstrNum).TypeIsWindow) continue;
     775           9 :         MatNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(state.dataConstruction->Construct(ConstrNum).TotLayers);
     776           9 :         auto const *thisMaterial = dynamic_cast<const Material::MaterialChild *>(state.dataMaterial->Material(MatNum));
     777           9 :         assert(thisMaterial != nullptr);
     778           9 :         if (thisMaterial->EMPDMaterialProps) {
     779             :             static constexpr std::string_view Format_700(
     780             :                 " Construction EMPD, {}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}, {:8.4F}\n");
     781           0 :             print(state.files.eio,
     782             :                   Format_700,
     783           0 :                   state.dataConstruction->Construct(ConstrNum).Name,
     784           0 :                   thisMaterial->Name,
     785           0 :                   thisMaterial->EMPDmu,
     786           0 :                   thisMaterial->MoistACoeff,
     787           0 :                   thisMaterial->MoistBCoeff,
     788           0 :                   thisMaterial->MoistCCoeff,
     789           0 :                   thisMaterial->MoistDCoeff,
     790           0 :                   thisMaterial->EMPDSurfaceDepth,
     791           0 :                   thisMaterial->EMPDDeepDepth,
     792           0 :                   thisMaterial->EMPDmuCoating,
     793           0 :                   thisMaterial->EMPDCoatingThickness);
     794             :         }
     795             :     }
     796             : }
     797             : 
     798             : } // namespace EnergyPlus::MoistureBalanceEMPDManager

Generated by: LCOV version 1.14