LCOV - code coverage report
Current view: top level - EnergyPlus - WindowManagerExteriorThermal.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 88.8 % 547 486
Test Date: 2025-06-02 07:23:51 Functions: 100.0 % 26 26

            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              : // EnergyPlus headers
      49              : #include <EnergyPlus/Construction.hh>
      50              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      51              : #include <EnergyPlus/DataEnvironment.hh>
      52              : #include <EnergyPlus/DataHeatBalSurface.hh>
      53              : #include <EnergyPlus/DataHeatBalance.hh>
      54              : #include <EnergyPlus/DataSurfaces.hh>
      55              : #include <EnergyPlus/General.hh>
      56              : #include <EnergyPlus/Material.hh>
      57              : #include <EnergyPlus/UtilityRoutines.hh>
      58              : #include <EnergyPlus/WindowManager.hh>
      59              : 
      60              : // Windows library headers
      61              : #include <WCEMultiLayerOptics.hpp>
      62              : #include <WCETarcog.hpp>
      63              : 
      64              : // EnergyPlus headers
      65              : #include <EnergyPlus/WindowManagerExteriorThermal.hh>
      66              : 
      67              : namespace EnergyPlus {
      68              : 
      69              : using namespace DataEnvironment;
      70              : using namespace DataSurfaces;
      71              : using namespace DataHeatBalance;
      72              : using namespace General;
      73              : 
      74              : namespace Window {
      75              : 
      76              :     /////////////////////////////////////////////////////////////////////////////////////////
      77         4032 :     void CalcWindowHeatBalanceExternalRoutines(EnergyPlusData &state,
      78              :                                                int const SurfNum,          // Surface number
      79              :                                                Real64 const HextConvCoeff, // Outside air film conductance coefficient
      80              :                                                Real64 &SurfInsideTemp,     // Inside window surface temperature
      81              :                                                Real64 &SurfOutsideTemp     // Outside surface temperature (C)
      82              :     )
      83              :     {
      84              :         // SUBROUTINE INFORMATION:
      85              :         //       AUTHOR         Simon Vidanovic
      86              :         //       DATE WRITTEN   July 2016
      87              :         //       MODIFIED       na
      88              :         //       RE-ENGINEERED  na
      89              : 
      90              :         // PURPOSE OF THIS SUBROUTINE:
      91              :         // Main wrapper routine to pick-up data from EnergyPlus and then call Windows-CalcEngine routines
      92              :         // to obtain results
      93              : 
      94         4032 :         auto &surf = state.dataSurface->Surface(SurfNum);
      95         4032 :         auto &surfWin = state.dataSurface->SurfaceWindow(SurfNum);
      96         4032 :         int ConstrNum = surf.Construction;
      97         4032 :         auto &construction = state.dataConstruction->Construct(ConstrNum);
      98              : 
      99         4032 :         constexpr Real64 solutionTolerance = 0.02;
     100              : 
     101              :         // Tarcog thermal system for solving heat transfer through the window
     102         4032 :         int activeConstrNum = CWCEHeatTransferFactory::getActiveConstructionNumber(state, surf, SurfNum);
     103         4032 :         auto aFactory = CWCEHeatTransferFactory(state, surf, SurfNum, activeConstrNum); // (AUTO_OK)
     104         4032 :         auto aSystem = aFactory.getTarcogSystem(state, HextConvCoeff);                  // (AUTO_OK_SPTR)
     105         4032 :         aSystem->setTolerance(solutionTolerance);
     106              : 
     107              :         // get previous timestep temperatures solution for faster iterations
     108         4032 :         std::vector<Real64> Guess;
     109         4032 :         int totSolidLayers = construction.TotSolidLayers;
     110              : 
     111              :         // Interior and exterior shading layers have gas between them and IGU but that gas
     112              :         // was not part of construction so it needs to be increased by one
     113         4032 :         if (ANY_SHADE_SCREEN(state.dataSurface->SurfWinShadingFlag(SurfNum)) || ANY_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
     114         2688 :             ++totSolidLayers;
     115              :         }
     116              : 
     117        20160 :         for (int k = 1; k <= 2 * totSolidLayers; ++k) {
     118        16128 :             Guess.push_back(state.dataSurface->SurfaceWindow(SurfNum).thetaFace[k]);
     119              :         }
     120              : 
     121              :         try {
     122         4032 :             aSystem->setInitialGuess(Guess);
     123         4032 :             aSystem->solve();
     124            0 :         } catch (const std::exception &ex) {
     125            0 :             ShowSevereError(state, "Error in Windows Calculation Engine Exterior Module.");
     126            0 :             ShowContinueError(state, ex.what());
     127            0 :         }
     128              : 
     129         4032 :         auto aLayers = aSystem->getSolidLayers(); // (AUTO_OK_OBJ)
     130         4032 :         int i = 1;
     131        12096 :         for (const auto &aLayer : aLayers) { // (AUTO_OK_SPTR)
     132         8064 :             Real64 aTemp = 0;
     133        24192 :             for (auto aSide : FenestrationCommon::EnumSide()) { // (AUTO_OK) I don't understand what this construct is
     134        16128 :                 aTemp = aLayer->getTemperature(aSide);
     135        16128 :                 state.dataWindowManager->thetas[i - 1] = aTemp;
     136        16128 :                 if (i == 1) {
     137         4032 :                     SurfOutsideTemp = aTemp - Constant::Kelvin;
     138              :                 }
     139        16128 :                 ++i;
     140              :             }
     141         8064 :             SurfInsideTemp = aTemp - Constant::Kelvin;
     142         8064 :             if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
     143         5376 :                 auto &surfShade = state.dataSurface->surfShades(SurfNum);
     144         5376 :                 Real64 EffShBlEmiss = surfShade.effShadeEmi;
     145         5376 :                 Real64 EffGlEmiss = surfShade.effGlassEmi;
     146         5376 :                 if (surfShade.blind.movableSlats) {
     147            0 :                     surfShade.effShadeEmi = Interp(construction.effShadeBlindEmi[surfShade.blind.slatAngIdxLo],
     148            0 :                                                    construction.effShadeBlindEmi[surfShade.blind.slatAngIdxHi],
     149              :                                                    surfShade.blind.slatAngInterpFac);
     150            0 :                     surfShade.effGlassEmi = Interp(construction.effGlassEmi[surfShade.blind.slatAngIdxLo],
     151            0 :                                                    construction.effGlassEmi[surfShade.blind.slatAngIdxHi],
     152              :                                                    surfShade.blind.slatAngInterpFac);
     153              :                 }
     154         5376 :                 state.dataSurface->SurfWinEffInsSurfTemp(SurfNum) =
     155         5376 :                     (EffShBlEmiss * SurfInsideTemp + EffGlEmiss * (state.dataWindowManager->thetas[2 * totSolidLayers - 3] - Constant::Kelvin)) /
     156         5376 :                     (EffShBlEmiss + EffGlEmiss);
     157              :             }
     158         4032 :         }
     159              : 
     160         4032 :         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = aSystem->getHc(Tarcog::ISO15099::Environment::Indoor);
     161         4032 :         if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum)) || aFactory.isInteriorShade()) {
     162         2688 :             auto &surfShade = state.dataSurface->surfShades(SurfNum);
     163              :             // It is not clear why EnergyPlus keeps this interior calculations separately for interior shade. This does create different
     164              :             // solution from heat transfer from tarcog itself. Need to confirm with LBNL team about this approach. Note that heat flow
     165              :             // through shade (consider case when openings are zero) is different from heat flow obtained by these equations. Will keep
     166              :             // these calculations just to confirm that current exterior engine is giving close results to what is in here. (Simon)
     167         2688 :             int totLayers = aLayers.size();
     168         2688 :             state.dataWindowManager->nglface = 2 * totLayers - 2;
     169         2688 :             state.dataWindowManager->nglfacep = state.dataWindowManager->nglface + 2;
     170         2688 :             auto aShadeLayer = aLayers[totLayers - 1]; // (AUTO_OK_SPTR)
     171         2688 :             auto aGlassLayer = aLayers[totLayers - 2]; // (AUTO_OK_SPTR)
     172         2688 :             Real64 ShadeArea = state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum);
     173         2688 :             auto frontSurface = aShadeLayer->getSurface(FenestrationCommon::Side::Front); // (AUTO_OK_SPTR)
     174         2688 :             auto backSurface = aShadeLayer->getSurface(FenestrationCommon::Side::Back);   // (AUTO_OK_SPTR)
     175         2688 :             Real64 EpsShIR1 = frontSurface->getEmissivity();
     176         2688 :             Real64 EpsShIR2 = backSurface->getEmissivity();
     177         2688 :             Real64 TauShIR = frontSurface->getTransmittance();
     178         2688 :             Real64 RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1);
     179         2688 :             Real64 RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2);
     180         2688 :             Real64 glassEmiss = aGlassLayer->getSurface(FenestrationCommon::Side::Back)->getEmissivity();
     181         2688 :             Real64 RhoGlIR2 = 1.0 - glassEmiss;
     182         2688 :             Real64 ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1;
     183         2688 :             Real64 rmir = state.dataSurface->SurfWinIRfromParentZone(SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum);
     184              :             Real64 NetIRHeatGainShade =
     185         5376 :                 ShadeArea * EpsShIR2 *
     186         2688 :                     (Constant::StefanBoltzmann * pow(state.dataWindowManager->thetas[state.dataWindowManager->nglfacep - 1], 4) - rmir) +
     187         2688 :                 EpsShIR1 * (Constant::StefanBoltzmann * pow(state.dataWindowManager->thetas[state.dataWindowManager->nglfacep - 2], 4) - rmir) *
     188         2688 :                     RhoGlIR2 * TauShIR / ShGlReflFacIR;
     189              :             Real64 NetIRHeatGainGlass =
     190         2688 :                 ShadeArea * (glassEmiss * TauShIR / ShGlReflFacIR) *
     191         2688 :                 (Constant::StefanBoltzmann * pow(state.dataWindowManager->thetas[state.dataWindowManager->nglface - 1], 4) - rmir);
     192         2688 :             Real64 tind = surf.getInsideAirTemperature(state, SurfNum) + Constant::Kelvin;
     193         2688 :             Real64 ConvHeatGainFrZoneSideOfShade = ShadeArea * state.dataHeatBalSurf->SurfHConvInt(SurfNum) *
     194         2688 :                                                    (state.dataWindowManager->thetas[state.dataWindowManager->nglfacep - 1] - tind);
     195         2688 :             state.dataSurface->SurfWinHeatGain(SurfNum) =
     196         2688 :                 state.dataSurface->SurfWinTransSolar(SurfNum) + ConvHeatGainFrZoneSideOfShade + NetIRHeatGainGlass + NetIRHeatGainShade;
     197              : 
     198         2688 :             state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) = NetIRHeatGainGlass;
     199              : 
     200              :             // Effective shade and glass emissivities that are used later for energy calculations.
     201              :             // This needs to be checked as well. (Simon)
     202         2688 :             surfShade.effShadeEmi = EpsShIR1 * (1.0 + RhoGlIR2 * TauShIR / (1.0 - RhoGlIR2 * RhoShIR2));
     203         2688 :             surfShade.effGlassEmi = glassEmiss * TauShIR / (1.0 - RhoGlIR2 * RhoShIR2);
     204              : 
     205         2688 :             Real64 glassTemperature = aGlassLayer->getSurface(FenestrationCommon::Side::Back)->getTemperature();
     206         2688 :             state.dataSurface->SurfWinEffInsSurfTemp(SurfNum) =
     207         2688 :                 (surfShade.effShadeEmi * SurfInsideTemp + surfShade.effGlassEmi * (glassTemperature - Constant::Kelvin)) /
     208         2688 :                 (surfShade.effShadeEmi + surfShade.effGlassEmi);
     209              : 
     210         2688 :         } else {
     211              :             // Another adoptation to old source that looks suspicious. Check if heat flow through
     212              :             // window is actually matching these values. (Simon)
     213              : 
     214              :             //
     215         1344 :             auto &surfShade = state.dataSurface->surfShades(SurfNum);
     216         1344 :             int totLayers = aLayers.size();
     217         1344 :             auto aGlassLayer = aLayers[totLayers - 1];                                  // (AUTO_OK_SPTR)
     218         1344 :             auto backSurface = aGlassLayer->getSurface(FenestrationCommon::Side::Back); // (AUTO_OK_SPTR)
     219              : 
     220         1344 :             Real64 h_cin = aSystem->getHc(Tarcog::ISO15099::Environment::Indoor);
     221              :             Real64 ConvHeatGainFrZoneSideOfGlass =
     222         1344 :                 surf.Area * h_cin * (backSurface->getTemperature() - aSystem->getAirTemperature(Tarcog::ISO15099::Environment::Indoor));
     223              : 
     224         1344 :             Real64 rmir = state.dataSurface->SurfWinIRfromParentZone(SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum);
     225              :             Real64 NetIRHeatGainGlass =
     226         1344 :                 surf.Area * backSurface->getEmissivity() * (Constant::StefanBoltzmann * pow(backSurface->getTemperature(), 4) - rmir);
     227              : 
     228         1344 :             state.dataSurface->SurfWinEffInsSurfTemp(SurfNum) =
     229         1344 :                 aLayers[totLayers - 1]->getTemperature(FenestrationCommon::Side::Back) - Constant::Kelvin;
     230         1344 :             surfShade.effGlassEmi = aLayers[totLayers - 1]->getSurface(FenestrationCommon::Side::Back)->getEmissivity();
     231              : 
     232         1344 :             state.dataSurface->SurfWinHeatGain(SurfNum) =
     233         1344 :                 state.dataSurface->SurfWinTransSolar(SurfNum) + ConvHeatGainFrZoneSideOfGlass + NetIRHeatGainGlass;
     234         1344 :             state.dataSurface->SurfWinGainConvGlazToZoneRep(SurfNum) = ConvHeatGainFrZoneSideOfGlass;
     235         1344 :             state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) = NetIRHeatGainGlass;
     236         1344 :         }
     237              : 
     238         4032 :         state.dataSurface->SurfWinLossSWZoneToOutWinRep(SurfNum) =
     239         4032 :             state.dataHeatBal->EnclSolQSWRad(state.dataSurface->Surface(SurfNum).SolarEnclIndex) * surf.Area * (1 - construction.ReflectSolDiffBack) +
     240         4032 :             state.dataHeatBalSurf->SurfWinInitialBeamSolInTrans(SurfNum);
     241         4032 :         state.dataSurface->SurfWinHeatGain(SurfNum) -=
     242         4032 :             (state.dataSurface->SurfWinLossSWZoneToOutWinRep(SurfNum) + state.dataHeatBalSurf->SurfWinInitialDifSolInTrans(SurfNum) * surf.Area);
     243              : 
     244        10752 :         for (int k = 1; k <= surf.getTotLayers(state); ++k) {
     245         6720 :             surfWin.thetaFace[2 * k - 1] = state.dataWindowManager->thetas[2 * k - 2];
     246         6720 :             surfWin.thetaFace[2 * k] = state.dataWindowManager->thetas[2 * k - 1];
     247              : 
     248              :             // temperatures for reporting
     249         6720 :             state.dataHeatBal->SurfWinFenLaySurfTempFront(SurfNum, k) = state.dataWindowManager->thetas[2 * k - 2] - Constant::Kelvin;
     250         6720 :             state.dataHeatBal->SurfWinFenLaySurfTempBack(SurfNum, k) = state.dataWindowManager->thetas[2 * k - 1] - Constant::Kelvin;
     251              :         }
     252         4032 :     }
     253              : 
     254              :     Real64
     255           41 :     GetIGUUValueForNFRCReport(EnergyPlusData &state, const int surfNum, const int constrNum, const Real64 windowWidth, const Real64 windowHeight)
     256              :     {
     257           41 :         Real64 tilt = 90.0;
     258              : 
     259           41 :         auto &surface = state.dataSurface->Surface(surfNum);
     260           41 :         auto aFactory = CWCEHeatTransferFactory(state, surface, surfNum, constrNum); // (AUTO_OK)
     261              : 
     262           41 :         const auto winterGlassUnit = aFactory.getTarcogSystemForReporting(state, false, windowWidth, windowHeight, tilt); // (AUTO_OK_SPTR)
     263              : 
     264           82 :         return winterGlassUnit->getUValue();
     265           41 :     }
     266              : 
     267           41 :     Real64 GetSHGCValueForNFRCReporting(EnergyPlusData &state, int surfNum, int constrNum, Real64 windowWidth, Real64 windowHeight)
     268              :     {
     269           41 :         Real64 tilt = 90.0;
     270              : 
     271           41 :         auto &surface = state.dataSurface->Surface(surfNum);
     272           41 :         auto aFactory = CWCEHeatTransferFactory(state, surface, surfNum, constrNum); // (AUTO_OK)
     273              : 
     274           41 :         const auto summerGlassUnit = aFactory.getTarcogSystemForReporting(state, true, windowWidth, windowHeight, tilt); // (AUTO_OK_SPTR)
     275           82 :         return summerGlassUnit->getSHGC(state.dataConstruction->Construct(surface.Construction).SolTransNorm);
     276           41 :     }
     277              : 
     278          422 :     void GetWindowAssemblyNfrcForReport(EnergyPlusData &state,
     279              :                                         int const surfNum,
     280              :                                         int constrNum,
     281              :                                         Real64 windowWidth,
     282              :                                         Real64 windowHeight,
     283              :                                         EnergyPlus::DataSurfaces::NfrcVisionType vision,
     284              :                                         Real64 &uvalue,
     285              :                                         Real64 &shgc,
     286              :                                         Real64 &vt)
     287              :     {
     288          422 :         auto &surface = state.dataSurface->Surface(surfNum);
     289          422 :         auto &frameDivider = state.dataSurface->FrameDivider(surface.FrameDivider);
     290              : 
     291          422 :         auto aFactory = CWCEHeatTransferFactory(state, surface, surfNum, constrNum); // (AUTO_OK)
     292              : 
     293         1266 :         for (bool isSummer : {false, true}) {
     294          844 :             constexpr Real64 framehExtConvCoeff = 30.0;
     295          844 :             constexpr Real64 framehIntConvCoeff = 8.0;
     296          844 :             constexpr Real64 tilt = 90.0;
     297              : 
     298          844 :             auto insulGlassUnit = aFactory.getTarcogSystemForReporting(state, isSummer, windowWidth, windowHeight, tilt); // (AUTO_OK_SPTR)
     299              : 
     300          844 :             const double centerOfGlassUvalue = insulGlassUnit->getUValue();
     301              : 
     302          844 :             auto winterGlassUnit = aFactory.getTarcogSystemForReporting(state, false, windowWidth, windowHeight, tilt); // (AUTO_OK_SPTR)
     303              : 
     304          844 :             const double frameUvalue = aFactory.overallUfactorFromFilmsAndCond(frameDivider.FrameConductance, framehIntConvCoeff, framehExtConvCoeff);
     305          844 :             const double frameEdgeUValue = winterGlassUnit->getUValue() * frameDivider.FrEdgeToCenterGlCondRatio; // not sure about this
     306          844 :             const double frameProjectedDimension = frameDivider.FrameWidth;
     307          844 :             const double frameWettedLength = frameProjectedDimension + frameDivider.FrameProjectionIn;
     308          844 :             const double frameAbsorptance = frameDivider.FrameSolAbsorp;
     309              : 
     310          844 :             Tarcog::ISO15099::FrameData frameData{frameUvalue, frameEdgeUValue, frameProjectedDimension, frameWettedLength, frameAbsorptance};
     311              : 
     312              :             const double dividerUvalue =
     313          844 :                 aFactory.overallUfactorFromFilmsAndCond(frameDivider.DividerConductance, framehIntConvCoeff, framehExtConvCoeff);
     314          844 :             const double dividerEdgeUValue = centerOfGlassUvalue * frameDivider.DivEdgeToCenterGlCondRatio; // not sure about this
     315          844 :             const double dividerProjectedDimension = frameDivider.DividerWidth;
     316          844 :             const double dividerWettedLength = dividerProjectedDimension + frameDivider.DividerProjectionIn;
     317          844 :             const double dividerAbsorptance = frameDivider.DividerSolAbsorp;
     318          844 :             const int numHorizDividers = frameDivider.HorDividers;
     319          844 :             const int numVertDividers = frameDivider.VertDividers;
     320              : 
     321              :             Tarcog::ISO15099::FrameData dividerData{
     322          844 :                 dividerUvalue, dividerEdgeUValue, dividerProjectedDimension, dividerWettedLength, dividerAbsorptance};
     323              : 
     324          844 :             const Real64 tVis = state.dataConstruction->Construct(constrNum).VisTransNorm;
     325          844 :             const Real64 tSol = state.dataConstruction->Construct(constrNum).SolTransNorm;
     326              : 
     327          844 :             if (vision == DataSurfaces::NfrcVisionType::Single) {
     328          830 :                 Tarcog::ISO15099::WindowSingleVision window(windowWidth, windowHeight, tVis, tSol, insulGlassUnit);
     329          830 :                 window.setFrameTop(frameData);
     330          830 :                 window.setFrameBottom(frameData);
     331          830 :                 window.setFrameLeft(frameData);
     332          830 :                 window.setFrameRight(frameData);
     333          830 :                 window.setDividers(dividerData, numHorizDividers, numVertDividers);
     334              : 
     335          830 :                 if (isSummer) {
     336          415 :                     vt = window.vt();
     337          415 :                     shgc = window.shgc();
     338              :                 } else {
     339          415 :                     uvalue = window.uValue();
     340              :                 }
     341          844 :             } else if (vision == EnergyPlus::DataSurfaces::NfrcVisionType::DualHorizontal) {
     342            0 :                 Tarcog::ISO15099::DualVisionHorizontal window(windowWidth, windowHeight, tVis, tSol, insulGlassUnit, tVis, tSol, insulGlassUnit);
     343            0 :                 window.setFrameLeft(frameData);
     344            0 :                 window.setFrameRight(frameData);
     345            0 :                 window.setFrameBottomLeft(frameData);
     346            0 :                 window.setFrameBottomRight(frameData);
     347            0 :                 window.setFrameTopLeft(frameData);
     348            0 :                 window.setFrameTopRight(frameData);
     349            0 :                 window.setFrameMeetingRail(frameData);
     350            0 :                 window.setDividers(dividerData, numHorizDividers, numVertDividers);
     351              : 
     352            0 :                 if (isSummer) {
     353            0 :                     vt = window.vt();
     354            0 :                     shgc = window.shgc();
     355              :                 } else {
     356            0 :                     uvalue = window.uValue();
     357              :                 }
     358           14 :             } else if (vision == EnergyPlus::DataSurfaces::NfrcVisionType::DualVertical) {
     359           14 :                 Tarcog::ISO15099::DualVisionVertical window(windowWidth, windowHeight, tVis, tSol, insulGlassUnit, tVis, tSol, insulGlassUnit);
     360           14 :                 window.setFrameTop(frameData);
     361           14 :                 window.setFrameBottom(frameData);
     362           14 :                 window.setFrameTopLeft(frameData);
     363           14 :                 window.setFrameTopRight(frameData);
     364           14 :                 window.setFrameBottomLeft(frameData);
     365           14 :                 window.setFrameBottomRight(frameData);
     366           14 :                 window.setFrameMeetingRail(frameData);
     367           14 :                 window.setDividers(dividerData, numHorizDividers, numVertDividers);
     368              : 
     369           14 :                 if (isSummer) {
     370            7 :                     vt = window.vt();
     371            7 :                     shgc = window.shgc();
     372              :                 } else {
     373            7 :                     uvalue = window.uValue();
     374              :                 }
     375           14 :             } else {
     376            0 :                 Tarcog::ISO15099::WindowSingleVision window(windowWidth, windowHeight, tVis, tSol, insulGlassUnit);
     377            0 :                 window.setFrameTop(frameData);
     378            0 :                 window.setFrameBottom(frameData);
     379            0 :                 window.setFrameLeft(frameData);
     380            0 :                 window.setFrameRight(frameData);
     381            0 :                 window.setDividers(dividerData, numHorizDividers, numVertDividers);
     382              : 
     383            0 :                 if (isSummer) {
     384            0 :                     vt = window.vt();
     385            0 :                     shgc = window.shgc();
     386              :                 } else {
     387            0 :                     uvalue = window.uValue();
     388              :                 }
     389            0 :             }
     390          844 :         }
     391          422 :     }
     392              : 
     393              :     /////////////////////////////////////////////////////////////////////////////////////////
     394              :     //  CWCEHeatTransferFactory
     395              :     /////////////////////////////////////////////////////////////////////////////////////////
     396              : 
     397         4536 :     CWCEHeatTransferFactory::CWCEHeatTransferFactory(EnergyPlusData &state, SurfaceData const &surface, int const t_SurfNum, int const t_ConstrNum)
     398         4536 :         : m_Surface(surface), m_Window(state.dataSurface->SurfaceWindow(t_SurfNum)), m_ShadePosition(ShadePosition::NoShade), m_SurfNum(t_SurfNum),
     399         4536 :           m_SolidLayerIndex(0), m_ConstructionNumber(t_ConstrNum), m_TotLay(getNumOfLayers(state)), m_InteriorBSDFShade(false), m_ExteriorShade(false)
     400              :     {
     401         7726 :         if (!state.dataConstruction->Construct(m_ConstructionNumber).WindowTypeBSDF &&
     402         3190 :             state.dataSurface->SurfWinShadingFlag.size() >= static_cast<size_t>(m_SurfNum)) {
     403         3190 :             if (ANY_SHADE_SCREEN(state.dataSurface->SurfWinShadingFlag(m_SurfNum)) || ANY_BLIND(state.dataSurface->SurfWinShadingFlag(m_SurfNum))) {
     404         2688 :                 m_ConstructionNumber = state.dataSurface->SurfWinActiveShadedConstruction(m_SurfNum);
     405         2688 :                 m_TotLay = getNumOfLayers(state);
     406              :             }
     407              :         }
     408         4536 :         const WinShadingType ShadeFlag = getShadeType(state, m_ConstructionNumber);
     409              : 
     410         4536 :         if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
     411         2718 :             m_ShadePosition = ShadePosition::Interior;
     412              :         }
     413              : 
     414         1818 :         else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
     415            6 :             m_ShadePosition = ShadePosition::Exterior;
     416              :         }
     417              : 
     418         1812 :         else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
     419            3 :             m_ShadePosition = ShadePosition::Between;
     420              :         }
     421         4536 :     }
     422              : 
     423              :     /////////////////////////////////////////////////////////////////////////////////////////
     424         4032 :     std::shared_ptr<Tarcog::ISO15099::CSingleSystem> CWCEHeatTransferFactory::getTarcogSystem(EnergyPlusData &state, Real64 const t_HextConvCoeff)
     425              :     {
     426         4032 :         auto Indoor = getIndoor(state);                    // (AUTO_OK_SPTR)
     427         4032 :         auto Outdoor = getOutdoor(state, t_HextConvCoeff); // (AUTO_OK_SPTR)
     428         4032 :         auto aIGU = getIGU();                              // (AUTO_OK_OBJ)
     429              : 
     430              :         // pick-up all layers and put them in IGU (this includes gap layers as well)
     431        13440 :         for (int i = 0; i < m_TotLay; ++i) {
     432         9408 :             auto aLayer = getIGULayer(state, i + 1); // (AUTO_OK_SPTR)
     433         9408 :             assert(aLayer != nullptr);
     434              :             // IDF for "standard" windows do not insert gas between glass and shade. Tarcog needs that gas
     435              :             // and it will be created here
     436         9408 :             if (m_ShadePosition == ShadePosition::Interior && i == m_TotLay - 1) {
     437         2688 :                 auto aAirLayer = getShadeToGlassLayer(state, i + 1); // (AUTO_OK_SPTR)
     438         2688 :                 aIGU.addLayer(aAirLayer);
     439         2688 :             }
     440         9408 :             aIGU.addLayer(aLayer);
     441         9408 :             if (m_ShadePosition == ShadePosition::Exterior && i == 0) {
     442            0 :                 auto aAirLayer = getShadeToGlassLayer(state, i + 1); // (AUTO_OK_SPTR)
     443            0 :                 aIGU.addLayer(aAirLayer);
     444            0 :             }
     445         9408 :         }
     446              : 
     447         8064 :         return std::make_shared<Tarcog::ISO15099::CSingleSystem>(aIGU, Indoor, Outdoor);
     448         4032 :     }
     449              : 
     450         1770 :     std::shared_ptr<Tarcog::ISO15099::IIGUSystem> CWCEHeatTransferFactory::getTarcogSystemForReporting(
     451              :         EnergyPlusData &state, bool const useSummerConditions, const Real64 width, const Real64 height, const Real64 tilt)
     452              :     {
     453         1770 :         auto Indoor = getIndoorNfrc(useSummerConditions);   // (AUTO_OK_SPTR)
     454         1770 :         auto Outdoor = getOutdoorNfrc(useSummerConditions); // (AUTO_OK_SPTR)
     455         1770 :         auto aIGU = getIGU(width, height, tilt);            // (AUTO_OK_OBJ)
     456              : 
     457         1770 :         m_SolidLayerIndex = 0;
     458              :         // pick-up all layers and put them in IGU (this includes gap layers as well)
     459         5876 :         for (int i = 0; i < m_TotLay; ++i) {
     460         4106 :             auto aLayer = getIGULayer(state, i + 1); // (AUTO_OK_SPTR)
     461         4106 :             assert(aLayer != nullptr);
     462              :             // IDF for "standard" windows do not insert gas between glass and shade. Tarcog needs that gas
     463              :             // and it will be created here
     464         4106 :             if (m_ShadePosition == ShadePosition::Interior && i == m_TotLay - 1) {
     465           60 :                 auto aAirLayer = getShadeToGlassLayer(state, i + 1); // (AUTO_OK_SPTR)
     466           60 :                 aIGU.addLayer(aAirLayer);
     467           60 :             }
     468         4106 :             aIGU.addLayer(aLayer);
     469         4106 :             if (m_ShadePosition == ShadePosition::Exterior && i == 0) {
     470           12 :                 auto aAirLayer = getShadeToGlassLayer(state, i + 1); // (AUTO_OK_SPTR)
     471           12 :                 aIGU.addLayer(aAirLayer);
     472           12 :             }
     473         4106 :         }
     474              : 
     475         3540 :         return std::make_shared<Tarcog::ISO15099::CSystem>(aIGU, Indoor, Outdoor);
     476         1770 :     }
     477              : 
     478              :     /////////////////////////////////////////////////////////////////////////////////////////
     479        14930 :     Material::MaterialBase *CWCEHeatTransferFactory::getLayerMaterial(EnergyPlusData &state, int const t_Index) const
     480              :     {
     481        14930 :         int ConstrNum = m_ConstructionNumber;
     482              : 
     483              :         // BSDF window do not have special shading flag
     484        25804 :         if (!state.dataConstruction->Construct(ConstrNum).WindowTypeBSDF &&
     485        10874 :             state.dataSurface->SurfWinShadingFlag.size() >= static_cast<size_t>(m_SurfNum)) {
     486        10874 :             if (ANY_SHADE_SCREEN(state.dataSurface->SurfWinShadingFlag(m_SurfNum)) || ANY_BLIND(state.dataSurface->SurfWinShadingFlag(m_SurfNum))) {
     487         6720 :                 ConstrNum = state.dataSurface->SurfWinActiveShadedConstruction(m_SurfNum);
     488              :             }
     489              :         }
     490              : 
     491        14930 :         auto &construction = state.dataConstruction->Construct(ConstrNum);
     492        14930 :         const int LayPtr = construction.LayerPoint(t_Index);
     493        14930 :         return state.dataMaterial->materials(LayPtr);
     494              :     }
     495              : 
     496              :     /////////////////////////////////////////////////////////////////////////////////////////
     497        13514 :     std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> CWCEHeatTransferFactory::getIGULayer(EnergyPlusData &state, int const t_Index)
     498              :     {
     499        13514 :         std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> aLayer = nullptr;
     500              : 
     501        13514 :         auto *material = getLayerMaterial(state, t_Index);
     502              : 
     503        13514 :         Material::Group matGroup = material->group;
     504              : 
     505        13514 :         if ((matGroup == Material::Group::Glass) || (matGroup == Material::Group::GlassSimple) || (matGroup == Material::Group::Blind) ||
     506         2484 :             (matGroup == Material::Group::Shade) || (matGroup == Material::Group::Screen) || (matGroup == Material::Group::ComplexShade)) {
     507        11038 :             ++m_SolidLayerIndex;
     508        11038 :             aLayer = getSolidLayer(state, material, m_SolidLayerIndex);
     509         2476 :         } else if (matGroup == Material::Group::Gas || matGroup == Material::Group::GasMixture) {
     510         1124 :             aLayer = getGapLayer(material);
     511         1352 :         } else if (matGroup == Material::Group::ComplexWindowGap) {
     512         1352 :             aLayer = getComplexGapLayer(state, material);
     513              :         }
     514              : 
     515        13514 :         return aLayer;
     516            0 :     }
     517              : 
     518              :     /////////////////////////////////////////////////////////////////////////////////////////
     519         7224 :     int CWCEHeatTransferFactory::getNumOfLayers(EnergyPlusData &state) const
     520              :     {
     521         7224 :         return state.dataConstruction->Construct(m_ConstructionNumber).TotLayers;
     522              :     }
     523              : 
     524              :     /////////////////////////////////////////////////////////////////////////////////////////
     525              :     std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer>
     526        11038 :     CWCEHeatTransferFactory::getSolidLayer(EnergyPlusData &state, Material::MaterialBase const *mat, int const t_Index)
     527              :     {
     528              :         // SUBROUTINE INFORMATION:
     529              :         //       AUTHOR         Simon Vidanovic
     530              :         //       DATE WRITTEN   July 2016
     531              :         //       MODIFIED       na
     532              :         //       RE-ENGINEERED  na
     533              : 
     534              :         // PURPOSE OF THIS SUBROUTINE:
     535              :         // Creates solid layer object from material properties in EnergyPlus
     536        11038 :         Real64 emissFront = 0.0;
     537        11038 :         Real64 emissBack = 0.0;
     538        11038 :         Real64 transThermalFront = 0.0;
     539        11038 :         Real64 transThermalBack = 0.0;
     540        11038 :         Real64 thickness = 0.0;
     541        11038 :         Real64 conductivity = 0.0;
     542        11038 :         Real64 createOpenness = false;
     543        11038 :         Real64 Atop = 0.0;
     544        11038 :         Real64 Abot = 0.0;
     545        11038 :         Real64 Aleft = 0.0;
     546        11038 :         Real64 Aright = 0.0;
     547        11038 :         Real64 Afront = 0.0;
     548              : 
     549        11038 :         if (mat->group == Material::Group::Glass || mat->group == Material::Group::GlassSimple) {
     550         8264 :             auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
     551         8264 :             assert(matGlass != nullptr);
     552              : 
     553         8264 :             emissFront = matGlass->AbsorpThermalFront;
     554         8264 :             emissBack = matGlass->AbsorpThermalBack;
     555         8264 :             transThermalFront = matGlass->TransThermal;
     556         8264 :             transThermalBack = matGlass->TransThermal;
     557         8264 :             thickness = matGlass->Thickness;
     558         8264 :             conductivity = matGlass->Conductivity;
     559              : 
     560        11038 :         } else if (mat->group == Material::Group::Blind) {
     561              :             // auto const &surfShade = state.dataSurface->surfShades(m_SurfNum);
     562         1350 :             auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(mat);
     563         1350 :             assert(matBlind != nullptr);
     564         1350 :             thickness = matBlind->SlatThickness;
     565         1350 :             conductivity = matBlind->SlatConductivity;
     566         1350 :             Atop = matBlind->topOpeningMult;
     567         1350 :             Abot = matBlind->bottomOpeningMult;
     568         1350 :             Aleft = matBlind->leftOpeningMult;
     569         1350 :             Aright = matBlind->rightOpeningMult;
     570              : 
     571         1350 :             Real64 slatAng = matBlind->SlatAngle * Constant::DegToRad;
     572         1350 :             Real64 PermA = std::sin(slatAng) - matBlind->SlatThickness / matBlind->SlatSeparation;
     573              :             Real64 PermB =
     574         1350 :                 1.0 - (std::abs(matBlind->SlatWidth * std::cos(slatAng)) + matBlind->SlatThickness * std::sin(slatAng)) / matBlind->SlatSeparation;
     575         1350 :             Afront = min(1.0, max(0.0, PermA, PermB));
     576              : 
     577              :             int iSlatLo, iSlatHi;
     578              :             Real64 interpFac;
     579              : 
     580         1350 :             Material::GetSlatIndicesInterpFac(slatAng, iSlatLo, iSlatHi, interpFac);
     581              : 
     582         1350 :             emissFront = Interp(matBlind->TARs[iSlatLo].IR.Ft.Emi, matBlind->TARs[iSlatHi].IR.Ft.Emi, interpFac);
     583         1350 :             emissBack = Interp(matBlind->TARs[iSlatLo].IR.Bk.Emi, matBlind->TARs[iSlatHi].IR.Bk.Emi, interpFac);
     584         1350 :             transThermalFront = Interp(matBlind->TARs[iSlatLo].IR.Ft.Tra, matBlind->TARs[iSlatHi].IR.Ft.Tra, interpFac);
     585         1350 :             transThermalBack = Interp(matBlind->TARs[iSlatLo].IR.Bk.Tra, matBlind->TARs[iSlatHi].IR.Bk.Tra, interpFac);
     586              : 
     587         1350 :             if (t_Index == 1) {
     588            0 :                 m_ExteriorShade = true;
     589              :             }
     590              : 
     591         1424 :         } else if (mat->group == Material::Group::Shade) {
     592         1416 :             auto const *matShade = dynamic_cast<Material::MaterialShade const *>(mat);
     593         1416 :             assert(matShade != nullptr);
     594              : 
     595         1416 :             emissFront = matShade->AbsorpThermal;
     596         1416 :             emissBack = matShade->AbsorpThermal;
     597         1416 :             transThermalFront = matShade->TransThermal;
     598         1416 :             transThermalBack = matShade->TransThermal;
     599         1416 :             thickness = matShade->Thickness;
     600         1416 :             conductivity = matShade->Conductivity;
     601              : 
     602         1416 :             Atop = matShade->topOpeningMult;
     603         1416 :             Abot = matShade->bottomOpeningMult;
     604         1416 :             Aleft = matShade->leftOpeningMult;
     605         1416 :             Aright = matShade->rightOpeningMult;
     606         1416 :             Afront = matShade->airFlowPermeability;
     607         1416 :             if (t_Index == 1) {
     608           12 :                 m_ExteriorShade = true;
     609              :             }
     610              : 
     611            8 :         } else if (mat->group == Material::Group::Screen) {
     612            0 :             auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(mat);
     613            0 :             assert(matScreen != nullptr);
     614              : 
     615              :             // Simon: Existing code already takes into account geometry of Woven and scales down
     616              :             // emissivity for opening area.
     617            0 :             emissFront = matScreen->AbsorpThermal;
     618            0 :             emissBack = matScreen->AbsorpThermal;
     619            0 :             transThermalFront = matScreen->TransThermal;
     620            0 :             transThermalBack = matScreen->TransThermal;
     621            0 :             thickness = matScreen->Thickness;
     622            0 :             conductivity = matScreen->Conductivity;
     623              : 
     624            0 :             Atop = matScreen->topOpeningMult;
     625            0 :             Abot = matScreen->bottomOpeningMult;
     626            0 :             Aleft = matScreen->leftOpeningMult;
     627            0 :             Aright = matScreen->rightOpeningMult;
     628            0 :             Afront = matScreen->airFlowPermeability;
     629            0 :             if (t_Index == 1) {
     630            0 :                 m_ExteriorShade = true;
     631              :             }
     632              : 
     633            8 :         } else if (mat->group == Material::Group::ComplexShade) {
     634            8 :             auto const *matShade = dynamic_cast<Material::MaterialComplexShade const *>(mat);
     635            8 :             assert(matShade != nullptr);
     636              : 
     637            8 :             thickness = matShade->Thickness;
     638            8 :             conductivity = matShade->Conductivity;
     639            8 :             emissFront = matShade->FrontEmissivity;
     640            8 :             emissBack = matShade->BackEmissivity;
     641            8 :             transThermalFront = matShade->TransThermal;
     642            8 :             transThermalBack = matShade->TransThermal;
     643            8 :             Afront = matShade->frontOpeningMult;
     644            8 :             Atop = matShade->topOpeningMult;
     645            8 :             Abot = matShade->bottomOpeningMult;
     646            8 :             Aleft = matShade->leftOpeningMult;
     647            8 :             Aright = matShade->rightOpeningMult;
     648            8 :             createOpenness = true;
     649            8 :             m_InteriorBSDFShade = ((2 * t_Index - 1) == m_TotLay);
     650              :         }
     651              : 
     652        11038 :         std::shared_ptr<Tarcog::ISO15099::ISurface> frontSurface = std::make_shared<Tarcog::ISO15099::CSurface>(emissFront, transThermalFront);
     653        11038 :         std::shared_ptr<Tarcog::ISO15099::ISurface> backSurface = std::make_shared<Tarcog::ISO15099::CSurface>(emissBack, transThermalBack);
     654              :         auto aSolidLayer = // (AUTO_OK_SPTR)
     655        11038 :             std::make_shared<Tarcog::ISO15099::CIGUSolidLayer>(thickness, conductivity, frontSurface, backSurface);
     656        11038 :         if (createOpenness) {
     657            8 :             auto aOpenings = std::make_shared<Tarcog::ISO15099::CShadeOpenings>(Atop, Abot, Aleft, Aright, Afront, Afront); // (AUTO_OK_SPTR)
     658            8 :             aSolidLayer = std::make_shared<Tarcog::ISO15099::CIGUShadeLayer>(aSolidLayer, aOpenings);
     659            8 :         }
     660              :         static constexpr double standardizedRadiationIntensity = 783.0;
     661        11038 :         if (state.dataWindowManager->inExtWindowModel->isExternalLibraryModel()) {
     662         8064 :             auto &surface(state.dataSurface->Surface(m_SurfNum));
     663         8064 :             const int ConstrNum = getActiveConstructionNumber(state, surface, m_SurfNum);
     664              :             std::shared_ptr<MultiLayerOptics::CMultiLayerScattered> aLayer =
     665         8064 :                 CWindowConstructionsSimplified::instance(state).getEquivalentLayer(state, FenestrationCommon::WavelengthRange::Solar, ConstrNum);
     666              : 
     667              :             // Report is done for normal incidence
     668         8064 :             constexpr Real64 Theta = 0.0;
     669         8064 :             constexpr Real64 Phi = 0.0;
     670              :             const Real64 absCoeff =
     671         8064 :                 aLayer->getAbsorptanceLayer(t_Index, FenestrationCommon::Side::Front, FenestrationCommon::ScatteringSimple::Diffuse, Theta, Phi);
     672         8064 :             aSolidLayer->setSolarAbsorptance(absCoeff, standardizedRadiationIntensity);
     673         8064 :         } else {
     674         2974 :             const Real64 absCoeff{state.dataConstruction->Construct(state.dataSurface->Surface(m_SurfNum).Construction).AbsDiff(t_Index)};
     675         2974 :             aSolidLayer->setSolarAbsorptance(absCoeff, standardizedRadiationIntensity);
     676              :         }
     677        22076 :         return aSolidLayer;
     678        11038 :     }
     679              : 
     680              :     /////////////////////////////////////////////////////////////////////////////////////////
     681         1124 :     std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> CWCEHeatTransferFactory::getGapLayer(Material::MaterialBase const *material) const
     682              :     {
     683              :         // SUBROUTINE INFORMATION:
     684              :         //       AUTHOR         Simon Vidanovic
     685              :         //       DATE WRITTEN   July 2016
     686              :         //       MODIFIED       na
     687              :         //       RE-ENGINEERED  na
     688              : 
     689              :         // PURPOSE OF THIS SUBROUTINE:
     690              :         // Creates gap layer object from material properties in EnergyPlus
     691         1124 :         Real64 constexpr pres = 1e5; // Old code uses this constant pressure
     692         1124 :         Real64 thickness = material->Thickness;
     693         1124 :         auto aGas = getGas(material); // (AUTO_OK_OBJ)
     694         1124 :         std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> aLayer = std::make_shared<Tarcog::ISO15099::CIGUGapLayer>(thickness, pres, aGas);
     695         2248 :         return aLayer;
     696         1124 :     }
     697              : 
     698              :     /////////////////////////////////////////////////////////////////////////////////////////
     699         2760 :     std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> CWCEHeatTransferFactory::getShadeToGlassLayer(EnergyPlusData &state, int const t_Index) const
     700              :     {
     701              :         // SUBROUTINE INFORMATION:
     702              :         //       AUTHOR         Simon Vidanovic
     703              :         //       DATE WRITTEN   August 2016
     704              :         //       MODIFIED       na
     705              :         //       RE-ENGINEERED  na
     706              : 
     707              :         // PURPOSE OF THIS SUBROUTINE:
     708              :         // Creates gap layer object from material properties in EnergyPlus
     709         2760 :         Real64 constexpr pres = 1e5; // Old code uses this constant pressure
     710         2760 :         auto aGas = getAir();        // (AUTO_OK_OBJ)
     711         2760 :         Real64 thickness = 0.0;
     712              : 
     713         2760 :         auto &s_mat = state.dataMaterial;
     714         2760 :         auto &surfWin = state.dataSurface->SurfaceWindow(m_SurfNum);
     715         2760 :         auto const &surfShade = state.dataSurface->surfShades(m_SurfNum);
     716              : 
     717         2760 :         const WinShadingType ShadeFlag = getShadeType(state, m_ConstructionNumber);
     718              : 
     719         2760 :         if (ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind) {
     720         1344 :             thickness = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(surfShade.blind.matNum))->toGlassDist;
     721         1416 :         } else if (ShadeFlag == WinShadingType::ExtScreen) {
     722            0 :             thickness = dynamic_cast<Material::MaterialScreen const *>(s_mat->materials(surfWin.screenNum))->toGlassDist;
     723         1416 :         } else if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) {
     724         1416 :             const auto *material = dynamic_cast<Material::MaterialShade *>(getLayerMaterial(state, t_Index));
     725         1416 :             assert(material != nullptr);
     726         1416 :             thickness = material->toGlassDist;
     727              :         }
     728         2760 :         std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> aLayer = std::make_shared<Tarcog::ISO15099::CIGUGapLayer>(thickness, pres, aGas);
     729         5520 :         return aLayer;
     730         2760 :     }
     731              : 
     732              :     /////////////////////////////////////////////////////////////////////////////////////////
     733         1352 :     std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> CWCEHeatTransferFactory::getComplexGapLayer([[maybe_unused]] EnergyPlusData &state,
     734              :                                                                                                  Material::MaterialBase const *materialBase) const
     735              :     {
     736              :         // SUBROUTINE INFORMATION:
     737              :         //       AUTHOR         Simon Vidanovic
     738              :         //       DATE WRITTEN   July 2016
     739              :         //       MODIFIED       na
     740              :         //       RE-ENGINEERED  na
     741              : 
     742              :         // PURPOSE OF THIS SUBROUTINE:
     743              :         // Creates gap layer object from material properties in EnergyPlus
     744         1352 :         Real64 constexpr pres = 1e5; // Old code uses this constant pressure
     745         1352 :         auto const *mat = dynamic_cast<Material::MaterialComplexWindowGap const *>(materialBase);
     746         1352 :         assert(mat != nullptr);
     747         1352 :         Real64 thickness = mat->Thickness;
     748         1352 :         auto aGas = getGas(mat); // (AUTO_OK_OBJ)
     749         2704 :         return std::make_shared<Tarcog::ISO15099::CIGUGapLayer>(thickness, pres, aGas);
     750         1352 :     }
     751              : 
     752              :     /////////////////////////////////////////////////////////////////////////////////////////
     753         2476 :     Gases::CGas CWCEHeatTransferFactory::getGas(Material::MaterialBase const *materialBase) const
     754              :     {
     755              :         // SUBROUTINE INFORMATION:
     756              :         //       AUTHOR         Simon Vidanovic
     757              :         //       DATE WRITTEN   July 2016
     758              :         //       MODIFIED       na
     759              :         //       RE-ENGINEERED
     760              :         //          April 2021: April 2021: Return of CGas instead of pointer to it
     761              : 
     762              :         // PURPOSE OF THIS SUBROUTINE:
     763              :         // Creates gap layer object from material properties in EnergyPlus
     764         2476 :         auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(materialBase);
     765         2476 :         assert(matGas != nullptr);
     766         2476 :         const int numGases = matGas->numGases;
     767         2476 :         double constexpr vacuumCoeff = 1.4; // Load vacuum coefficient once it is implemented (Simon).
     768         2476 :         std::string const &gasName = matGas->Name;
     769         2476 :         Gases::CGas aGas;
     770         4994 :         for (int i = 0; i < numGases; ++i) {
     771         2518 :             auto const &gas = matGas->gases[i];
     772         2518 :             Real64 wght = gas.wght;
     773         2518 :             Real64 fract = matGas->gasFracts[i];
     774         2518 :             Gases::CIntCoeff aCon(gas.con.c0, gas.con.c1, gas.con.c2);
     775         2518 :             Gases::CIntCoeff aCp(gas.cp.c0, gas.cp.c1, gas.cp.c2);
     776         2518 :             Gases::CIntCoeff aVis(gas.vis.c0, gas.vis.c1, gas.vis.c2);
     777         2518 :             Gases::CGasData aData(gasName, wght, vacuumCoeff, aCp, aCon, aVis);
     778         2518 :             aGas.addGasItem(fract, aData);
     779         2518 :         }
     780         2476 :         return aGas;
     781            0 :     }
     782              : 
     783              :     /////////////////////////////////////////////////////////////////////////////////////////
     784         2760 :     Gases::CGas CWCEHeatTransferFactory::getAir()
     785              :     {
     786              :         // SUBROUTINE INFORMATION:
     787              :         //       AUTHOR         Simon Vidanovic
     788              :         //       DATE WRITTEN   August 2016
     789              :         //       MODIFIED       na
     790              :         //       RE-ENGINEERED
     791              :         //          April 2021: CGas return from the function instead of pointer to it
     792              : 
     793              :         // PURPOSE OF THIS SUBROUTINE:
     794              :         // Creates air gas layer for tarcog routines
     795         2760 :         return {};
     796              :     }
     797              : 
     798              :     /////////////////////////////////////////////////////////////////////////////////////////
     799         4032 :     std::shared_ptr<Tarcog::ISO15099::CEnvironment> CWCEHeatTransferFactory::getIndoor(EnergyPlusData &state) const
     800              :     {
     801              :         // SUBROUTINE INFORMATION:
     802              :         //       AUTHOR         Simon Vidanovic
     803              :         //       DATE WRITTEN   July 2016
     804              :         //       MODIFIED       na
     805              :         //       RE-ENGINEERED  na
     806              : 
     807              :         // PURPOSE OF THIS SUBROUTINE:
     808              :         // Creates indoor environment object from surface properties in EnergyPlus
     809         4032 :         Real64 tin = m_Surface.getInsideAirTemperature(state, m_SurfNum) + Constant::Kelvin;
     810         4032 :         Real64 hcin = state.dataHeatBalSurf->SurfHConvInt(m_SurfNum);
     811              : 
     812         4032 :         Real64 IR = state.dataSurface->SurfWinIRfromParentZone(m_SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(m_SurfNum);
     813              : 
     814              :         std::shared_ptr<Tarcog::ISO15099::CEnvironment> Indoor =
     815         4032 :             std::make_shared<Tarcog::ISO15099::CIndoorEnvironment>(tin, state.dataEnvrn->OutBaroPress);
     816         4032 :         Indoor->setHCoeffModel(Tarcog::ISO15099::BoundaryConditionsCoeffModel::CalculateH, hcin);
     817         4032 :         Indoor->setEnvironmentIR(IR);
     818         8064 :         return Indoor;
     819            0 :     }
     820              : 
     821              :     /////////////////////////////////////////////////////////////////////////////////////////
     822         4032 :     std::shared_ptr<Tarcog::ISO15099::CEnvironment> CWCEHeatTransferFactory::getOutdoor(EnergyPlusData &state, const Real64 t_Hext) const
     823              :     {
     824              :         // SUBROUTINE INFORMATION:
     825              :         //       AUTHOR         Simon Vidanovic
     826              :         //       DATE WRITTEN   July 2016
     827              :         //       MODIFIED       na
     828              :         //       RE-ENGINEERED  na
     829              : 
     830              :         // PURPOSE OF THIS SUBROUTINE:
     831              :         // Creates outdoor environment object from surface properties in EnergyPlus
     832         4032 :         double tout = m_Surface.getOutsideAirTemperature(state, m_SurfNum) + Constant::Kelvin;
     833         4032 :         double IR = m_Surface.getOutsideIR(state, m_SurfNum);
     834              :         // double dirSolRad = SurfQRadSWOutIncident( t_SurfNum ) + QS( Surface( t_SurfNum ).Zone );
     835         4032 :         double swRadiation = m_Surface.getSWIncident(state, m_SurfNum);
     836         4032 :         double tSky = state.dataEnvrn->SkyTempKelvin;
     837         4032 :         double airSpeed = 0.0;
     838         4032 :         if (m_Surface.ExtWind) {
     839         4032 :             airSpeed = state.dataSurface->SurfOutWindSpeed(m_SurfNum);
     840              :         }
     841         4032 :         double fclr = 1 - state.dataEnvrn->CloudFraction;
     842         4032 :         Tarcog::ISO15099::AirHorizontalDirection airDirection = Tarcog::ISO15099::AirHorizontalDirection::Windward;
     843         4032 :         std::shared_ptr<Tarcog::ISO15099::CEnvironment> Outdoor = std::make_shared<Tarcog::ISO15099::COutdoorEnvironment>(
     844         4032 :             tout, airSpeed, swRadiation, airDirection, tSky, Tarcog::ISO15099::SkyModel::AllSpecified, state.dataEnvrn->OutBaroPress, fclr);
     845         4032 :         Outdoor->setHCoeffModel(Tarcog::ISO15099::BoundaryConditionsCoeffModel::HcPrescribed, t_Hext);
     846         4032 :         Outdoor->setEnvironmentIR(IR);
     847         8064 :         return Outdoor;
     848            0 :     }
     849              : 
     850              :     /////////////////////////////////////////////////////////////////////////////////////////
     851         4032 :     Tarcog::ISO15099::CIGU CWCEHeatTransferFactory::getIGU() const
     852              :     {
     853              :         // SUBROUTINE INFORMATION:
     854              :         //       AUTHOR         Simon Vidanovic
     855              :         //       DATE WRITTEN   July 2016
     856              :         //       MODIFIED       na
     857              :         //       RE-ENGINEERED
     858              :         //          April 2021: Return CIGU object rather than pointer to it
     859              : 
     860              :         // PURPOSE OF THIS SUBROUTINE:
     861              :         // Creates IGU object from surface properties in EnergyPlus
     862              : 
     863         4032 :         return {m_Surface.Width, m_Surface.Height, m_Surface.Tilt};
     864              :     }
     865              : 
     866         1770 :     Tarcog::ISO15099::CIGU CWCEHeatTransferFactory::getIGU(double width, double height, double tilt)
     867              :     {
     868              :         // SUBROUTINE INFORMATION:
     869              :         //       AUTHOR         Simon Vidanovic
     870              :         //       DATE WRITTEN   November 2021
     871              :         //       MODIFIED       na
     872              :         //       RE-ENGINEERED
     873              :         //          April 2021: Return CIGU object rather than pointer to it
     874              : 
     875              :         // PURPOSE OF THIS SUBROUTINE:
     876              :         // Creates IGU object for given width, height and tilt
     877              : 
     878         1770 :         return {width, height, tilt};
     879              :     }
     880              : 
     881              :     int
     882        12096 :     CWCEHeatTransferFactory::getActiveConstructionNumber(EnergyPlusData &state, EnergyPlus::DataSurfaces::SurfaceData const &surface, int t_SurfNum)
     883              :     {
     884        12096 :         int result = surface.Construction;
     885        12096 :         const WinShadingType ShadeFlag = state.dataSurface->SurfWinShadingFlag(t_SurfNum);
     886              : 
     887        12096 :         if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
     888         8064 :             result = state.dataSurface->SurfWinActiveShadedConstruction(t_SurfNum);
     889              :         }
     890              : 
     891        12096 :         return result;
     892              :     }
     893              : 
     894              :     /////////////////////////////////////////////////////////////////////////////////////////
     895         1344 :     bool CWCEHeatTransferFactory::isInteriorShade() const
     896              :     {
     897         1344 :         return m_InteriorBSDFShade;
     898              :     }
     899              : 
     900         1770 :     std::shared_ptr<Tarcog::ISO15099::CEnvironment> CWCEHeatTransferFactory::getOutdoorNfrc(bool const useSummerConditions)
     901              :     {
     902              :         // NFRC 100 Section 4.3.1
     903         1770 :         Real64 airTemperature = -18.0 + Constant::Kelvin; // Kelvins
     904         1770 :         Real64 airSpeed = 5.5;                            // meters per second
     905         1770 :         Real64 tSky = -18.0 + Constant::Kelvin;           // Kelvins
     906         1770 :         Real64 solarRadiation = 0.;                       // W/m2
     907         1770 :         if (useSummerConditions) {
     908              :             // NFRC 200 Section 4.3.1
     909          463 :             airTemperature = 32.0 + Constant::Kelvin;
     910          463 :             airSpeed = 2.75;
     911          463 :             tSky = 32.0 + Constant::Kelvin;
     912          463 :             solarRadiation = 783.;
     913              :         }
     914              :         auto Outdoor = // (AUTO_OK_SPTR)
     915         1770 :             Tarcog::ISO15099::Environments::outdoor(airTemperature, airSpeed, solarRadiation, tSky, Tarcog::ISO15099::SkyModel::AllSpecified);
     916         1770 :         Outdoor->setHCoeffModel(Tarcog::ISO15099::BoundaryConditionsCoeffModel::CalculateH);
     917         3540 :         return Outdoor;
     918         1770 :     }
     919              : 
     920         1770 :     std::shared_ptr<Tarcog::ISO15099::CEnvironment> CWCEHeatTransferFactory::getIndoorNfrc(bool const useSummerConditions)
     921              :     {
     922              :         // NFRC 100 Section 4.3.1
     923         1770 :         Real64 roomTemperature = 21. + Constant::Kelvin;
     924         1770 :         if (useSummerConditions) {
     925              :             // NFRC 200 Section 4.3.1
     926          463 :             roomTemperature = 24. + Constant::Kelvin;
     927              :         }
     928         1770 :         return Tarcog::ISO15099::Environments::indoor(roomTemperature);
     929              :     }
     930              : 
     931         7296 :     WinShadingType CWCEHeatTransferFactory::getShadeType(EnergyPlusData &state, int ConstrNum)
     932              :     {
     933         7296 :         auto &s_mat = state.dataMaterial;
     934         7296 :         WinShadingType ShadeFlag = WinShadingType::NoShade;
     935              : 
     936         7296 :         const int TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
     937         7296 :         const int TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
     938         7296 :         const int matOutNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(1);
     939         7296 :         const int matInNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLay);
     940              : 
     941         7296 :         auto const *matOut = s_mat->materials(matOutNum);
     942         7296 :         auto const *matIn = s_mat->materials(matInNum);
     943              : 
     944         7296 :         if (matOut->group == Material::Group::Shade) { // Exterior shade present
     945           18 :             ShadeFlag = WinShadingType::ExtShade;
     946         7278 :         } else if (matOut->group == Material::Group::Screen) { // Exterior screen present
     947            0 :             ShadeFlag = WinShadingType::ExtScreen;
     948         7278 :         } else if (matOut->group == Material::Group::Blind) { // Exterior blind present
     949            0 :             ShadeFlag = WinShadingType::ExtBlind;
     950         7278 :         } else if (matIn->group == Material::Group::Shade) { // Interior shade present
     951         2778 :             ShadeFlag = WinShadingType::IntShade;
     952         4500 :         } else if (matIn->group == Material::Group::Blind) { // Interior blind present
     953         2688 :             ShadeFlag = WinShadingType::IntBlind;
     954         1812 :         } else if (TotGlassLay == 2) {
     955         1645 :             auto const *mat3 = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(3));
     956         1645 :             if (mat3->group == Material::Group::Shade) {
     957            0 :                 ShadeFlag = WinShadingType::BGShade;
     958         1645 :             } else if (mat3->group == Material::Group::Blind) {
     959            3 :                 ShadeFlag = WinShadingType::BGBlind;
     960              :             }
     961          167 :         } else if (TotGlassLay == 3) {
     962            2 :             auto const *mat5 = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(5));
     963            2 :             if (mat5->group == Material::Group::Shade) {
     964            0 :                 ShadeFlag = WinShadingType::BGShade;
     965            2 :             } else if (mat5->group == Material::Group::Blind) {
     966            0 :                 ShadeFlag = WinShadingType::BGBlind;
     967              :             }
     968              :         }
     969              : 
     970         7296 :         return ShadeFlag;
     971              :     }
     972              : 
     973         1688 :     double CWCEHeatTransferFactory::overallUfactorFromFilmsAndCond(double conductance, double insideFilm, double outsideFilm)
     974              :     {
     975         1688 :         double rOverall(0.);
     976         1688 :         double uFactor(0.);
     977         1688 :         if (insideFilm != 0 && outsideFilm != 0. && conductance != 0.) {
     978          532 :             rOverall = 1 / insideFilm + 1 / conductance + 1 / outsideFilm;
     979              :         }
     980         1688 :         if (rOverall != 0.) {
     981          532 :             uFactor = 1 / rOverall;
     982              :         }
     983         1688 :         return uFactor;
     984              :     }
     985              : 
     986              : } // namespace Window
     987              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1