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

Generated by: LCOV version 2.0-1