LCOV - code coverage report
Current view: top level - EnergyPlus - DataHeatBalance.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 71.9 % 481 346
Test Date: 2025-05-22 16:09:37 Functions: 100.0 % 15 15

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Array.functions.hh>
      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/DataHeatBalSurface.hh>
      60              : #include <EnergyPlus/DataHeatBalance.hh>
      61              : #include <EnergyPlus/DataSurfaces.hh>
      62              : #include <EnergyPlus/DaylightingManager.hh>
      63              : #include <EnergyPlus/Material.hh>
      64              : #include <EnergyPlus/OutputProcessor.hh>
      65              : #include <EnergyPlus/UtilityRoutines.hh>
      66              : 
      67              : namespace EnergyPlus::DataHeatBalance {
      68              : 
      69              : // MODULE INFORMATION:
      70              : //       AUTHOR         Rick Strand
      71              : //       DATE WRITTEN   August 1997 (rewritten)
      72              : //       MODIFIED       Aug-Oct 1997 RKS (added derived types)
      73              : //       MODIFIED       Feb 1999 (FW) Added visible radiation parameters,
      74              : //                      WindowShadingControl type and SurfaceWindowCalc type
      75              : //                      Sep 1999 (FW) Added/modified Window4 gas variables
      76              : //                      Jul 2003 (CC) Added reference temperature variable for air models
      77              : //                      Aug 2003 (FW) Added FractionReturnAirPlenTempCoeff1 and
      78              : //                      FractionReturnAirPlenTempCoeff2 to Type LightsData
      79              : //                      Nov 2003 (FW) Add FullExteriorWithRefl and FullInteriorExteriorWithRefl
      80              : //                       as SolarDistribution values
      81              : //                      Dec 2003 (PGE) Added Zone List and Zone Group; added SNLoad variables
      82              : //                      August 2006 (COP) Added variable k coefficient and PCM enthalpy.
      83              : //                      Dec 2006 (DJS-PSU) Added ecoroof material
      84              : //                      Dec 2008 TH added new properties to MaterialProperties and
      85              : //                              ConstructionData for thermochromic windows
      86              : //       RE-ENGINEERED  na
      87              : 
      88              : // PURPOSE OF THIS MODULE:
      89              : // This module should contain the information that is needed to pass
      90              : // from the Heat Balance Module and all of the Zone Initializations
      91              : // such as ConductionTransferFunction, GlassCalculation,
      92              : // SolarShading, etc. Modules.
      93              : 
      94              : // Using/Aliasing
      95              : using namespace DataVectorTypes;
      96              : using DataBSDFWindow::BSDFLayerAbsorpStruct;
      97              : using DataBSDFWindow::BSDFWindowInputStruct;
      98              : 
      99              : // Functions
     100              : 
     101           72 : Real64 SpaceData::sumHATsurf(EnergyPlusData &state)
     102              : {
     103              :     // PURPOSE OF THIS FUNCTION:
     104              :     // This function calculates the space sum of Hc*Area*Tsurf.
     105              : 
     106           72 :     Real64 sumHATsurf = 0.0;
     107              : 
     108          168 :     for (int surfNum = this->HTSurfaceFirst; surfNum <= this->HTSurfaceLast; ++surfNum) {
     109           96 :         Real64 Area = state.dataSurface->Surface(surfNum).Area;
     110              : 
     111           96 :         if (state.dataSurface->Surface(surfNum).Class == DataSurfaces::SurfaceClass::Window) {
     112            0 :             if (state.dataSurface->SurfWinDividerArea(surfNum) > 0.0) {
     113            0 :                 if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(surfNum))) {
     114              :                     // The area is the shade or blind area = sum of the glazing area and the divider area (which is zero if no divider)
     115            0 :                     Area += state.dataSurface->SurfWinDividerArea(surfNum);
     116              :                 } else {
     117              :                     // Window divider contribution (only for window with divider and no interior shade or blind)
     118            0 :                     sumHATsurf += state.dataHeatBalSurf->SurfHConvInt(surfNum) * state.dataSurface->SurfWinDividerArea(surfNum) *
     119            0 :                                   (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(surfNum)) * state.dataSurface->SurfWinDividerTempIn(surfNum);
     120              :                 }
     121              :             }
     122              : 
     123            0 :             if (state.dataSurface->SurfWinFrameArea(surfNum) > 0.0) {
     124              :                 // Window frame contribution
     125            0 :                 sumHATsurf += state.dataHeatBalSurf->SurfHConvInt(surfNum) * state.dataSurface->SurfWinFrameArea(surfNum) *
     126            0 :                               (1.0 + state.dataSurface->SurfWinProjCorrFrIn(surfNum)) * state.dataSurface->SurfWinFrameTempIn(surfNum);
     127              :             }
     128              :         }
     129              : 
     130           96 :         sumHATsurf += state.dataHeatBalSurf->SurfHConvInt(surfNum) * Area * state.dataHeatBalSurf->SurfTempInTmp(surfNum);
     131              :     }
     132              : 
     133           72 :     return sumHATsurf;
     134              : }
     135              : 
     136           24 : Real64 ZoneData::sumHATsurf(EnergyPlusData &state)
     137              : {
     138           24 :     Real64 sumHATsurf = 0.0;
     139           96 :     for (int spaceNum : this->spaceIndexes) {
     140           72 :         sumHATsurf += state.dataHeatBal->space(spaceNum).sumHATsurf(state);
     141              :     }
     142           24 :     return sumHATsurf;
     143              : }
     144       336921 : void ZoneData::SetOutBulbTempAt(EnergyPlusData &state)
     145              : {
     146              :     // SUBROUTINE INFORMATION:
     147              :     //       AUTHOR         Noel Keen (LBL)/Linda Lawrie
     148              :     //       DATE WRITTEN   August 2010
     149              :     //       MODIFIED       na
     150              :     //       RE-ENGINEERED  na
     151              : 
     152              :     // PURPOSE OF THIS SUBROUTINE:
     153              :     // Routine provides facility for doing bulk Set Temperature at Height.
     154              : 
     155       336921 :     if (state.dataEnvrn->SiteTempGradient == 0.0) {
     156            0 :         OutDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
     157            0 :         OutWetBulbTemp = state.dataEnvrn->OutWetBulbTemp;
     158              :     } else {
     159              :         // Base temperatures at Z = 0 (C)
     160       336921 :         Real64 const BaseDryTemp(state.dataEnvrn->OutDryBulbTemp + state.dataEnvrn->WeatherFileTempModCoeff);
     161       336921 :         Real64 const BaseWetTemp(state.dataEnvrn->OutWetBulbTemp + state.dataEnvrn->WeatherFileTempModCoeff);
     162              : 
     163       336921 :         Real64 const Z(Centroid.z); // Centroid value
     164       336921 :         if (Z <= 0.0) {
     165         6371 :             OutDryBulbTemp = BaseDryTemp;
     166         6371 :             OutWetBulbTemp = BaseWetTemp;
     167              :         } else {
     168       330550 :             OutDryBulbTemp = BaseDryTemp - state.dataEnvrn->SiteTempGradient * DataEnvironment::EarthRadius * Z / (DataEnvironment::EarthRadius + Z);
     169       330550 :             OutWetBulbTemp = BaseWetTemp - state.dataEnvrn->SiteTempGradient * DataEnvironment::EarthRadius * Z / (DataEnvironment::EarthRadius + Z);
     170              :         }
     171              :     }
     172       336921 : }
     173              : 
     174       336646 : void ZoneData::SetWindSpeedAt(EnergyPlusData const &state, Real64 const fac)
     175              : {
     176              :     // SUBROUTINE INFORMATION:
     177              :     //       AUTHOR         Linda Lawrie
     178              :     //       DATE WRITTEN   June 2013
     179              :     //       MODIFIED       na
     180              :     //       RE-ENGINEERED  na
     181              : 
     182              :     // PURPOSE OF THIS SUBROUTINE:
     183              :     // Routine provides facility for doing bulk Set Windspeed at Height.
     184              : 
     185       336646 :     if (state.dataEnvrn->SiteWindExp == 0.0) {
     186            0 :         WindSpeed = state.dataEnvrn->WindSpeed;
     187              :     } else {
     188       336646 :         Real64 const Z(Centroid.z); // Centroid value
     189       336646 :         if (Z <= 0.0) {
     190         6356 :             WindSpeed = 0.0;
     191              :         } else {
     192              :             //  [Met] - at meterological Station, Height of measurement is usually 10m above ground
     193              :             //  LocalWindSpeed = Windspeed [Met] * (Wind Boundary LayerThickness [Met]/Height [Met])**Wind Exponent[Met] &
     194              :             //                     * (Height above ground / Site Wind Boundary Layer Thickness) ** Site Wind Exponent
     195       330290 :             WindSpeed = fac * std::pow(Z, state.dataEnvrn->SiteWindExp);
     196              :         }
     197              :     }
     198       336646 : }
     199              : 
     200       336646 : void ZoneData::SetWindDirAt(Real64 const fac)
     201              : {
     202       336646 :     WindDir = fac;
     203       336646 : }
     204              : 
     205          166 : void AirReportVars::setUpOutputVars(EnergyPlusData &state, std::string_view prefix, std::string const &name)
     206              : {
     207          498 :     SetupOutputVariable(state,
     208          332 :                         format("{} Mean Air Temperature", prefix),
     209              :                         Constant::Units::C,
     210          166 :                         this->MeanAirTemp,
     211              :                         OutputProcessor::TimeStepType::Zone,
     212              :                         OutputProcessor::StoreType::Average,
     213              :                         name);
     214          498 :     SetupOutputVariable(state,
     215          332 :                         format("{} Wetbulb Globe Temperature", prefix),
     216              :                         Constant::Units::C,
     217          166 :                         this->WetbulbGlobeTemp,
     218              :                         OutputProcessor::TimeStepType::Zone,
     219              :                         OutputProcessor::StoreType::Average,
     220              :                         name);
     221          498 :     SetupOutputVariable(state,
     222          332 :                         format("{} Operative Temperature", prefix),
     223              :                         Constant::Units::C,
     224          166 :                         this->OperativeTemp,
     225              :                         OutputProcessor::TimeStepType::Zone,
     226              :                         OutputProcessor::StoreType::Average,
     227              :                         name);
     228          498 :     SetupOutputVariable(state,
     229          332 :                         format("{} Mean Air Dewpoint Temperature", prefix),
     230              :                         Constant::Units::C,
     231          166 :                         this->MeanAirDewPointTemp,
     232              :                         OutputProcessor::TimeStepType::Zone,
     233              :                         OutputProcessor::StoreType::Average,
     234              :                         name);
     235          498 :     SetupOutputVariable(state,
     236          332 :                         format("{} Mean Air Humidity Ratio", prefix),
     237              :                         Constant::Units::kgWater_kgDryAir,
     238          166 :                         this->MeanAirHumRat,
     239              :                         OutputProcessor::TimeStepType::Zone,
     240              :                         OutputProcessor::StoreType::Average,
     241              :                         name);
     242          498 :     SetupOutputVariable(state,
     243          332 :                         format("{} Air Heat Balance Internal Convective Heat Gain Rate", prefix),
     244              :                         Constant::Units::W,
     245          166 :                         this->SumIntGains,
     246              :                         OutputProcessor::TimeStepType::System,
     247              :                         OutputProcessor::StoreType::Average,
     248              :                         name);
     249          498 :     SetupOutputVariable(state,
     250          332 :                         format("{} Air Heat Balance Surface Convection Rate", prefix),
     251              :                         Constant::Units::W,
     252          166 :                         this->SumHADTsurfs,
     253              :                         OutputProcessor::TimeStepType::System,
     254              :                         OutputProcessor::StoreType::Average,
     255              :                         name);
     256          498 :     SetupOutputVariable(state,
     257          332 :                         format("{} Air Heat Balance Interzone Air Transfer Rate", prefix),
     258              :                         Constant::Units::W,
     259          166 :                         this->SumMCpDTzones,
     260              :                         OutputProcessor::TimeStepType::System,
     261              :                         OutputProcessor::StoreType::Average,
     262              :                         name);
     263          498 :     SetupOutputVariable(state,
     264          332 :                         format("{} Air Heat Balance Outdoor Air Transfer Rate", prefix),
     265              :                         Constant::Units::W,
     266          166 :                         this->SumMCpDtInfil,
     267              :                         OutputProcessor::TimeStepType::System,
     268              :                         OutputProcessor::StoreType::Average,
     269              :                         name);
     270          498 :     SetupOutputVariable(state,
     271          332 :                         format("{} Air Heat Balance System Air Transfer Rate", prefix),
     272              :                         Constant::Units::W,
     273          166 :                         this->SumMCpDTsystem,
     274              :                         OutputProcessor::TimeStepType::System,
     275              :                         OutputProcessor::StoreType::Average,
     276              :                         name);
     277          498 :     SetupOutputVariable(state,
     278          332 :                         format("{} Air Heat Balance System Convective Heat Gain Rate", prefix),
     279              :                         Constant::Units::W,
     280          166 :                         this->SumNonAirSystem,
     281              :                         OutputProcessor::TimeStepType::System,
     282              :                         OutputProcessor::StoreType::Average,
     283              :                         name);
     284          498 :     SetupOutputVariable(state,
     285          332 :                         format("{} Air Heat Balance Air Energy Storage Rate", prefix),
     286              :                         Constant::Units::W,
     287          166 :                         this->CzdTdt,
     288              :                         OutputProcessor::TimeStepType::System,
     289              :                         OutputProcessor::StoreType::Average,
     290              :                         name);
     291          166 :     if (state.dataGlobal->DisplayAdvancedReportVariables) {
     292            0 :         SetupOutputVariable(state,
     293            0 :                             format("{} Air Heat Balance Deviation Rate", prefix),
     294              :                             Constant::Units::W,
     295            0 :                             this->imBalance,
     296              :                             OutputProcessor::TimeStepType::System,
     297              :                             OutputProcessor::StoreType::Average,
     298              :                             name);
     299              :     }
     300          166 : }
     301              : 
     302       250148 : void SetZoneOutBulbTempAt(EnergyPlusData &state)
     303              : {
     304       587069 :     for (auto &zone : state.dataHeatBal->Zone) {
     305       336921 :         zone.SetOutBulbTempAt(state);
     306              :     }
     307       250148 : }
     308              : 
     309       250148 : void CheckZoneOutBulbTempAt(EnergyPlusData &state)
     310              : {
     311              :     // Using/Aliasing
     312              :     using DataEnvironment::SetOutBulbTempAt_error;
     313              : 
     314       250148 :     Real64 minBulb = 0.0;
     315       587069 :     for (auto &zone : state.dataHeatBal->Zone) {
     316       336921 :         minBulb = min(minBulb, zone.OutDryBulbTemp, zone.OutWetBulbTemp);
     317       336921 :         if (minBulb < -100.0) SetOutBulbTempAt_error(state, "Zone", zone.Centroid.z, zone.Name);
     318              :     }
     319       250148 : }
     320              : 
     321       249956 : void SetZoneWindSpeedAt(EnergyPlusData &state)
     322              : {
     323       249956 :     Real64 const fac(state.dataEnvrn->WindSpeed * state.dataEnvrn->WeatherFileWindModCoeff *
     324       249956 :                      std::pow(state.dataEnvrn->SiteWindBLHeight, -state.dataEnvrn->SiteWindExp));
     325       586602 :     for (auto &zone : state.dataHeatBal->Zone) {
     326       336646 :         zone.SetWindSpeedAt(state, fac);
     327              :     }
     328       249956 : }
     329              : 
     330       249956 : void SetZoneWindDirAt(EnergyPlusData &state)
     331              : {
     332              :     // Using/Aliasing
     333       249956 :     Real64 const fac(state.dataEnvrn->WindDir);
     334       586602 :     for (auto &zone : state.dataHeatBal->Zone) {
     335       336646 :         zone.SetWindDirAt(fac);
     336              :     }
     337       249956 : }
     338              : 
     339          787 : void CheckAndSetConstructionProperties(EnergyPlusData &state,
     340              :                                        int const ConstrNum, // Construction number to be set/checked
     341              :                                        bool &ErrorsFound    // error flag that is set when certain errors have occurred
     342              : )
     343              : {
     344              : 
     345              :     // SUBROUTINE INFORMATION:
     346              :     //       AUTHOR         Linda Lawrie
     347              :     //       DATE WRITTEN   December 2006
     348              : 
     349              :     // This routine checks some properties of entered constructions; sets some properties; and sets
     350              :     // an error flag for certain error conditions.
     351          787 :     auto &s_mat = state.dataMaterial;
     352              : 
     353          787 :     auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
     354          787 :     int TotLayers = thisConstruct.TotLayers;                // Number of layers in a construction
     355          787 :     if (TotLayers == 0) return;                             // error condition, hopefully caught elsewhere
     356          787 :     int InsideLayer = TotLayers;                            // Inside Layer of Construct; for window construct, layer no. of inside glass
     357          787 :     if (thisConstruct.LayerPoint(InsideLayer) <= 0) return; // Error condition
     358              : 
     359              :     //   window screen is not allowed on inside layer
     360              : 
     361          784 :     thisConstruct.DayltPropPtr = 0;
     362          784 :     int InsideMaterNum = thisConstruct.LayerPoint(InsideLayer); // Material "number" of the Inside layer
     363          784 :     if (InsideMaterNum != 0) {
     364          784 :         auto const *mat = s_mat->materials(InsideMaterNum);
     365          784 :         thisConstruct.InsideAbsorpVis = mat->AbsorpVisible;
     366          784 :         thisConstruct.InsideAbsorpSolar = mat->AbsorpSolar;
     367              : 
     368              :         // Following line applies only to opaque surfaces; it is recalculated later for windows.
     369          784 :         thisConstruct.ReflectVisDiffBack = 1.0 - mat->AbsorpVisible;
     370              :     }
     371              : 
     372          784 :     int OutsideMaterNum = thisConstruct.LayerPoint(1); // Material "number" of the Outside layer
     373          784 :     if (OutsideMaterNum != 0) {
     374          784 :         auto const *mat = s_mat->materials(OutsideMaterNum);
     375          784 :         thisConstruct.OutsideAbsorpVis = mat->AbsorpVisible;
     376          784 :         thisConstruct.OutsideAbsorpSolar = mat->AbsorpSolar;
     377              :     }
     378              : 
     379          784 :     thisConstruct.TotSolidLayers = 0;
     380          784 :     thisConstruct.TotGlassLayers = 0;
     381          784 :     thisConstruct.AbsDiffShade = 0.0;
     382              : 
     383              :     // Check if any layer is glass, gas, shade, screen or blind; if so it is considered a window construction for
     384              :     // purposes of error checking.
     385              : 
     386          784 :     thisConstruct.TypeIsWindow = false;
     387         2206 :     for (int Layer = 1; Layer <= TotLayers; ++Layer) {
     388         1422 :         int const MaterNum = thisConstruct.LayerPoint(Layer);
     389         1422 :         if (MaterNum == 0) continue; // error -- has been caught will stop program later
     390         1422 :         auto const *mat = s_mat->materials(MaterNum);
     391         1422 :         thisConstruct.TypeIsWindow =
     392         1285 :             (mat->group == Material::Group::Glass || mat->group == Material::Group::Gas || mat->group == Material::Group::GasMixture ||
     393         1249 :              mat->group == Material::Group::Shade || mat->group == Material::Group::Blind || mat->group == Material::Group::Screen ||
     394         1245 :              mat->group == Material::Group::GlassSimple || mat->group == Material::Group::ComplexShade ||
     395         1220 :              mat->group == Material::Group::ComplexWindowGap || mat->group == Material::Group::GlassEQL || mat->group == Material::Group::ShadeEQL ||
     396         3907 :              mat->group == Material::Group::DrapeEQL || mat->group == Material::Group::ScreenEQL || mat->group == Material::Group::BlindEQL ||
     397         1200 :              mat->group == Material::Group::WindowGapEQL);
     398         1422 :         bool TypeIsNotWindow =
     399         1422 :             (mat->group == Material::Group::Invalid || mat->group == Material::Group::AirGap || mat->group == Material::Group::Regular ||
     400         2844 :              mat->group == Material::Group::EcoRoof || mat->group == Material::Group::IRTransparent);
     401         1422 :         if (!thisConstruct.TypeIsWindow && !TypeIsNotWindow) assert(false);
     402              :     }
     403              : 
     404          784 :     if (InsideMaterNum == 0) return;
     405          784 :     auto const *matInside = s_mat->materials(InsideMaterNum);
     406          784 :     if (OutsideMaterNum == 0) return;
     407          784 :     auto const *matOutside = s_mat->materials(OutsideMaterNum);
     408              : 
     409          784 :     if (thisConstruct.TypeIsWindow) {
     410              : 
     411          131 :         bool WrongMaterialsMix = false;
     412          131 :         thisConstruct.NumCTFTerms = 0;
     413          131 :         thisConstruct.NumHistories = 0;
     414          364 :         for (int Layer = 1; Layer <= TotLayers; ++Layer) {
     415          233 :             int const MaterNum = thisConstruct.LayerPoint(Layer);
     416          233 :             if (MaterNum == 0) continue; // error -- has been caught will stop program later
     417          233 :             auto const *mat = s_mat->materials(MaterNum);
     418          233 :             WrongMaterialsMix =
     419          293 :                 !((mat->group == Material::Group::Glass) || (mat->group == Material::Group::Gas) || (mat->group == Material::Group::GasMixture) ||
     420           60 :                   (mat->group == Material::Group::Shade) || (mat->group == Material::Group::Blind) || (mat->group == Material::Group::Screen) ||
     421           56 :                   (mat->group == Material::Group::GlassSimple) || (mat->group == Material::Group::ComplexShade) ||
     422           31 :                   (mat->group == Material::Group::ComplexWindowGap) || (mat->group == Material::Group::GlassEQL) ||
     423           15 :                   (mat->group == Material::Group::ShadeEQL) || (mat->group == Material::Group::DrapeEQL) ||
     424           15 :                   (mat->group == Material::Group::ScreenEQL) || (mat->group == Material::Group::BlindEQL) ||
     425           11 :                   (mat->group == Material::Group::WindowGapEQL));
     426              :         }
     427              : 
     428          131 :         if (WrongMaterialsMix) { // Illegal material for a window construction
     429            0 :             ShowSevereError(state,
     430            0 :                             format("Error: Window construction={} has materials other than glass, gas, shade, screen, blind, complex shading, "
     431              :                                    "complex gap, or simple system.",
     432            0 :                                    thisConstruct.Name));
     433            0 :             ErrorsFound = true;
     434              :             // Do not check number of layers for BSDF type of window since that can be handled
     435          131 :         } else if ((TotLayers > 8) && (!thisConstruct.WindowTypeBSDF) &&
     436            0 :                    (!thisConstruct.WindowTypeEQL)) { // Too many layers for a window construction
     437            0 :             ShowSevereError(state,
     438            0 :                             format("CheckAndSetConstructionProperties: Window construction={} has too many layers (max of 8 allowed -- 4 glass + 3 "
     439              :                                    "gap + 1 shading device).",
     440            0 :                                    thisConstruct.Name));
     441            0 :             ErrorsFound = true;
     442              : 
     443          131 :         } else if (TotLayers == 1) {
     444           83 :             auto const *mat = s_mat->materials(thisConstruct.LayerPoint(1));
     445           83 :             Material::Group matGroup = mat->group;
     446           83 :             if ((matGroup == Material::Group::Shade) || (matGroup == Material::Group::Gas) || (matGroup == Material::Group::GasMixture) ||
     447           83 :                 (matGroup == Material::Group::Blind) || (matGroup == Material::Group::Screen) || (matGroup == Material::Group::ComplexShade) ||
     448              :                 (matGroup == Material::Group::ComplexWindowGap)) {
     449            0 :                 ShowSevereError(state,
     450            0 :                                 format("CheckAndSetConstructionProperties: The single-layer window construction={} has a gas, complex gap, shade, "
     451              :                                        "complex shade, screen or blind material; it should be glass of simple glazing system.",
     452            0 :                                        thisConstruct.Name));
     453            0 :                 ErrorsFound = true;
     454              :             }
     455              :         }
     456              : 
     457              :         // Find total glass layers, total shade/blind layers and total gas layers in a window construction
     458              : 
     459          131 :         bool WrongWindowLayering = false;
     460          131 :         int TotGlassLayers = 0;
     461          131 :         int TotShadeLayers = 0; // Includes shades, blinds, and screens
     462          131 :         int TotGasLayers = 0;
     463          364 :         for (int Layer = 1; Layer <= TotLayers; ++Layer) {
     464          233 :             int const MaterNum = thisConstruct.LayerPoint(Layer);
     465          233 :             if (MaterNum == 0) continue; // error -- has been caught will stop program later
     466          233 :             auto const *mat = s_mat->materials(MaterNum);
     467          233 :             if (mat->group == Material::Group::Glass) ++TotGlassLayers;
     468          233 :             if (mat->group == Material::Group::GlassSimple) ++TotGlassLayers;
     469          233 :             if (mat->group == Material::Group::Shade || mat->group == Material::Group::Blind || mat->group == Material::Group::Screen ||
     470          229 :                 mat->group == Material::Group::ComplexShade)
     471            5 :                 ++TotShadeLayers;
     472          233 :             if (mat->group == Material::Group::Gas || mat->group == Material::Group::GasMixture || mat->group == Material::Group::ComplexWindowGap)
     473           38 :                 ++TotGasLayers;
     474          233 :             if (Layer < TotLayers) {
     475          102 :                 int const MaterNumNext = thisConstruct.LayerPoint(Layer + 1);
     476              :                 // Adjacent layers of same type not allowed
     477          102 :                 if (MaterNumNext == 0) continue;
     478          102 :                 if (mat->group == s_mat->materials(MaterNumNext)->group) WrongWindowLayering = true;
     479              :             }
     480              :         }
     481              : 
     482              :         // It is not necessary to check rest of BSDF window structure since that is performed inside TARCOG90 routine.
     483              :         // That routine also allow structures which are not allowed in rest of this routine
     484          131 :         if (thisConstruct.WindowTypeBSDF) {
     485            1 :             thisConstruct.TotGlassLayers = TotGlassLayers;
     486            1 :             thisConstruct.TotSolidLayers = TotGlassLayers + TotShadeLayers;
     487            1 :             thisConstruct.InsideAbsorpThermal = matInside->AbsorpThermalBack;
     488            1 :             thisConstruct.OutsideAbsorpThermal = matOutside->AbsorpThermalFront;
     489            1 :             return;
     490              :         }
     491              : 
     492          130 :         if (thisConstruct.WindowTypeEQL) {
     493            8 :             thisConstruct.InsideAbsorpThermal = matInside->AbsorpThermalBack;
     494            8 :             thisConstruct.OutsideAbsorpThermal = matOutside->AbsorpThermalFront;
     495            8 :             return;
     496              :         }
     497              : 
     498          122 :         if (matOutside->group == Material::Group::Gas || matOutside->group == Material::Group::GasMixture ||
     499          122 :             matInside->group == Material::Group::Gas || matInside->group == Material::Group::GasMixture)
     500            0 :             WrongWindowLayering = true;                     // Gas cannot be first or last layer
     501          122 :         if (TotShadeLayers > 1) WrongWindowLayering = true; // At most one shade, screen or blind allowed
     502              : 
     503              :         // If there is a diffusing glass layer no shade, screen or blind is allowed
     504          320 :         for (int Layer = 1; Layer <= TotLayers; ++Layer) {
     505          198 :             int const MatNum = thisConstruct.LayerPoint(Layer);
     506          198 :             if (MatNum == 0) continue; // error -- has been caught will stop program later
     507          198 :             auto const *mat = s_mat->materials(MatNum);
     508          198 :             if (mat->group != Material::Group::Glass) continue;
     509          135 :             auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
     510          135 :             assert(matGlass != nullptr);
     511          135 :             if (matGlass->SolarDiffusing && TotShadeLayers > 0) {
     512            0 :                 ErrorsFound = true;
     513            0 :                 ShowSevereError(state, format("CheckAndSetConstructionProperties: Window construction={}", thisConstruct.Name));
     514            0 :                 ShowContinueError(state, format("has diffusing glass={} and a shade, screen or blind layer.", matGlass->Name));
     515            0 :                 break;
     516              :             }
     517              :         }
     518              : 
     519              :         // If there is a diffusing glass layer it must be the innermost layer
     520          122 :         if (TotGlassLayers > 1) {
     521           36 :             int GlassLayNum = 0;
     522          144 :             for (int Layer = 1; Layer <= TotLayers; ++Layer) {
     523          108 :                 int const MatNum = thisConstruct.LayerPoint(Layer);
     524          108 :                 if (MatNum == 0) continue; // error -- has been caught will stop program later
     525          108 :                 auto const *mat = s_mat->materials(MatNum);
     526          108 :                 if (mat->group != Material::Group::Glass) continue;
     527              : 
     528           72 :                 auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
     529           72 :                 assert(matGlass != nullptr);
     530           72 :                 ++GlassLayNum;
     531           72 :                 if (GlassLayNum < TotGlassLayers && matGlass->SolarDiffusing) {
     532            0 :                     ErrorsFound = true;
     533            0 :                     ShowSevereError(state, format("CheckAndSetConstructionProperties: Window construction={}", thisConstruct.Name));
     534            0 :                     ShowContinueError(state, format("has diffusing glass={} that is not the innermost glass layer.", matGlass->Name));
     535              :                 }
     536              :             }
     537              :         }
     538              : 
     539              :         // interior window screen is not allowed. Check for invalid between-glass screen is checked below.
     540          122 :         if (TotShadeLayers == 1 && matInside->group == Material::Group::Screen && TotLayers != 1) {
     541            0 :             WrongWindowLayering = true;
     542              :         }
     543              : 
     544              :         // Consistency checks for a construction with a between-glass shade or blind
     545              : 
     546          122 :         if (TotShadeLayers == 1 && matOutside->group != Material::Group::Shade && matOutside->group != Material::Group::Blind &&
     547            4 :             matOutside->group != Material::Group::Screen && matInside->group != Material::Group::Shade &&
     548            2 :             matInside->group != Material::Group::Blind && matInside->group != Material::Group::ComplexShade && !WrongWindowLayering) {
     549              : 
     550              :             // This is a construction with a between-glass shade or blind
     551              : 
     552            0 :             if (TotGlassLayers >= 4) {
     553              :                 // Quadruple pane not allowed.
     554            0 :                 WrongWindowLayering = true;
     555            0 :             } else if (TotGlassLayers == 2 || TotGlassLayers == 3) {
     556            0 :                 bool ValidBGShadeBlindConst = false;
     557            0 :                 if (TotGlassLayers == 2) {
     558            0 :                     if (TotLayers != 5) {
     559            0 :                         WrongWindowLayering = true;
     560              :                     } else {
     561            0 :                         if (matOutside->group == Material::Group::Glass &&
     562            0 :                             (s_mat->materials(thisConstruct.LayerPoint(2))->group == Material::Group::Gas ||
     563            0 :                              s_mat->materials(thisConstruct.LayerPoint(2))->group == Material::Group::GasMixture) &&
     564            0 :                             ((s_mat->materials(thisConstruct.LayerPoint(3))->group == Material::Group::Shade ||
     565            0 :                               s_mat->materials(thisConstruct.LayerPoint(3))->group == Material::Group::Blind) &&
     566            0 :                              s_mat->materials(thisConstruct.LayerPoint(3))->group != Material::Group::Screen) &&
     567            0 :                             (s_mat->materials(thisConstruct.LayerPoint(4))->group == Material::Group::Gas ||
     568            0 :                              s_mat->materials(thisConstruct.LayerPoint(4))->group == Material::Group::GasMixture) &&
     569            0 :                             s_mat->materials(thisConstruct.LayerPoint(5))->group == Material::Group::Glass)
     570            0 :                             ValidBGShadeBlindConst = true;
     571              :                     }
     572              :                 } else { // TotGlassLayers = 3
     573            0 :                     if (TotLayers != 7) {
     574            0 :                         WrongWindowLayering = true;
     575              :                     } else {
     576            0 :                         if (matOutside->group == Material::Group::Glass &&
     577            0 :                             (s_mat->materials(thisConstruct.LayerPoint(2))->group == Material::Group::Gas ||
     578            0 :                              s_mat->materials(thisConstruct.LayerPoint(2))->group == Material::Group::GasMixture) &&
     579            0 :                             s_mat->materials(thisConstruct.LayerPoint(3))->group == Material::Group::Glass &&
     580            0 :                             (s_mat->materials(thisConstruct.LayerPoint(4))->group == Material::Group::Gas ||
     581            0 :                              s_mat->materials(thisConstruct.LayerPoint(4))->group == Material::Group::GasMixture) &&
     582            0 :                             ((s_mat->materials(thisConstruct.LayerPoint(5))->group == Material::Group::Shade ||
     583            0 :                               s_mat->materials(thisConstruct.LayerPoint(5))->group == Material::Group::Blind) &&
     584            0 :                              s_mat->materials(thisConstruct.LayerPoint(5))->group != Material::Group::Screen) &&
     585            0 :                             (s_mat->materials(thisConstruct.LayerPoint(6))->group == Material::Group::Gas ||
     586            0 :                              s_mat->materials(thisConstruct.LayerPoint(6))->group == Material::Group::GasMixture) &&
     587            0 :                             s_mat->materials(thisConstruct.LayerPoint(7))->group == Material::Group::Glass)
     588            0 :                             ValidBGShadeBlindConst = true;
     589              :                     }
     590              :                 } // End of check if TotGlassLayers = 2 or 3
     591            0 :                 if (!ValidBGShadeBlindConst) WrongWindowLayering = true;
     592            0 :                 if (!WrongWindowLayering) {
     593            0 :                     int const LayNumSh = 2 * TotGlassLayers - 1;
     594            0 :                     int const MatSh = thisConstruct.LayerPoint(LayNumSh);
     595            0 :                     auto const *matSh = s_mat->materials(MatSh);
     596              :                     // For double pane, shade/blind must be layer #3.
     597              :                     // For triple pane, it must be layer #5 (i.e., between two inner panes).
     598            0 :                     if (matSh->group != Material::Group::Shade && matSh->group != Material::Group::Blind) WrongWindowLayering = true;
     599            0 :                     if (TotLayers != 2 * TotGlassLayers + 1) WrongWindowLayering = true;
     600            0 :                     if (!WrongWindowLayering) {
     601              :                         // Gas on either side of a between-glass shade/blind must be the same
     602            0 :                         int const MatGapL = thisConstruct.LayerPoint(LayNumSh - 1);
     603            0 :                         int const MatGapR = thisConstruct.LayerPoint(LayNumSh + 1);
     604            0 :                         auto const *matGapL = dynamic_cast<const Material::MaterialGasMix *>(s_mat->materials(MatGapL));
     605            0 :                         auto const *matGapR = dynamic_cast<const Material::MaterialGasMix *>(s_mat->materials(MatGapR));
     606            0 :                         for (int IGas = 0; IGas < Material::maxMixGases; ++IGas) {
     607            0 :                             if ((matGapL->gases[IGas].type != matGapR->gases[IGas].type) || (matGapL->gasFracts[IGas] != matGapR->gasFracts[IGas]))
     608            0 :                                 WrongWindowLayering = true;
     609              :                         }
     610              :                         // Gap width on either side of a between-glass shade/blind must be the same
     611            0 :                         if (std::abs(matGapL->Thickness - matGapR->Thickness) > 0.0005) WrongWindowLayering = true;
     612            0 :                         if (matSh->group == Material::Group::Blind) {
     613            0 :                             auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(matSh);
     614            0 :                             assert(matBlind != nullptr);
     615            0 :                             if ((matGapL->Thickness + matGapR->Thickness) < matBlind->SlatWidth) {
     616            0 :                                 ErrorsFound = true;
     617            0 :                                 ShowSevereError(state, format("CheckAndSetConstructionProperties: For window construction {}", thisConstruct.Name));
     618            0 :                                 ShowContinueError(state, "the slat width of the between-glass blind is greater than");
     619            0 :                                 ShowContinueError(state, "the sum of the widths of the gas layers adjacent to the blind.");
     620              :                             }
     621              :                         } // End of check if material is window blind
     622              :                     }     // End of check if WrongWindowLayering
     623              :                 }         // End of check if WrongWindowLayering
     624              :             }             // End of check on total glass layers
     625              :         }                 // End of check if construction has between-glass shade/blind
     626              : 
     627              :         // Check Simple Windows,
     628          122 :         if (s_mat->materials(thisConstruct.LayerPoint(1))->group == Material::Group::GlassSimple) {
     629           23 :             if (TotLayers > 1) {
     630              :                 // check that none of the other layers are glazing or gas
     631            3 :                 for (int Layer = 1; Layer <= TotLayers; ++Layer) {
     632            2 :                     int const MaterNum = thisConstruct.LayerPoint(Layer);
     633            2 :                     if (MaterNum == 0) continue; // error -- has been caught will stop program later
     634            2 :                     auto const *mat = s_mat->materials(MaterNum);
     635            2 :                     if (mat->group == Material::Group::Glass) {
     636            0 :                         ErrorsFound = true;
     637            0 :                         ShowSevereError(state, format("CheckAndSetConstructionProperties: Error in window construction {}--", thisConstruct.Name));
     638            0 :                         ShowContinueError(state, "For simple window constructions, no other glazing layers are allowed.");
     639              :                     }
     640            2 :                     if (mat->group == Material::Group::Gas) {
     641            0 :                         ErrorsFound = true;
     642            0 :                         ShowSevereError(state, format("CheckAndSetConstructionProperties: Error in window construction {}--", thisConstruct.Name));
     643            0 :                         ShowContinueError(state, "For simple window constructions, no other gas layers are allowed.");
     644              :                     }
     645              :                 }
     646              :             }
     647              :         }
     648              : 
     649          122 :         if (WrongWindowLayering) {
     650            0 :             ShowSevereError(state, format("CheckAndSetConstructionProperties: Error in window construction {}--", thisConstruct.Name));
     651            0 :             ShowContinueError(state, "  For multi-layer window constructions the following rules apply:");
     652            0 :             ShowContinueError(state, "    --The first and last layer must be a solid layer (glass or shade/screen/blind),");
     653            0 :             ShowContinueError(state, "    --Adjacent glass layers must be separated by one and only one gas layer,");
     654            0 :             ShowContinueError(state, "    --Adjacent layers must not be of the same type,");
     655            0 :             ShowContinueError(state, "    --Only one shade/screen/blind layer is allowed,");
     656            0 :             ShowContinueError(state, "    --An exterior shade/screen/blind must be the first layer,");
     657            0 :             ShowContinueError(state, "    --An interior shade/blind must be the last layer,");
     658            0 :             ShowContinueError(state, "    --An interior screen is not allowed,");
     659            0 :             ShowContinueError(state, "    --For an exterior shade/screen/blind or interior shade/blind, there should not be a gas layer");
     660            0 :             ShowContinueError(state, "    ----between the shade/screen/blind and adjacent glass,");
     661            0 :             ShowContinueError(state, "    --A between-glass screen is not allowed,");
     662            0 :             ShowContinueError(state, "    --A between-glass shade/blind is allowed only for double and triple glazing,");
     663            0 :             ShowContinueError(state, "    --A between-glass shade/blind must have adjacent gas layers of the same type and width,");
     664            0 :             ShowContinueError(state, "    --For triple glazing the between-glass shade/blind must be between the two inner glass layers,");
     665            0 :             ShowContinueError(state, "    --The slat width of a between-glass blind must be less than the sum of the widths");
     666            0 :             ShowContinueError(state, "    ----of the gas layers adjacent to the blind.");
     667            0 :             ErrorsFound = true;
     668              :         }
     669              : 
     670          122 :         thisConstruct.TotGlassLayers = TotGlassLayers;
     671          122 :         thisConstruct.TotSolidLayers = TotGlassLayers + TotShadeLayers;
     672              : 
     673              :         // In following, InsideLayer is layer number of inside glass and InsideAbsorpThermal applies
     674              :         // only to inside glass; it is corrected later in InitGlassOpticalCalculations
     675              :         // if construction has inside shade or blind.
     676          122 :         if (matInside->group == Material::Group::Shade || matInside->group == Material::Group::Blind) {
     677            4 :             --InsideLayer;
     678              :         }
     679          122 :         if (InsideLayer > 0) {
     680          122 :             InsideMaterNum = thisConstruct.LayerPoint(InsideLayer);
     681          122 :             thisConstruct.InsideAbsorpThermal = matInside->AbsorpThermalBack;
     682              :         }
     683          122 :         if (InsideMaterNum != 0) {
     684          122 :             auto const *thisInsideMaterial = s_mat->materials(InsideMaterNum);
     685          122 :             thisConstruct.InsideAbsorpVis = thisInsideMaterial->AbsorpVisible;
     686          122 :             thisConstruct.InsideAbsorpSolar = thisInsideMaterial->AbsorpSolar;
     687              :         }
     688              : 
     689          122 :         if ((matOutside->group == Material::Group::Glass) || (matOutside->group == Material::Group::GlassSimple)) { // Glass
     690          122 :             thisConstruct.OutsideAbsorpThermal = matOutside->AbsorpThermalFront;
     691              :         } else { // Exterior shade, blind or screen
     692            0 :             thisConstruct.OutsideAbsorpThermal = matOutside->AbsorpThermal;
     693              :         }
     694              : 
     695              :     } else { // Opaque surface
     696          653 :         thisConstruct.InsideAbsorpThermal = matInside->AbsorpThermal;
     697          653 :         thisConstruct.OutsideAbsorpThermal = matOutside->AbsorpThermal;
     698              :     }
     699              : 
     700          775 :     thisConstruct.OutsideRoughness = matOutside->Roughness;
     701              : 
     702          775 :     if (matOutside->group == Material::Group::AirGap) {
     703            0 :         ShowSevereError(state, format("CheckAndSetConstructionProperties: Outside Layer is Air for construction {}", thisConstruct.Name));
     704            0 :         ShowContinueError(state, format("  Error in material {}", matOutside->Name));
     705            0 :         ErrorsFound = true;
     706              :     }
     707          775 :     if (InsideLayer > 0) {
     708          775 :         if (matInside->group == Material::Group::AirGap) {
     709            0 :             ShowSevereError(state, format("CheckAndSetConstructionProperties: Inside Layer is Air for construction {}", thisConstruct.Name));
     710            0 :             ShowContinueError(state, format("  Error in material {}", matInside->Name));
     711            0 :             ErrorsFound = true;
     712              :         }
     713              :     }
     714              : 
     715          775 :     if (matOutside->group == Material::Group::EcoRoof) {
     716            1 :         thisConstruct.TypeIsEcoRoof = true;
     717              :         // need to check EcoRoof is not non-outside layer
     718            3 :         for (int Layer = 2; Layer <= TotLayers; ++Layer) {
     719            2 :             if (s_mat->materials(thisConstruct.LayerPoint(Layer))->group == Material::Group::EcoRoof) {
     720            0 :                 ShowSevereError(state,
     721            0 :                                 format("CheckAndSetConstructionProperties: Interior Layer is EcoRoof for construction {}", thisConstruct.Name));
     722            0 :                 ShowContinueError(state, format("  Error in material {}", s_mat->materials(thisConstruct.LayerPoint(Layer))->Name));
     723            0 :                 ErrorsFound = true;
     724              :             }
     725              :         }
     726              :     }
     727              : 
     728          775 :     if (matOutside->group == Material::Group::IRTransparent) {
     729            0 :         thisConstruct.TypeIsIRT = true;
     730            0 :         if (thisConstruct.TotLayers != 1) {
     731            0 :             ShowSevereError(
     732              :                 state,
     733            0 :                 format("CheckAndSetConstructionProperties: Infrared Transparent (IRT) Construction is limited to 1 layer {}", thisConstruct.Name));
     734            0 :             ShowContinueError(state, "  Too many layers in referenced construction.");
     735            0 :             ErrorsFound = true;
     736              :         }
     737              :     }
     738              : }
     739              : 
     740           17 : int AssignReverseConstructionNumber(EnergyPlusData &state,
     741              :                                     int const ConstrNum, // Existing Construction number of first surface
     742              :                                     bool &ErrorsFound)
     743              : {
     744              : 
     745              :     // FUNCTION INFORMATION:
     746              :     //       AUTHOR         Linda Lawrie
     747              :     //       DATE WRITTEN   December 2006
     748              : 
     749              :     // PURPOSE OF THIS FUNCTION:
     750              :     // For interzone, unentered surfaces, we need to have "reverse" constructions
     751              :     // assigned to the created surfaces.  These need to be the reverse (outside to inside layer)
     752              :     // of existing surfaces.  Plus, there may be one already in the data structure so this is looked for as well.
     753              : 
     754              :     // METHODOLOGY EMPLOYED:
     755              :     // Create reverse layers.  Look in current constructions to see if match.  If no match, create a new one.
     756              : 
     757           17 :     auto &s_mat = state.dataMaterial;
     758              :     // Return value
     759              :     int NewConstrNum; // Reverse Construction Number
     760              : 
     761           17 :     if (ConstrNum == 0) {
     762              :         // error caught elsewhere
     763            0 :         NewConstrNum = 0;
     764            0 :         return NewConstrNum;
     765              :     }
     766              : 
     767           17 :     auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
     768           17 :     thisConstruct.IsUsed = true;
     769           17 :     int nLayer = 0;
     770           17 :     state.dataConstruction->LayerPoint = 0;
     771           47 :     for (int Loop = thisConstruct.TotLayers; Loop >= 1; --Loop) {
     772           30 :         ++nLayer;
     773           30 :         state.dataConstruction->LayerPoint(nLayer) = thisConstruct.LayerPoint(Loop);
     774              :     }
     775              : 
     776              :     // now, got thru and see if there is a match already....
     777           17 :     NewConstrNum = 0;
     778           77 :     for (int Loop = 1; Loop <= state.dataHeatBal->TotConstructs; ++Loop) {
     779           73 :         bool Found = true;
     780          218 :         for (nLayer = 1; nLayer <= Construction::MaxLayersInConstruct; ++nLayer) {
     781          205 :             if (state.dataConstruction->Construct(Loop).LayerPoint(nLayer) != state.dataConstruction->LayerPoint(nLayer)) {
     782           60 :                 Found = false;
     783           60 :                 break;
     784              :             }
     785              :         }
     786           73 :         if (Found) {
     787           13 :             NewConstrNum = Loop;
     788           13 :             state.dataConstruction->Construct(Loop).IsUsed = true;
     789           13 :             break;
     790              :         }
     791              :     }
     792              : 
     793              :     // if need new one, bunch o stuff
     794           17 :     if (NewConstrNum == 0) {
     795            4 :         ++state.dataHeatBal->TotConstructs;
     796            4 :         state.dataConstruction->Construct.redimension(state.dataHeatBal->TotConstructs);
     797            4 :         state.dataHeatBal->NominalRforNominalUCalculation.redimension(state.dataHeatBal->TotConstructs);
     798            4 :         state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) = 0.0;
     799            4 :         state.dataHeatBal->NominalU.redimension(state.dataHeatBal->TotConstructs);
     800            4 :         state.dataHeatBal->NominalU(state.dataHeatBal->TotConstructs) = 0.0;
     801            4 :         state.dataHeatBal->NominalUBeforeAdjusted.redimension(state.dataHeatBal->TotConstructs);
     802            4 :         state.dataHeatBal->NominalUBeforeAdjusted(state.dataHeatBal->TotConstructs) = 0.0;
     803            4 :         state.dataHeatBal->CoeffAdjRatio.redimension(state.dataHeatBal->TotConstructs) = 1.0;
     804              :         //  Put in new attributes
     805            4 :         NewConstrNum = state.dataHeatBal->TotConstructs;
     806            4 :         state.dataConstruction->Construct(NewConstrNum).IsUsed = true;
     807            4 :         state.dataConstruction->Construct(state.dataHeatBal->TotConstructs) =
     808            8 :             state.dataConstruction->Construct(ConstrNum); // preserve some of the attributes.
     809              :         // replace others...
     810            4 :         state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).Name = "iz-" + state.dataConstruction->Construct(ConstrNum).Name;
     811            4 :         state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).TotLayers = state.dataConstruction->Construct(ConstrNum).TotLayers;
     812           48 :         for (nLayer = 1; nLayer <= Construction::MaxLayersInConstruct; ++nLayer) {
     813           44 :             state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).LayerPoint(nLayer) = state.dataConstruction->LayerPoint(nLayer);
     814           44 :             if (state.dataConstruction->LayerPoint(nLayer) != 0) {
     815            9 :                 state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) +=
     816            9 :                     s_mat->materials(state.dataConstruction->LayerPoint(nLayer))->NominalR;
     817              :             }
     818              :         }
     819              : 
     820              :         // no error if zero -- that will have been caught with earlier construction
     821              :         // the following line was changed to fix CR7601
     822            4 :         if (state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs) != 0.0) {
     823            4 :             state.dataHeatBal->NominalU(state.dataHeatBal->TotConstructs) =
     824            4 :                 1.0 / state.dataHeatBal->NominalRforNominalUCalculation(state.dataHeatBal->TotConstructs);
     825              :         }
     826              : 
     827            4 :         CheckAndSetConstructionProperties(state, state.dataHeatBal->TotConstructs, ErrorsFound);
     828              :     }
     829              : 
     830           17 :     return NewConstrNum;
     831              : }
     832              : 
     833         1639 : Real64 ComputeNominalUwithConvCoeffs(EnergyPlusData &state,
     834              :                                      int const numSurf, // index for Surface array.
     835              :                                      bool &isValid      // returns true if result is valid
     836              : )
     837              : {
     838              : 
     839              :     // SUBROUTINE INFORMATION:
     840              :     //       AUTHOR         Jason Glazer
     841              :     //       DATE WRITTEN   September 2013
     842              :     //       MODIFIED       na
     843              :     //       RE-ENGINEERED  na
     844              : 
     845              :     // PURPOSE OF THIS SUBROUTINE:
     846              :     // Calculate Nominal U-value with convection/film coefficients for reporting by
     847              :     // adding on prescribed R-values for interior and exterior convection coefficients
     848              :     // as found in ASHRAE 90.1-2004, Appendix A. Used in EIO and tabular reports.
     849              :     // ASHRAE 90.1-2004 Section A9.4.1 shows the following:
     850              :     //      R-value Condition
     851              :     //      All exterior conditions                        IP: 0.17  SI: 0.0299
     852              :     //      All semi-exterior surfaces                     IP: 0.46  SI: 0.0810
     853              :     //      Interior horizontal surfaces, heat flow up     IP: 0.61  SI: 0.1074
     854              :     //      Interior horizontal surfaces, heat flow down   IP: 0.92  SI: 0.1620
     855              :     //      Interior vertical surfaces                     IP: 0.68  SI: 0.1198
     856              :     // This section shows the same value in 90.1-2010 and 90.2-2010
     857              :     // Note that this report does not use the semi-exterior surface value because
     858              :     // EnergyPlus does not have a way to specifically tell whether or not a surface
     859              :     // is connected to a semi-exterior area of the building.  Users can always use
     860              :     // the Nominal U-Value to manually calculated this.  The values calculated here
     861              :     // are simply reported to the EIO file and not used for any calculations.
     862              : 
     863              :     // Return value
     864              :     Real64 NominalUwithConvCoeffs; // return value
     865              : 
     866              :     static constexpr std::array<Real64, static_cast<int>(DataSurfaces::SurfaceClass::Num)> filmCoefs = {
     867              :         0.0,       // None
     868              :         0.1197548, // Wall
     869              :         0.1620212, // Floor
     870              :         0.1074271, // Roof
     871              :         0.0,       // IntMass
     872              :         0.0,       // Detached_B
     873              :         0.0,       // Detached_F
     874              :         0.1197548, // Window
     875              :         0.1197548, // GlassDoor
     876              :         0.1197548, // Door
     877              :         0.0,       // Shading
     878              :         0.0,       // Overhang
     879              :         0.0,       // Fin
     880              :         0.0,       // TDD_Dome
     881              :         0.0        // TDD_Diffuser
     882              :     };             // If anything added to the enum SurfaceClass, adjust this list appropriately
     883              : 
     884              :     Real64 insideFilm;
     885              :     Real64 outsideFilm;
     886              : 
     887         1639 :     isValid = true;
     888              : 
     889         1639 :     auto &thisSurface = state.dataSurface->Surface(numSurf);
     890              : 
     891              :     // exterior conditions
     892         1639 :     switch (thisSurface.ExtBoundCond) {
     893         1093 :     case DataSurfaces::ExternalEnvironment: { // ExtBoundCond = 0
     894         1093 :         outsideFilm = 0.0299387;              // All exterior conditions
     895         1093 :     } break;
     896            1 :     case DataSurfaces::OtherSideCoefCalcExt: {
     897            1 :         outsideFilm = state.dataSurface->OSC(thisSurface.OSCPtr).SurfFilmCoef;
     898            1 :     } break;
     899          112 :     case DataSurfaces::Ground:
     900              :     case DataSurfaces::OtherSideCoefNoCalcExt:
     901              :     case DataSurfaces::OtherSideCondModeledExt:
     902              :     case DataSurfaces::GroundFCfactorMethod:
     903              :     case DataSurfaces::KivaFoundation: { // All these cases have a negative ExtBoundCond so don't use film coefficients
     904          112 :         outsideFilm = 0.0;
     905          112 :     } break;
     906          433 :     default: { // Interior Surface Attached to a Zone (ExtBoundCond is a surface)
     907          433 :         outsideFilm = filmCoefs[static_cast<int>(state.dataSurface->Surface(thisSurface.ExtBoundCond).Class)];
     908          433 :     } break;
     909              :     }
     910              :     // interior conditions and calculate the return value
     911         1639 :     if (state.dataHeatBal->NominalU(thisSurface.Construction) > 0.0) {
     912         1596 :         insideFilm = filmCoefs[static_cast<int>(thisSurface.Class)];
     913         1596 :         if (insideFilm == 0.0) outsideFilm = 0.0;
     914         1596 :         NominalUwithConvCoeffs =
     915         1596 :             1.0 / (insideFilm + (1.0 / state.dataHeatBal->NominalU(state.dataSurface->Surface(numSurf).Construction)) + outsideFilm);
     916              :     } else {
     917           43 :         isValid = false;
     918           43 :         NominalUwithConvCoeffs = state.dataHeatBal->NominalU(state.dataSurface->Surface(numSurf).Construction);
     919              :     }
     920              : 
     921         1639 :     return NominalUwithConvCoeffs;
     922              : }
     923              : 
     924          194 : void SetFlagForWindowConstructionWithShadeOrBlindLayer(EnergyPlusData &state)
     925              : {
     926              : 
     927              :     // PURPOSE OF THIS SUBROUTINE:
     928              :     // check fenestrations with shading control and set a flag to true if its construction has
     929              :     // either shade or blind material layer
     930              : 
     931              :     // METHODOLOGY EMPLOYED:
     932              :     // Loop through Surface and register any shading controls, and loop through the construction
     933              :     // material layer
     934              : 
     935              :     // Using/Aliasing
     936              :     using DataSurfaces::ExternalEnvironment;
     937              : 
     938              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     939          194 :     int loopSurfNum(0); // surface index
     940          194 :     int ConstrNum(0);   // construction index
     941          194 :     int NumLayers(0);   // number of material layers in a construction
     942          194 :     int Layer(0);       // construction material layer index
     943          194 :     int MaterNum(0);    // construction material index
     944              : 
     945          194 :     auto &s_mat = state.dataMaterial;
     946              : 
     947         1899 :     for (loopSurfNum = 1; loopSurfNum <= state.dataSurface->TotSurfaces; ++loopSurfNum) {
     948              : 
     949         1705 :         if (state.dataSurface->Surface(loopSurfNum).Class != DataSurfaces::SurfaceClass::Window) continue;
     950          122 :         if (state.dataSurface->Surface(loopSurfNum).ExtBoundCond != ExternalEnvironment) continue;
     951          114 :         if (!state.dataSurface->Surface(loopSurfNum).HasShadeControl) continue;
     952           12 :         if (state.dataSurface->Surface(loopSurfNum).activeShadedConstruction == 0) continue;
     953              : 
     954           12 :         ConstrNum = state.dataSurface->Surface(loopSurfNum).activeShadedConstruction;
     955           12 :         auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
     956           12 :         if (thisConstruct.TypeIsWindow) {
     957           12 :             NumLayers = thisConstruct.TotLayers;
     958           41 :             for (Layer = 1; Layer <= NumLayers; ++Layer) {
     959           29 :                 MaterNum = thisConstruct.LayerPoint(Layer);
     960           29 :                 if (MaterNum == 0) continue;
     961           29 :                 auto const *mat = s_mat->materials(MaterNum);
     962           29 :                 if (mat->group == Material::Group::Shade || mat->group == Material::Group::Blind)
     963           10 :                     state.dataSurface->SurfWinHasShadeOrBlindLayer(loopSurfNum) = true;
     964              :             }
     965              :         }
     966              :     }
     967          194 : }
     968              : 
     969          209 : void AllocateIntGains(EnergyPlusData &state)
     970              : {
     971          209 :     state.dataHeatBal->ZoneIntGain.allocate(state.dataGlobal->NumOfZones);
     972          209 :     state.dataHeatBal->spaceIntGain.allocate(state.dataGlobal->numSpaces);
     973          209 :     state.dataHeatBal->spaceIntGainDevices.allocate(state.dataGlobal->numSpaces);
     974          209 :     state.dataDayltg->spacePowerReductionFactor.dimension(state.dataGlobal->numSpaces, 1.0);
     975          209 : }
     976              : 
     977              : } // namespace EnergyPlus::DataHeatBalance
        

Generated by: LCOV version 2.0-1