LCOV - code coverage report
Current view: top level - EnergyPlus - WindowManagerExteriorThermal.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 42.6 % 547 233
Test Date: 2025-06-02 12:03:30 Functions: 57.7 % 26 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              : // 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            0 :     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            0 :         auto &surf = state.dataSurface->Surface(SurfNum);
      95            0 :         auto &surfWin = state.dataSurface->SurfaceWindow(SurfNum);
      96            0 :         int ConstrNum = surf.Construction;
      97            0 :         auto &construction = state.dataConstruction->Construct(ConstrNum);
      98              : 
      99            0 :         constexpr Real64 solutionTolerance = 0.02;
     100              : 
     101              :         // Tarcog thermal system for solving heat transfer through the window
     102            0 :         int activeConstrNum = CWCEHeatTransferFactory::getActiveConstructionNumber(state, surf, SurfNum);
     103            0 :         auto aFactory = CWCEHeatTransferFactory(state, surf, SurfNum, activeConstrNum); // (AUTO_OK)
     104            0 :         auto aSystem = aFactory.getTarcogSystem(state, HextConvCoeff);                  // (AUTO_OK_SPTR)
     105            0 :         aSystem->setTolerance(solutionTolerance);
     106              : 
     107              :         // get previous timestep temperatures solution for faster iterations
     108            0 :         std::vector<Real64> Guess;
     109            0 :         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            0 :         if (ANY_SHADE_SCREEN(state.dataSurface->SurfWinShadingFlag(SurfNum)) || ANY_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
     114            0 :             ++totSolidLayers;
     115              :         }
     116              : 
     117            0 :         for (int k = 1; k <= 2 * totSolidLayers; ++k) {
     118            0 :             Guess.push_back(state.dataSurface->SurfaceWindow(SurfNum).thetaFace[k]);
     119              :         }
     120              : 
     121              :         try {
     122            0 :             aSystem->setInitialGuess(Guess);
     123            0 :             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            0 :         auto aLayers = aSystem->getSolidLayers(); // (AUTO_OK_OBJ)
     130            0 :         int i = 1;
     131            0 :         for (const auto &aLayer : aLayers) { // (AUTO_OK_SPTR)
     132            0 :             Real64 aTemp = 0;
     133            0 :             for (auto aSide : FenestrationCommon::EnumSide()) { // (AUTO_OK) I don't understand what this construct is
     134            0 :                 aTemp = aLayer->getTemperature(aSide);
     135            0 :                 state.dataWindowManager->thetas[i - 1] = aTemp;
     136            0 :                 if (i == 1) {
     137            0 :                     SurfOutsideTemp = aTemp - Constant::Kelvin;
     138              :                 }
     139            0 :                 ++i;
     140              :             }
     141            0 :             SurfInsideTemp = aTemp - Constant::Kelvin;
     142            0 :             if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
     143            0 :                 auto &surfShade = state.dataSurface->surfShades(SurfNum);
     144            0 :                 Real64 EffShBlEmiss = surfShade.effShadeEmi;
     145            0 :                 Real64 EffGlEmiss = surfShade.effGlassEmi;
     146            0 :                 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            0 :                 state.dataSurface->SurfWinEffInsSurfTemp(SurfNum) =
     155            0 :                     (EffShBlEmiss * SurfInsideTemp + EffGlEmiss * (state.dataWindowManager->thetas[2 * totSolidLayers - 3] - Constant::Kelvin)) /
     156            0 :                     (EffShBlEmiss + EffGlEmiss);
     157              :             }
     158            0 :         }
     159              : 
     160            0 :         state.dataHeatBalSurf->SurfHConvInt(SurfNum) = aSystem->getHc(Tarcog::ISO15099::Environment::Indoor);
     161            0 :         if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum)) || aFactory.isInteriorShade()) {
     162            0 :             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            0 :             int totLayers = aLayers.size();
     168            0 :             state.dataWindowManager->nglface = 2 * totLayers - 2;
     169            0 :             state.dataWindowManager->nglfacep = state.dataWindowManager->nglface + 2;
     170            0 :             auto aShadeLayer = aLayers[totLayers - 1]; // (AUTO_OK_SPTR)
     171            0 :             auto aGlassLayer = aLayers[totLayers - 2]; // (AUTO_OK_SPTR)
     172            0 :             Real64 ShadeArea = state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum);
     173            0 :             auto frontSurface = aShadeLayer->getSurface(FenestrationCommon::Side::Front); // (AUTO_OK_SPTR)
     174            0 :             auto backSurface = aShadeLayer->getSurface(FenestrationCommon::Side::Back);   // (AUTO_OK_SPTR)
     175            0 :             Real64 EpsShIR1 = frontSurface->getEmissivity();
     176            0 :             Real64 EpsShIR2 = backSurface->getEmissivity();
     177            0 :             Real64 TauShIR = frontSurface->getTransmittance();
     178            0 :             Real64 RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1);
     179            0 :             Real64 RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2);
     180            0 :             Real64 glassEmiss = aGlassLayer->getSurface(FenestrationCommon::Side::Back)->getEmissivity();
     181            0 :             Real64 RhoGlIR2 = 1.0 - glassEmiss;
     182            0 :             Real64 ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1;
     183            0 :             Real64 rmir = state.dataSurface->SurfWinIRfromParentZone(SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum);
     184              :             Real64 NetIRHeatGainShade =
     185            0 :                 ShadeArea * EpsShIR2 *
     186            0 :                     (Constant::StefanBoltzmann * pow(state.dataWindowManager->thetas[state.dataWindowManager->nglfacep - 1], 4) - rmir) +
     187            0 :                 EpsShIR1 * (Constant::StefanBoltzmann * pow(state.dataWindowManager->thetas[state.dataWindowManager->nglfacep - 2], 4) - rmir) *
     188            0 :                     RhoGlIR2 * TauShIR / ShGlReflFacIR;
     189              :             Real64 NetIRHeatGainGlass =
     190            0 :                 ShadeArea * (glassEmiss * TauShIR / ShGlReflFacIR) *
     191            0 :                 (Constant::StefanBoltzmann * pow(state.dataWindowManager->thetas[state.dataWindowManager->nglface - 1], 4) - rmir);
     192            0 :             Real64 tind = surf.getInsideAirTemperature(state, SurfNum) + Constant::Kelvin;
     193            0 :             Real64 ConvHeatGainFrZoneSideOfShade = ShadeArea * state.dataHeatBalSurf->SurfHConvInt(SurfNum) *
     194            0 :                                                    (state.dataWindowManager->thetas[state.dataWindowManager->nglfacep - 1] - tind);
     195            0 :             state.dataSurface->SurfWinHeatGain(SurfNum) =
     196            0 :                 state.dataSurface->SurfWinTransSolar(SurfNum) + ConvHeatGainFrZoneSideOfShade + NetIRHeatGainGlass + NetIRHeatGainShade;
     197              : 
     198            0 :             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            0 :             surfShade.effShadeEmi = EpsShIR1 * (1.0 + RhoGlIR2 * TauShIR / (1.0 - RhoGlIR2 * RhoShIR2));
     203            0 :             surfShade.effGlassEmi = glassEmiss * TauShIR / (1.0 - RhoGlIR2 * RhoShIR2);
     204              : 
     205            0 :             Real64 glassTemperature = aGlassLayer->getSurface(FenestrationCommon::Side::Back)->getTemperature();
     206            0 :             state.dataSurface->SurfWinEffInsSurfTemp(SurfNum) =
     207            0 :                 (surfShade.effShadeEmi * SurfInsideTemp + surfShade.effGlassEmi * (glassTemperature - Constant::Kelvin)) /
     208            0 :                 (surfShade.effShadeEmi + surfShade.effGlassEmi);
     209              : 
     210            0 :         } 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            0 :             auto &surfShade = state.dataSurface->surfShades(SurfNum);
     216            0 :             int totLayers = aLayers.size();
     217            0 :             auto aGlassLayer = aLayers[totLayers - 1];                                  // (AUTO_OK_SPTR)
     218            0 :             auto backSurface = aGlassLayer->getSurface(FenestrationCommon::Side::Back); // (AUTO_OK_SPTR)
     219              : 
     220            0 :             Real64 h_cin = aSystem->getHc(Tarcog::ISO15099::Environment::Indoor);
     221              :             Real64 ConvHeatGainFrZoneSideOfGlass =
     222            0 :                 surf.Area * h_cin * (backSurface->getTemperature() - aSystem->getAirTemperature(Tarcog::ISO15099::Environment::Indoor));
     223              : 
     224            0 :             Real64 rmir = state.dataSurface->SurfWinIRfromParentZone(SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum);
     225              :             Real64 NetIRHeatGainGlass =
     226            0 :                 surf.Area * backSurface->getEmissivity() * (Constant::StefanBoltzmann * pow(backSurface->getTemperature(), 4) - rmir);
     227              : 
     228            0 :             state.dataSurface->SurfWinEffInsSurfTemp(SurfNum) =
     229            0 :                 aLayers[totLayers - 1]->getTemperature(FenestrationCommon::Side::Back) - Constant::Kelvin;
     230            0 :             surfShade.effGlassEmi = aLayers[totLayers - 1]->getSurface(FenestrationCommon::Side::Back)->getEmissivity();
     231              : 
     232            0 :             state.dataSurface->SurfWinHeatGain(SurfNum) =
     233            0 :                 state.dataSurface->SurfWinTransSolar(SurfNum) + ConvHeatGainFrZoneSideOfGlass + NetIRHeatGainGlass;
     234            0 :             state.dataSurface->SurfWinGainConvGlazToZoneRep(SurfNum) = ConvHeatGainFrZoneSideOfGlass;
     235            0 :             state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) = NetIRHeatGainGlass;
     236            0 :         }
     237              : 
     238            0 :         state.dataSurface->SurfWinLossSWZoneToOutWinRep(SurfNum) =
     239            0 :             state.dataHeatBal->EnclSolQSWRad(state.dataSurface->Surface(SurfNum).SolarEnclIndex) * surf.Area * (1 - construction.ReflectSolDiffBack) +
     240            0 :             state.dataHeatBalSurf->SurfWinInitialBeamSolInTrans(SurfNum);
     241            0 :         state.dataSurface->SurfWinHeatGain(SurfNum) -=
     242            0 :             (state.dataSurface->SurfWinLossSWZoneToOutWinRep(SurfNum) + state.dataHeatBalSurf->SurfWinInitialDifSolInTrans(SurfNum) * surf.Area);
     243              : 
     244            0 :         for (int k = 1; k <= surf.getTotLayers(state); ++k) {
     245            0 :             surfWin.thetaFace[2 * k - 1] = state.dataWindowManager->thetas[2 * k - 2];
     246            0 :             surfWin.thetaFace[2 * k] = state.dataWindowManager->thetas[2 * k - 1];
     247              : 
     248              :             // temperatures for reporting
     249            0 :             state.dataHeatBal->SurfWinFenLaySurfTempFront(SurfNum, k) = state.dataWindowManager->thetas[2 * k - 2] - Constant::Kelvin;
     250            0 :             state.dataHeatBal->SurfWinFenLaySurfTempBack(SurfNum, k) = state.dataWindowManager->thetas[2 * k - 1] - Constant::Kelvin;
     251              :         }
     252            0 :     }
     253              : 
     254              :     Real64
     255            0 :     GetIGUUValueForNFRCReport(EnergyPlusData &state, const int surfNum, const int constrNum, const Real64 windowWidth, const Real64 windowHeight)
     256              :     {
     257            0 :         Real64 tilt = 90.0;
     258              : 
     259            0 :         auto &surface = state.dataSurface->Surface(surfNum);
     260            0 :         auto aFactory = CWCEHeatTransferFactory(state, surface, surfNum, constrNum); // (AUTO_OK)
     261              : 
     262            0 :         const auto winterGlassUnit = aFactory.getTarcogSystemForReporting(state, false, windowWidth, windowHeight, tilt); // (AUTO_OK_SPTR)
     263              : 
     264            0 :         return winterGlassUnit->getUValue();
     265            0 :     }
     266              : 
     267            0 :     Real64 GetSHGCValueForNFRCReporting(EnergyPlusData &state, int surfNum, int constrNum, Real64 windowWidth, Real64 windowHeight)
     268              :     {
     269            0 :         Real64 tilt = 90.0;
     270              : 
     271            0 :         auto &surface = state.dataSurface->Surface(surfNum);
     272            0 :         auto aFactory = CWCEHeatTransferFactory(state, surface, surfNum, constrNum); // (AUTO_OK)
     273              : 
     274            0 :         const auto summerGlassUnit = aFactory.getTarcogSystemForReporting(state, true, windowWidth, windowHeight, tilt); // (AUTO_OK_SPTR)
     275            0 :         return summerGlassUnit->getSHGC(state.dataConstruction->Construct(surface.Construction).SolTransNorm);
     276            0 :     }
     277              : 
     278            6 :     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            6 :         auto &surface = state.dataSurface->Surface(surfNum);
     289            6 :         auto &frameDivider = state.dataSurface->FrameDivider(surface.FrameDivider);
     290              : 
     291            6 :         auto aFactory = CWCEHeatTransferFactory(state, surface, surfNum, constrNum); // (AUTO_OK)
     292              : 
     293           18 :         for (bool isSummer : {false, true}) {
     294           12 :             constexpr Real64 framehExtConvCoeff = 30.0;
     295           12 :             constexpr Real64 framehIntConvCoeff = 8.0;
     296           12 :             constexpr Real64 tilt = 90.0;
     297              : 
     298           12 :             auto insulGlassUnit = aFactory.getTarcogSystemForReporting(state, isSummer, windowWidth, windowHeight, tilt); // (AUTO_OK_SPTR)
     299              : 
     300           12 :             const double centerOfGlassUvalue = insulGlassUnit->getUValue();
     301              : 
     302           12 :             auto winterGlassUnit = aFactory.getTarcogSystemForReporting(state, false, windowWidth, windowHeight, tilt); // (AUTO_OK_SPTR)
     303              : 
     304           12 :             const double frameUvalue = aFactory.overallUfactorFromFilmsAndCond(frameDivider.FrameConductance, framehIntConvCoeff, framehExtConvCoeff);
     305           12 :             const double frameEdgeUValue = winterGlassUnit->getUValue() * frameDivider.FrEdgeToCenterGlCondRatio; // not sure about this
     306           12 :             const double frameProjectedDimension = frameDivider.FrameWidth;
     307           12 :             const double frameWettedLength = frameProjectedDimension + frameDivider.FrameProjectionIn;
     308           12 :             const double frameAbsorptance = frameDivider.FrameSolAbsorp;
     309              : 
     310           12 :             Tarcog::ISO15099::FrameData frameData{frameUvalue, frameEdgeUValue, frameProjectedDimension, frameWettedLength, frameAbsorptance};
     311              : 
     312              :             const double dividerUvalue =
     313           12 :                 aFactory.overallUfactorFromFilmsAndCond(frameDivider.DividerConductance, framehIntConvCoeff, framehExtConvCoeff);
     314           12 :             const double dividerEdgeUValue = centerOfGlassUvalue * frameDivider.DivEdgeToCenterGlCondRatio; // not sure about this
     315           12 :             const double dividerProjectedDimension = frameDivider.DividerWidth;
     316           12 :             const double dividerWettedLength = dividerProjectedDimension + frameDivider.DividerProjectionIn;
     317           12 :             const double dividerAbsorptance = frameDivider.DividerSolAbsorp;
     318           12 :             const int numHorizDividers = frameDivider.HorDividers;
     319           12 :             const int numVertDividers = frameDivider.VertDividers;
     320              : 
     321              :             Tarcog::ISO15099::FrameData dividerData{
     322           12 :                 dividerUvalue, dividerEdgeUValue, dividerProjectedDimension, dividerWettedLength, dividerAbsorptance};
     323              : 
     324           12 :             const Real64 tVis = state.dataConstruction->Construct(constrNum).VisTransNorm;
     325           12 :             const Real64 tSol = state.dataConstruction->Construct(constrNum).SolTransNorm;
     326              : 
     327           12 :             if (vision == DataSurfaces::NfrcVisionType::Single) {
     328            8 :                 Tarcog::ISO15099::WindowSingleVision window(windowWidth, windowHeight, tVis, tSol, insulGlassUnit);
     329            8 :                 window.setFrameTop(frameData);
     330            8 :                 window.setFrameBottom(frameData);
     331            8 :                 window.setFrameLeft(frameData);
     332            8 :                 window.setFrameRight(frameData);
     333            8 :                 window.setDividers(dividerData, numHorizDividers, numVertDividers);
     334              : 
     335            8 :                 if (isSummer) {
     336            4 :                     vt = window.vt();
     337            4 :                     shgc = window.shgc();
     338              :                 } else {
     339            4 :                     uvalue = window.uValue();
     340              :                 }
     341           12 :             } else if (vision == EnergyPlus::DataSurfaces::NfrcVisionType::DualHorizontal) {
     342            2 :                 Tarcog::ISO15099::DualVisionHorizontal window(windowWidth, windowHeight, tVis, tSol, insulGlassUnit, tVis, tSol, insulGlassUnit);
     343            2 :                 window.setFrameLeft(frameData);
     344            2 :                 window.setFrameRight(frameData);
     345            2 :                 window.setFrameBottomLeft(frameData);
     346            2 :                 window.setFrameBottomRight(frameData);
     347            2 :                 window.setFrameTopLeft(frameData);
     348            2 :                 window.setFrameTopRight(frameData);
     349            2 :                 window.setFrameMeetingRail(frameData);
     350            2 :                 window.setDividers(dividerData, numHorizDividers, numVertDividers);
     351              : 
     352            2 :                 if (isSummer) {
     353            1 :                     vt = window.vt();
     354            1 :                     shgc = window.shgc();
     355              :                 } else {
     356            1 :                     uvalue = window.uValue();
     357              :                 }
     358            4 :             } else if (vision == EnergyPlus::DataSurfaces::NfrcVisionType::DualVertical) {
     359            2 :                 Tarcog::ISO15099::DualVisionVertical window(windowWidth, windowHeight, tVis, tSol, insulGlassUnit, tVis, tSol, insulGlassUnit);
     360            2 :                 window.setFrameTop(frameData);
     361            2 :                 window.setFrameBottom(frameData);
     362            2 :                 window.setFrameTopLeft(frameData);
     363            2 :                 window.setFrameTopRight(frameData);
     364            2 :                 window.setFrameBottomLeft(frameData);
     365            2 :                 window.setFrameBottomRight(frameData);
     366            2 :                 window.setFrameMeetingRail(frameData);
     367            2 :                 window.setDividers(dividerData, numHorizDividers, numVertDividers);
     368              : 
     369            2 :                 if (isSummer) {
     370            1 :                     vt = window.vt();
     371            1 :                     shgc = window.shgc();
     372              :                 } else {
     373            1 :                     uvalue = window.uValue();
     374              :                 }
     375            2 :             } 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           12 :         }
     391            6 :     }
     392              : 
     393              :     /////////////////////////////////////////////////////////////////////////////////////////
     394              :     //  CWCEHeatTransferFactory
     395              :     /////////////////////////////////////////////////////////////////////////////////////////
     396              : 
     397           12 :     CWCEHeatTransferFactory::CWCEHeatTransferFactory(EnergyPlusData &state, SurfaceData const &surface, int const t_SurfNum, int const t_ConstrNum)
     398           12 :         : m_Surface(surface), m_Window(state.dataSurface->SurfaceWindow(t_SurfNum)), m_ShadePosition(ShadePosition::NoShade), m_SurfNum(t_SurfNum),
     399           12 :           m_SolidLayerIndex(0), m_ConstructionNumber(t_ConstrNum), m_TotLay(getNumOfLayers(state)), m_InteriorBSDFShade(false), m_ExteriorShade(false)
     400              :     {
     401           24 :         if (!state.dataConstruction->Construct(m_ConstructionNumber).WindowTypeBSDF &&
     402           12 :             state.dataSurface->SurfWinShadingFlag.size() >= static_cast<size_t>(m_SurfNum)) {
     403            7 :             if (ANY_SHADE_SCREEN(state.dataSurface->SurfWinShadingFlag(m_SurfNum)) || ANY_BLIND(state.dataSurface->SurfWinShadingFlag(m_SurfNum))) {
     404            0 :                 m_ConstructionNumber = state.dataSurface->SurfWinActiveShadedConstruction(m_SurfNum);
     405            0 :                 m_TotLay = getNumOfLayers(state);
     406              :             }
     407              :         }
     408           12 :         const WinShadingType ShadeFlag = getShadeType(state, m_ConstructionNumber);
     409              : 
     410           12 :         if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
     411            0 :             m_ShadePosition = ShadePosition::Interior;
     412              :         }
     413              : 
     414           12 :         else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
     415            0 :             m_ShadePosition = ShadePosition::Exterior;
     416              :         }
     417              : 
     418           12 :         else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
     419            0 :             m_ShadePosition = ShadePosition::Between;
     420              :         }
     421           12 :     }
     422              : 
     423              :     /////////////////////////////////////////////////////////////////////////////////////////
     424            0 :     std::shared_ptr<Tarcog::ISO15099::CSingleSystem> CWCEHeatTransferFactory::getTarcogSystem(EnergyPlusData &state, Real64 const t_HextConvCoeff)
     425              :     {
     426            0 :         auto Indoor = getIndoor(state);                    // (AUTO_OK_SPTR)
     427            0 :         auto Outdoor = getOutdoor(state, t_HextConvCoeff); // (AUTO_OK_SPTR)
     428            0 :         auto aIGU = getIGU();                              // (AUTO_OK_OBJ)
     429              : 
     430              :         // pick-up all layers and put them in IGU (this includes gap layers as well)
     431            0 :         for (int i = 0; i < m_TotLay; ++i) {
     432            0 :             auto aLayer = getIGULayer(state, i + 1); // (AUTO_OK_SPTR)
     433            0 :             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            0 :             if (m_ShadePosition == ShadePosition::Interior && i == m_TotLay - 1) {
     437            0 :                 auto aAirLayer = getShadeToGlassLayer(state, i + 1); // (AUTO_OK_SPTR)
     438            0 :                 aIGU.addLayer(aAirLayer);
     439            0 :             }
     440            0 :             aIGU.addLayer(aLayer);
     441            0 :             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            0 :         }
     446              : 
     447            0 :         return std::make_shared<Tarcog::ISO15099::CSingleSystem>(aIGU, Indoor, Outdoor);
     448            0 :     }
     449              : 
     450           24 :     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           24 :         auto Indoor = getIndoorNfrc(useSummerConditions);   // (AUTO_OK_SPTR)
     454           24 :         auto Outdoor = getOutdoorNfrc(useSummerConditions); // (AUTO_OK_SPTR)
     455           24 :         auto aIGU = getIGU(width, height, tilt);            // (AUTO_OK_OBJ)
     456              : 
     457           24 :         m_SolidLayerIndex = 0;
     458              :         // pick-up all layers and put them in IGU (this includes gap layers as well)
     459           88 :         for (int i = 0; i < m_TotLay; ++i) {
     460           64 :             auto aLayer = getIGULayer(state, i + 1); // (AUTO_OK_SPTR)
     461           64 :             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           64 :             if (m_ShadePosition == ShadePosition::Interior && i == m_TotLay - 1) {
     465            0 :                 auto aAirLayer = getShadeToGlassLayer(state, i + 1); // (AUTO_OK_SPTR)
     466            0 :                 aIGU.addLayer(aAirLayer);
     467            0 :             }
     468           64 :             aIGU.addLayer(aLayer);
     469           64 :             if (m_ShadePosition == ShadePosition::Exterior && i == 0) {
     470            0 :                 auto aAirLayer = getShadeToGlassLayer(state, i + 1); // (AUTO_OK_SPTR)
     471            0 :                 aIGU.addLayer(aAirLayer);
     472            0 :             }
     473           64 :         }
     474              : 
     475           48 :         return std::make_shared<Tarcog::ISO15099::CSystem>(aIGU, Indoor, Outdoor);
     476           24 :     }
     477              : 
     478              :     /////////////////////////////////////////////////////////////////////////////////////////
     479           64 :     Material::MaterialBase *CWCEHeatTransferFactory::getLayerMaterial(EnergyPlusData &state, int const t_Index) const
     480              :     {
     481           64 :         int ConstrNum = m_ConstructionNumber;
     482              : 
     483              :         // BSDF window do not have special shading flag
     484          128 :         if (!state.dataConstruction->Construct(ConstrNum).WindowTypeBSDF &&
     485           64 :             state.dataSurface->SurfWinShadingFlag.size() >= static_cast<size_t>(m_SurfNum)) {
     486           64 :             if (ANY_SHADE_SCREEN(state.dataSurface->SurfWinShadingFlag(m_SurfNum)) || ANY_BLIND(state.dataSurface->SurfWinShadingFlag(m_SurfNum))) {
     487            0 :                 ConstrNum = state.dataSurface->SurfWinActiveShadedConstruction(m_SurfNum);
     488              :             }
     489              :         }
     490              : 
     491           64 :         auto &construction = state.dataConstruction->Construct(ConstrNum);
     492           64 :         const int LayPtr = construction.LayerPoint(t_Index);
     493           64 :         return state.dataMaterial->materials(LayPtr);
     494              :     }
     495              : 
     496              :     /////////////////////////////////////////////////////////////////////////////////////////
     497           64 :     std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> CWCEHeatTransferFactory::getIGULayer(EnergyPlusData &state, int const t_Index)
     498              :     {
     499           64 :         std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> aLayer = nullptr;
     500              : 
     501           64 :         auto *material = getLayerMaterial(state, t_Index);
     502              : 
     503           64 :         Material::Group matGroup = material->group;
     504              : 
     505           64 :         if ((matGroup == Material::Group::Glass) || (matGroup == Material::Group::GlassSimple) || (matGroup == Material::Group::Blind) ||
     506           20 :             (matGroup == Material::Group::Shade) || (matGroup == Material::Group::Screen) || (matGroup == Material::Group::ComplexShade)) {
     507           44 :             ++m_SolidLayerIndex;
     508           44 :             aLayer = getSolidLayer(state, material, m_SolidLayerIndex);
     509           20 :         } else if (matGroup == Material::Group::Gas || matGroup == Material::Group::GasMixture) {
     510           20 :             aLayer = getGapLayer(material);
     511            0 :         } else if (matGroup == Material::Group::ComplexWindowGap) {
     512            0 :             aLayer = getComplexGapLayer(state, material);
     513              :         }
     514              : 
     515           64 :         return aLayer;
     516            0 :     }
     517              : 
     518              :     /////////////////////////////////////////////////////////////////////////////////////////
     519           12 :     int CWCEHeatTransferFactory::getNumOfLayers(EnergyPlusData &state) const
     520              :     {
     521           12 :         return state.dataConstruction->Construct(m_ConstructionNumber).TotLayers;
     522              :     }
     523              : 
     524              :     /////////////////////////////////////////////////////////////////////////////////////////
     525              :     std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer>
     526           44 :     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           44 :         Real64 emissFront = 0.0;
     537           44 :         Real64 emissBack = 0.0;
     538           44 :         Real64 transThermalFront = 0.0;
     539           44 :         Real64 transThermalBack = 0.0;
     540           44 :         Real64 thickness = 0.0;
     541           44 :         Real64 conductivity = 0.0;
     542           44 :         Real64 createOpenness = false;
     543           44 :         Real64 Atop = 0.0;
     544           44 :         Real64 Abot = 0.0;
     545           44 :         Real64 Aleft = 0.0;
     546           44 :         Real64 Aright = 0.0;
     547           44 :         Real64 Afront = 0.0;
     548              : 
     549           44 :         if (mat->group == Material::Group::Glass || mat->group == Material::Group::GlassSimple) {
     550           44 :             auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
     551           44 :             assert(matGlass != nullptr);
     552              : 
     553           44 :             emissFront = matGlass->AbsorpThermalFront;
     554           44 :             emissBack = matGlass->AbsorpThermalBack;
     555           44 :             transThermalFront = matGlass->TransThermal;
     556           44 :             transThermalBack = matGlass->TransThermal;
     557           44 :             thickness = matGlass->Thickness;
     558           44 :             conductivity = matGlass->Conductivity;
     559              : 
     560           44 :         } else if (mat->group == Material::Group::Blind) {
     561              :             // auto const &surfShade = state.dataSurface->surfShades(m_SurfNum);
     562            0 :             auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(mat);
     563            0 :             assert(matBlind != nullptr);
     564            0 :             thickness = matBlind->SlatThickness;
     565            0 :             conductivity = matBlind->SlatConductivity;
     566            0 :             Atop = matBlind->topOpeningMult;
     567            0 :             Abot = matBlind->bottomOpeningMult;
     568            0 :             Aleft = matBlind->leftOpeningMult;
     569            0 :             Aright = matBlind->rightOpeningMult;
     570              : 
     571            0 :             Real64 slatAng = matBlind->SlatAngle * Constant::DegToRad;
     572            0 :             Real64 PermA = std::sin(slatAng) - matBlind->SlatThickness / matBlind->SlatSeparation;
     573              :             Real64 PermB =
     574            0 :                 1.0 - (std::abs(matBlind->SlatWidth * std::cos(slatAng)) + matBlind->SlatThickness * std::sin(slatAng)) / matBlind->SlatSeparation;
     575            0 :             Afront = min(1.0, max(0.0, PermA, PermB));
     576              : 
     577              :             int iSlatLo, iSlatHi;
     578              :             Real64 interpFac;
     579              : 
     580            0 :             Material::GetSlatIndicesInterpFac(slatAng, iSlatLo, iSlatHi, interpFac);
     581              : 
     582            0 :             emissFront = Interp(matBlind->TARs[iSlatLo].IR.Ft.Emi, matBlind->TARs[iSlatHi].IR.Ft.Emi, interpFac);
     583            0 :             emissBack = Interp(matBlind->TARs[iSlatLo].IR.Bk.Emi, matBlind->TARs[iSlatHi].IR.Bk.Emi, interpFac);
     584            0 :             transThermalFront = Interp(matBlind->TARs[iSlatLo].IR.Ft.Tra, matBlind->TARs[iSlatHi].IR.Ft.Tra, interpFac);
     585            0 :             transThermalBack = Interp(matBlind->TARs[iSlatLo].IR.Bk.Tra, matBlind->TARs[iSlatHi].IR.Bk.Tra, interpFac);
     586              : 
     587            0 :             if (t_Index == 1) {
     588            0 :                 m_ExteriorShade = true;
     589              :             }
     590              : 
     591            0 :         } else if (mat->group == Material::Group::Shade) {
     592            0 :             auto const *matShade = dynamic_cast<Material::MaterialShade const *>(mat);
     593            0 :             assert(matShade != nullptr);
     594              : 
     595            0 :             emissFront = matShade->AbsorpThermal;
     596            0 :             emissBack = matShade->AbsorpThermal;
     597            0 :             transThermalFront = matShade->TransThermal;
     598            0 :             transThermalBack = matShade->TransThermal;
     599            0 :             thickness = matShade->Thickness;
     600            0 :             conductivity = matShade->Conductivity;
     601              : 
     602            0 :             Atop = matShade->topOpeningMult;
     603            0 :             Abot = matShade->bottomOpeningMult;
     604            0 :             Aleft = matShade->leftOpeningMult;
     605            0 :             Aright = matShade->rightOpeningMult;
     606            0 :             Afront = matShade->airFlowPermeability;
     607            0 :             if (t_Index == 1) {
     608            0 :                 m_ExteriorShade = true;
     609              :             }
     610              : 
     611            0 :         } 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            0 :         } else if (mat->group == Material::Group::ComplexShade) {
     634            0 :             auto const *matShade = dynamic_cast<Material::MaterialComplexShade const *>(mat);
     635            0 :             assert(matShade != nullptr);
     636              : 
     637            0 :             thickness = matShade->Thickness;
     638            0 :             conductivity = matShade->Conductivity;
     639            0 :             emissFront = matShade->FrontEmissivity;
     640            0 :             emissBack = matShade->BackEmissivity;
     641            0 :             transThermalFront = matShade->TransThermal;
     642            0 :             transThermalBack = matShade->TransThermal;
     643            0 :             Afront = matShade->frontOpeningMult;
     644            0 :             Atop = matShade->topOpeningMult;
     645            0 :             Abot = matShade->bottomOpeningMult;
     646            0 :             Aleft = matShade->leftOpeningMult;
     647            0 :             Aright = matShade->rightOpeningMult;
     648            0 :             createOpenness = true;
     649            0 :             m_InteriorBSDFShade = ((2 * t_Index - 1) == m_TotLay);
     650              :         }
     651              : 
     652           44 :         std::shared_ptr<Tarcog::ISO15099::ISurface> frontSurface = std::make_shared<Tarcog::ISO15099::CSurface>(emissFront, transThermalFront);
     653           44 :         std::shared_ptr<Tarcog::ISO15099::ISurface> backSurface = std::make_shared<Tarcog::ISO15099::CSurface>(emissBack, transThermalBack);
     654              :         auto aSolidLayer = // (AUTO_OK_SPTR)
     655           44 :             std::make_shared<Tarcog::ISO15099::CIGUSolidLayer>(thickness, conductivity, frontSurface, backSurface);
     656           44 :         if (createOpenness) {
     657            0 :             auto aOpenings = std::make_shared<Tarcog::ISO15099::CShadeOpenings>(Atop, Abot, Aleft, Aright, Afront, Afront); // (AUTO_OK_SPTR)
     658            0 :             aSolidLayer = std::make_shared<Tarcog::ISO15099::CIGUShadeLayer>(aSolidLayer, aOpenings);
     659            0 :         }
     660              :         static constexpr double standardizedRadiationIntensity = 783.0;
     661           44 :         if (state.dataWindowManager->inExtWindowModel->isExternalLibraryModel()) {
     662            0 :             auto &surface(state.dataSurface->Surface(m_SurfNum));
     663            0 :             const int ConstrNum = getActiveConstructionNumber(state, surface, m_SurfNum);
     664              :             std::shared_ptr<MultiLayerOptics::CMultiLayerScattered> aLayer =
     665            0 :                 CWindowConstructionsSimplified::instance(state).getEquivalentLayer(state, FenestrationCommon::WavelengthRange::Solar, ConstrNum);
     666              : 
     667              :             // Report is done for normal incidence
     668            0 :             constexpr Real64 Theta = 0.0;
     669            0 :             constexpr Real64 Phi = 0.0;
     670              :             const Real64 absCoeff =
     671            0 :                 aLayer->getAbsorptanceLayer(t_Index, FenestrationCommon::Side::Front, FenestrationCommon::ScatteringSimple::Diffuse, Theta, Phi);
     672            0 :             aSolidLayer->setSolarAbsorptance(absCoeff, standardizedRadiationIntensity);
     673            0 :         } else {
     674           44 :             const Real64 absCoeff{state.dataConstruction->Construct(state.dataSurface->Surface(m_SurfNum).Construction).AbsDiff(t_Index)};
     675           44 :             aSolidLayer->setSolarAbsorptance(absCoeff, standardizedRadiationIntensity);
     676              :         }
     677           88 :         return aSolidLayer;
     678           44 :     }
     679              : 
     680              :     /////////////////////////////////////////////////////////////////////////////////////////
     681           20 :     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           20 :         Real64 constexpr pres = 1e5; // Old code uses this constant pressure
     692           20 :         Real64 thickness = material->Thickness;
     693           20 :         auto aGas = getGas(material); // (AUTO_OK_OBJ)
     694           20 :         std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> aLayer = std::make_shared<Tarcog::ISO15099::CIGUGapLayer>(thickness, pres, aGas);
     695           40 :         return aLayer;
     696           20 :     }
     697              : 
     698              :     /////////////////////////////////////////////////////////////////////////////////////////
     699            0 :     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            0 :         Real64 constexpr pres = 1e5; // Old code uses this constant pressure
     710            0 :         auto aGas = getAir();        // (AUTO_OK_OBJ)
     711            0 :         Real64 thickness = 0.0;
     712              : 
     713            0 :         auto &s_mat = state.dataMaterial;
     714            0 :         auto &surfWin = state.dataSurface->SurfaceWindow(m_SurfNum);
     715            0 :         auto const &surfShade = state.dataSurface->surfShades(m_SurfNum);
     716              : 
     717            0 :         const WinShadingType ShadeFlag = getShadeType(state, m_ConstructionNumber);
     718              : 
     719            0 :         if (ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind) {
     720            0 :             thickness = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(surfShade.blind.matNum))->toGlassDist;
     721            0 :         } else if (ShadeFlag == WinShadingType::ExtScreen) {
     722            0 :             thickness = dynamic_cast<Material::MaterialScreen const *>(s_mat->materials(surfWin.screenNum))->toGlassDist;
     723            0 :         } else if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) {
     724            0 :             const auto *material = dynamic_cast<Material::MaterialShade *>(getLayerMaterial(state, t_Index));
     725            0 :             assert(material != nullptr);
     726            0 :             thickness = material->toGlassDist;
     727              :         }
     728            0 :         std::shared_ptr<Tarcog::ISO15099::CBaseIGULayer> aLayer = std::make_shared<Tarcog::ISO15099::CIGUGapLayer>(thickness, pres, aGas);
     729            0 :         return aLayer;
     730            0 :     }
     731              : 
     732              :     /////////////////////////////////////////////////////////////////////////////////////////
     733            0 :     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            0 :         Real64 constexpr pres = 1e5; // Old code uses this constant pressure
     745            0 :         auto const *mat = dynamic_cast<Material::MaterialComplexWindowGap const *>(materialBase);
     746            0 :         assert(mat != nullptr);
     747            0 :         Real64 thickness = mat->Thickness;
     748            0 :         auto aGas = getGas(mat); // (AUTO_OK_OBJ)
     749            0 :         return std::make_shared<Tarcog::ISO15099::CIGUGapLayer>(thickness, pres, aGas);
     750            0 :     }
     751              : 
     752              :     /////////////////////////////////////////////////////////////////////////////////////////
     753           20 :     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           20 :         auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(materialBase);
     765           20 :         assert(matGas != nullptr);
     766           20 :         const int numGases = matGas->numGases;
     767           20 :         double constexpr vacuumCoeff = 1.4; // Load vacuum coefficient once it is implemented (Simon).
     768           20 :         std::string const &gasName = matGas->Name;
     769           20 :         Gases::CGas aGas;
     770           40 :         for (int i = 0; i < numGases; ++i) {
     771           20 :             auto const &gas = matGas->gases[i];
     772           20 :             Real64 wght = gas.wght;
     773           20 :             Real64 fract = matGas->gasFracts[i];
     774           20 :             Gases::CIntCoeff aCon(gas.con.c0, gas.con.c1, gas.con.c2);
     775           20 :             Gases::CIntCoeff aCp(gas.cp.c0, gas.cp.c1, gas.cp.c2);
     776           20 :             Gases::CIntCoeff aVis(gas.vis.c0, gas.vis.c1, gas.vis.c2);
     777           20 :             Gases::CGasData aData(gasName, wght, vacuumCoeff, aCp, aCon, aVis);
     778           20 :             aGas.addGasItem(fract, aData);
     779           20 :         }
     780           20 :         return aGas;
     781            0 :     }
     782              : 
     783              :     /////////////////////////////////////////////////////////////////////////////////////////
     784            0 :     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            0 :         return {};
     796              :     }
     797              : 
     798              :     /////////////////////////////////////////////////////////////////////////////////////////
     799            0 :     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            0 :         Real64 tin = m_Surface.getInsideAirTemperature(state, m_SurfNum) + Constant::Kelvin;
     810            0 :         Real64 hcin = state.dataHeatBalSurf->SurfHConvInt(m_SurfNum);
     811              : 
     812            0 :         Real64 IR = state.dataSurface->SurfWinIRfromParentZone(m_SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(m_SurfNum);
     813              : 
     814              :         std::shared_ptr<Tarcog::ISO15099::CEnvironment> Indoor =
     815            0 :             std::make_shared<Tarcog::ISO15099::CIndoorEnvironment>(tin, state.dataEnvrn->OutBaroPress);
     816            0 :         Indoor->setHCoeffModel(Tarcog::ISO15099::BoundaryConditionsCoeffModel::CalculateH, hcin);
     817            0 :         Indoor->setEnvironmentIR(IR);
     818            0 :         return Indoor;
     819            0 :     }
     820              : 
     821              :     /////////////////////////////////////////////////////////////////////////////////////////
     822            0 :     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            0 :         double tout = m_Surface.getOutsideAirTemperature(state, m_SurfNum) + Constant::Kelvin;
     833            0 :         double IR = m_Surface.getOutsideIR(state, m_SurfNum);
     834              :         // double dirSolRad = SurfQRadSWOutIncident( t_SurfNum ) + QS( Surface( t_SurfNum ).Zone );
     835            0 :         double swRadiation = m_Surface.getSWIncident(state, m_SurfNum);
     836            0 :         double tSky = state.dataEnvrn->SkyTempKelvin;
     837            0 :         double airSpeed = 0.0;
     838            0 :         if (m_Surface.ExtWind) {
     839            0 :             airSpeed = state.dataSurface->SurfOutWindSpeed(m_SurfNum);
     840              :         }
     841            0 :         double fclr = 1 - state.dataEnvrn->CloudFraction;
     842            0 :         Tarcog::ISO15099::AirHorizontalDirection airDirection = Tarcog::ISO15099::AirHorizontalDirection::Windward;
     843            0 :         std::shared_ptr<Tarcog::ISO15099::CEnvironment> Outdoor = std::make_shared<Tarcog::ISO15099::COutdoorEnvironment>(
     844            0 :             tout, airSpeed, swRadiation, airDirection, tSky, Tarcog::ISO15099::SkyModel::AllSpecified, state.dataEnvrn->OutBaroPress, fclr);
     845            0 :         Outdoor->setHCoeffModel(Tarcog::ISO15099::BoundaryConditionsCoeffModel::HcPrescribed, t_Hext);
     846            0 :         Outdoor->setEnvironmentIR(IR);
     847            0 :         return Outdoor;
     848            0 :     }
     849              : 
     850              :     /////////////////////////////////////////////////////////////////////////////////////////
     851            0 :     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            0 :         return {m_Surface.Width, m_Surface.Height, m_Surface.Tilt};
     864              :     }
     865              : 
     866           25 :     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           25 :         return {width, height, tilt};
     879              :     }
     880              : 
     881              :     int
     882            2 :     CWCEHeatTransferFactory::getActiveConstructionNumber(EnergyPlusData &state, EnergyPlus::DataSurfaces::SurfaceData const &surface, int t_SurfNum)
     883              :     {
     884            2 :         int result = surface.Construction;
     885            2 :         const WinShadingType ShadeFlag = state.dataSurface->SurfWinShadingFlag(t_SurfNum);
     886              : 
     887            2 :         if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
     888            1 :             result = state.dataSurface->SurfWinActiveShadedConstruction(t_SurfNum);
     889              :         }
     890              : 
     891            2 :         return result;
     892              :     }
     893              : 
     894              :     /////////////////////////////////////////////////////////////////////////////////////////
     895            0 :     bool CWCEHeatTransferFactory::isInteriorShade() const
     896              :     {
     897            0 :         return m_InteriorBSDFShade;
     898              :     }
     899              : 
     900           26 :     std::shared_ptr<Tarcog::ISO15099::CEnvironment> CWCEHeatTransferFactory::getOutdoorNfrc(bool const useSummerConditions)
     901              :     {
     902              :         // NFRC 100 Section 4.3.1
     903           26 :         Real64 airTemperature = -18.0 + Constant::Kelvin; // Kelvins
     904           26 :         Real64 airSpeed = 5.5;                            // meters per second
     905           26 :         Real64 tSky = -18.0 + Constant::Kelvin;           // Kelvins
     906           26 :         Real64 solarRadiation = 0.;                       // W/m2
     907           26 :         if (useSummerConditions) {
     908              :             // NFRC 200 Section 4.3.1
     909            7 :             airTemperature = 32.0 + Constant::Kelvin;
     910            7 :             airSpeed = 2.75;
     911            7 :             tSky = 32.0 + Constant::Kelvin;
     912            7 :             solarRadiation = 783.;
     913              :         }
     914              :         auto Outdoor = // (AUTO_OK_SPTR)
     915           26 :             Tarcog::ISO15099::Environments::outdoor(airTemperature, airSpeed, solarRadiation, tSky, Tarcog::ISO15099::SkyModel::AllSpecified);
     916           26 :         Outdoor->setHCoeffModel(Tarcog::ISO15099::BoundaryConditionsCoeffModel::CalculateH);
     917           52 :         return Outdoor;
     918           26 :     }
     919              : 
     920           26 :     std::shared_ptr<Tarcog::ISO15099::CEnvironment> CWCEHeatTransferFactory::getIndoorNfrc(bool const useSummerConditions)
     921              :     {
     922              :         // NFRC 100 Section 4.3.1
     923           26 :         Real64 roomTemperature = 21. + Constant::Kelvin;
     924           26 :         if (useSummerConditions) {
     925              :             // NFRC 200 Section 4.3.1
     926            7 :             roomTemperature = 24. + Constant::Kelvin;
     927              :         }
     928           26 :         return Tarcog::ISO15099::Environments::indoor(roomTemperature);
     929              :     }
     930              : 
     931           19 :     WinShadingType CWCEHeatTransferFactory::getShadeType(EnergyPlusData &state, int ConstrNum)
     932              :     {
     933           19 :         auto &s_mat = state.dataMaterial;
     934           19 :         WinShadingType ShadeFlag = WinShadingType::NoShade;
     935              : 
     936           19 :         const int TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
     937           19 :         const int TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
     938           19 :         const int matOutNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(1);
     939           19 :         const int matInNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLay);
     940              : 
     941           19 :         auto const *matOut = s_mat->materials(matOutNum);
     942           19 :         auto const *matIn = s_mat->materials(matInNum);
     943              : 
     944           19 :         if (matOut->group == Material::Group::Shade) { // Exterior shade present
     945            1 :             ShadeFlag = WinShadingType::ExtShade;
     946           18 :         } else if (matOut->group == Material::Group::Screen) { // Exterior screen present
     947            0 :             ShadeFlag = WinShadingType::ExtScreen;
     948           18 :         } else if (matOut->group == Material::Group::Blind) { // Exterior blind present
     949            1 :             ShadeFlag = WinShadingType::ExtBlind;
     950           17 :         } else if (matIn->group == Material::Group::Shade) { // Interior shade present
     951            1 :             ShadeFlag = WinShadingType::IntShade;
     952           16 :         } else if (matIn->group == Material::Group::Blind) { // Interior blind present
     953            1 :             ShadeFlag = WinShadingType::IntBlind;
     954           15 :         } else if (TotGlassLay == 2) {
     955            9 :             auto const *mat3 = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(3));
     956            9 :             if (mat3->group == Material::Group::Shade) {
     957            1 :                 ShadeFlag = WinShadingType::BGShade;
     958            8 :             } else if (mat3->group == Material::Group::Blind) {
     959            1 :                 ShadeFlag = WinShadingType::BGBlind;
     960              :             }
     961            6 :         } else if (TotGlassLay == 3) {
     962            0 :             auto const *mat5 = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(5));
     963            0 :             if (mat5->group == Material::Group::Shade) {
     964            0 :                 ShadeFlag = WinShadingType::BGShade;
     965            0 :             } else if (mat5->group == Material::Group::Blind) {
     966            0 :                 ShadeFlag = WinShadingType::BGBlind;
     967              :             }
     968              :         }
     969              : 
     970           19 :         return ShadeFlag;
     971              :     }
     972              : 
     973           29 :     double CWCEHeatTransferFactory::overallUfactorFromFilmsAndCond(double conductance, double insideFilm, double outsideFilm)
     974              :     {
     975           29 :         double rOverall(0.);
     976           29 :         double uFactor(0.);
     977           29 :         if (insideFilm != 0 && outsideFilm != 0. && conductance != 0.) {
     978           27 :             rOverall = 1 / insideFilm + 1 / conductance + 1 / outsideFilm;
     979              :         }
     980           29 :         if (rOverall != 0.) {
     981           27 :             uFactor = 1 / rOverall;
     982              :         }
     983           29 :         return uFactor;
     984              :     }
     985              : 
     986              : } // namespace Window
     987              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1