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
|