Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <algorithm>
50 : #include <cassert>
51 : #include <cmath>
52 : #include <memory>
53 : #include <string>
54 :
55 : // ObjexxFCL Headers
56 : #include <ObjexxFCL/Array.functions.hh>
57 :
58 : // EnergyPlus Headers
59 : #include <EnergyPlus/Construction.hh>
60 : #include <EnergyPlus/ConvectionCoefficients.hh>
61 : #include <EnergyPlus/CurveManager.hh>
62 : #include <EnergyPlus/Data/EnergyPlusData.hh>
63 : #include <EnergyPlus/DataBSDFWindow.hh>
64 : #include <EnergyPlus/DataEnvironment.hh>
65 : #include <EnergyPlus/DataHeatBalSurface.hh>
66 : #include <EnergyPlus/DataHeatBalance.hh>
67 : #include <EnergyPlus/DataIPShortCuts.hh>
68 : #include <EnergyPlus/DataWindowEquivalentLayer.hh>
69 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
70 : #include <EnergyPlus/Material.hh>
71 : #include <EnergyPlus/Psychrometrics.hh>
72 : #include <EnergyPlus/UtilityRoutines.hh>
73 : #include <EnergyPlus/WindowComplexManager.hh>
74 : #include <EnergyPlus/WindowEquivalentLayer.hh>
75 : #include <EnergyPlus/WindowManager.hh>
76 : #include <EnergyPlus/WindowManagerExteriorOptical.hh>
77 : #include <EnergyPlus/WindowManagerExteriorThermal.hh>
78 : #include <EnergyPlus/WindowModel.hh>
79 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
80 :
81 : namespace EnergyPlus {
82 :
83 : namespace Window {
84 :
85 : // MODULE INFORMATION
86 : // AUTHOR Fred Winkelmann
87 : // DATE WRITTEN September 1999
88 : // MODIFIED August 2001 (FW): add window shade thermal calculation;
89 : // add window blind optical and thermal model.
90 : // February 2003 (FW/LKL): Name changed to WindowManager
91 : // RE-ENGINEERED na
92 :
93 : // PURPOSE OF THIS MODULE:
94 : // Manages the window optical and thermal calculations derived
95 : // from WINDOW 4 and WINDOW 5.
96 :
97 : // METHODOLOGY EMPLOYED:
98 :
99 : // REFERENCES:
100 : // WINDOW 4:
101 : // D.Arasteh, M.Reilly and M.Rubin. A versative procedure for
102 : // calculating heat transfer through windows. ASHRAE Trans. 1989, Vol. 95, Pt. 2.
103 :
104 : // E.Finlayson, D.Arasteh, C.Huizenga, M.Rubin, and M.Reilly. WINDOW 4.0:
105 : // Documentation of calculation procedures. LBL-33943. July 1993.
106 :
107 : // WINDOW 5:
108 : // ASHRAE Standard 142P (draft 1/13/98): Standard method for determining and expressing
109 : // the heat transfer and total optical properties of fenestration products.
110 :
111 : // Shade and blind thermal model:
112 : // ISO/DIS 15099, Thermal Performance of Windows, Doors and Shading Devices,
113 : // Detailed Calculations, 1/12/00.
114 :
115 : // Blind optical model:
116 : // H. Simmler, U. Fischer and Frederick Winkelmann, Solar-Thermal Window Blind Model
117 : // for DOE-2, Lawrence Berkeley National Laboratory, Jan. 1996.
118 :
119 : // Using/Aliasing
120 : using namespace DataEnvironment;
121 : using namespace DataHeatBalance;
122 : using namespace DataSurfaces;
123 :
124 : // SUBROUTINE SPECIFICATIONS FOR MODULE WindowManager:
125 : // Optical Calculation Routines
126 : // Heat Balance Routines
127 :
128 111 : void InitWindowOpticalCalculations(EnergyPlusData &state)
129 : {
130 : // SUBROUTINE INFORMATION:
131 : // AUTHOR Simon Vidanovic
132 : // DATE WRITTEN September 2016
133 : // MODIFIED na
134 : // RE-ENGINEERED na
135 :
136 : // PURPOSE OF THIS SUBROUTINE:
137 : // Manages if optical calculation will be performed with internal or external routines
138 111 : auto &s_surf = state.dataSurface;
139 :
140 : // check and read custom solar and/or visible spectrum data if any
141 111 : CheckAndReadCustomSprectrumData(state);
142 :
143 : // allocate surface level adj ratio data member
144 111 : state.dataHeatBalSurf->SurfWinCoeffAdjRatio.dimension(s_surf->TotSurfaces, 1.0);
145 :
146 111 : if (state.dataWindowManager->inExtWindowModel->isExternalLibraryModel()) {
147 3 : InitWCE_SimplifiedOpticalData(state);
148 : } else {
149 108 : InitGlassOpticalCalculations(state);
150 : }
151 111 : }
152 :
153 110 : void InitGlassOpticalCalculations(EnergyPlusData &state)
154 : {
155 :
156 : // SUBROUTINE INFORMATION:
157 : // AUTHOR F. Winkelmann
158 : // DATE WRITTEN August 1999
159 : // MODIFIED May 2001 (FW): add window blinds
160 : // Jan 2002 (FW): add blinds with variable slat angle
161 : // Jan 2003 (FW): add between-glass shade/blind
162 : // May 2006 (RR): add exterior window screen
163 : // Aug 2010 (TH): allow spectral data for between-glass shade/blind
164 : // Aug 2013 (TH): allow user defined solar and visible spectrum data
165 : // RE-ENGINEERED na
166 :
167 : // PURPOSE OF THIS SUBROUTINE:
168 : // Manages the calculation of the solar and visible properties of a multi-layer glazing
169 : // system from the properties of the individual glazing and shading layers
170 :
171 : // Using/Aliasing
172 : using namespace Vectors;
173 :
174 : int TotLay; // Total solid and gas layers in a window construction
175 : int ConstrNumSh; // Shaded construction number
176 : int ShadeLayNum; // Layer number for shade or blind, if present
177 : int ShadeLayPtr; // Material number for shade or blind
178 : bool lquasi; // True if one or more glass layers have no spectral data
179 : bool AllGlassIsSpectralAverage; // True if all glazing in a construction is spectral average
180 : bool IntShade; // True if construction has an interior,exterior or between-glass shade
181 : bool ExtShade;
182 : bool BGShade;
183 : bool IntBlind; // True if construction has an interior,exterior or between-glass blind
184 : bool ExtBlind;
185 : bool BGBlind;
186 : bool ExtScreen; // True if construction has an exterior screen
187 : bool ScreenOn; // True if construction has an exterior screen
188 : bool BlindOn; // True if IntBlind, ExtBlind or BGBlind is true
189 : bool ShadeOn; // True if IntShade, ExtShade or BGShade is true
190 : int BlNum; // Blind number
191 :
192 110 : auto &wm = state.dataWindowManager;
193 110 : Array1D<Real64> sabsPhi(nume); // Glazing system absorptance for a glass layer
194 : // and angle of incidence, for each wavelength
195 : // glass layer for an angle of incidence, for each wavelength
196 : // Glazing system layer solar absorptance for each glass layer
197 110 : Array1D<Real64> solabsDiff(maxGlassLayers);
198 : // Glazing system solar absorptance for a layer at each incidence angle
199 : std::array<Real64, numPhis> solabsPhiLay;
200 : // Glazing system solar transmittance from fit at each incidence angle
201 : std::array<Real64, numPhis> tsolPhiFit;
202 : // Glazing system visible transmittance from fit at each incidence angle
203 : std::array<Real64, numPhis> tvisPhiFit;
204 : // Isolated glass solar transmittance for each incidence angle
205 110 : Array1D<std::array<Real64, numPhis>> tBareSolPhi(maxGlassLayers);
206 : Real64 t1; // = tBareSolPhi(,1)(,2)
207 : Real64 t2;
208 : // Isolated glass visible transmittance for each incidence angle
209 110 : Array1D<std::array<Real64, numPhis>> tBareVisPhi(maxGlassLayers);
210 : Real64 t1v; // = tBareVisPhi(,1)(,2)
211 : Real64 t2v;
212 : // Isolated glass front solar reflectance for each incidence angle
213 110 : Array1D<std::array<Real64, numPhis>> rfBareSolPhi(maxGlassLayers);
214 : // Isolated glass front visible reflectance for each incidence angle
215 110 : Array1D<std::array<Real64, numPhis>> rfBareVisPhi(maxGlassLayers);
216 : // Isolated glass back solar reflectance for each incidence angle
217 110 : Array1D<std::array<Real64, numPhis>> rbBareSolPhi(maxGlassLayers);
218 : // Isolated glass back visible reflectance for each incidence angle
219 110 : Array1D<std::array<Real64, numPhis>> rbBareVisPhi(maxGlassLayers);
220 : // Isolated glass front solar absorptance for each incidence angle
221 110 : Array1D<std::array<Real64, numPhis>> afBareSolPhi(maxGlassLayers);
222 : Real64 af1; // = afBareSolPhi(,1)(,2)
223 : Real64 af2;
224 : Real64 rbmf2; // Isolated glass #2 front beam reflectance
225 : // Isolated glass back solar absorptance for each incidence angle
226 110 : Array1D<std::array<Real64, numPhis>> abBareSolPhi(maxGlassLayers);
227 : // Glazing system solar absorptance for each angle of incidence
228 110 : Array1D<std::array<Real64, numPhis>> solabsPhi(maxGlassLayers);
229 : // Glazing system back solar absorptance for each angle of incidence
230 110 : Array1D<std::array<Real64, numPhis>> solabsBackPhi(maxGlassLayers);
231 : // Glazing system interior shade solar absorptance for each angle of incidence
232 : std::array<Real64, numPhis> solabsShadePhi;
233 :
234 : // These need to stay as Array1D for a little longer because changing them spreads into many source files
235 : std::array<Real64, numPhis> tsolPhi; // Glazing system solar transmittance for each angle of incidence
236 : std::array<Real64, numPhis> rfsolPhi; // Glazing system solar front reflectance for each angle of incidence
237 : std::array<Real64, numPhis> rbsolPhi; // Glazing system solar back reflectance for each angle of incidence
238 : std::array<Real64, numPhis> tvisPhi; // Glazing system visible transmittance for each angle of incidence
239 : std::array<Real64, numPhis> rfvisPhi; // Glazing system visible front reflectance for each angle of incidence
240 : std::array<Real64, numPhis> rbvisPhi; // Glazing system visible back reflectance for each angle of incidence
241 :
242 : Real64 ab1; // = abBareSolPhi(,1)(,2)
243 : Real64 ab2;
244 : Real64 td1; // Isolated glass diffuse solar transmittance
245 : Real64 td2;
246 : Real64 td3;
247 : Real64 td1v; // Isolated glass diffuse visible transmittance
248 : Real64 td2v;
249 : Real64 td3v;
250 : Real64 rf1; // Isolated glass diffuse solar front reflectance
251 : Real64 rf2;
252 : Real64 rf3;
253 : Real64 rf1v; // Isolated glass diffuse visible front reflectance
254 : Real64 rf2v;
255 : Real64 rf3v;
256 : Real64 rb1; // Isolated glass diffuse solar back reflectance
257 : Real64 rb2;
258 : Real64 rb3;
259 : Real64 rb1v; // Isolated glass diffuse visible back reflectance
260 : Real64 rb2v;
261 : Real64 rb3v;
262 : Real64 afd1; // Isolated glass diffuse solar front absorptance
263 : Real64 afd2;
264 : Real64 afd3;
265 : Real64 abd1; // Isolated glass diffuse solar back absorptance
266 : Real64 abd2;
267 : Real64 abd3;
268 : Real64 TauShIR; // IR transmittance of isolated shade
269 : Real64 EpsShIR; // IR absorptance of isolated shade
270 : Real64 RhoShIR; // IR reflectance of isolated shade
271 : Real64 EpsGlIR; // IR absorptance of front or back of isolated glass
272 : Real64 RhoGlIR; // IR reflectance of inside face of inside glass
273 : int NGlass; // Number of glass layers in a construction
274 : int LayPtr; // Material number corresponding to LayNum
275 : Real64 tsolDiff; // Glazing system diffuse solar transmittance
276 : Real64 tvisDiff; // Glazing system diffuse visible transmittance
277 : int IGlassBack; // Glass layer number counted from back of window
278 : Real64 ShadeAbs; // Solar absorptance of isolated shade
279 : Real64 ash; // = ShadeAbs
280 : Real64 afsh; // Diffuse solar front absorptance of isolated blind
281 : Real64 afshGnd; // Ground and sky diffuse solar front absorptance of isolated blind
282 : Real64 afshSky;
283 : Real64 absh; // Diffuse solar back absorptance of isolated blind
284 : Real64 ShadeTrans; // Solar transmittance of isolated shade/blind
285 : Real64 ShadeTransGnd; // Diffuse-diffuse transmittance of isolated vertical blind with
286 : // horizontal slats for isotropic ground solar
287 : Real64 ShadeTransSky; // Diffuse-diffuse transmittance of isolated vertical blind with
288 : // horizontal slats for isotropic sky solar
289 : Real64 tsh; // = ShadeTrans
290 : Real64 tshGnd; // = ShadeTransGnd,ShadeTransSky
291 : Real64 tshSky;
292 : Real64 tsh2; // = tsh**2
293 : Real64 ShadeRefl; // Solar reflectance of isolated shade
294 : Real64 ShadeReflGnd; // Front blind reflectance for ground diffuse solar
295 : Real64 ShadeReflSky; // Front blind reflectance for sky diffuse solar
296 : Real64 rsh; // = ShadeRefl
297 : Real64 rfsh; // Diffuse solar front reflectance of isolated blind
298 : Real64 rfshGnd; // Ground and sky diffuse solar front reflectance of isolated blind
299 : Real64 rfshSky;
300 : Real64 rbsh; // Diffuse solar back reflectance of isolated blind
301 : Real64 ShadeReflFac; // Shade/blind solar reflection factor
302 : Real64 ShadeTransVis; // Visible transmittance of isolated shade/blind
303 : Real64 tshv; // = ShadeTransVis
304 : Real64 tshv2; // = tshv**2
305 : Real64 ShadeReflVis; // Visible reflectance of isolated shade
306 : Real64 rshv; // = ShadeReflVis
307 : Real64 rfshv; // Diffuse visible front reflectance of isolated blind
308 : Real64 rbshv; // Diffuse visible back reflectance of isolated blind
309 : Real64 ShadeReflFacVis; // Shade/blind visible reflection factor
310 110 : int SpecDataNum = 0; // Spectral data set number
311 : int numptDAT; // Number of wavelengths in a spectral data set
312 : bool StormWinConst; // True if a construction with a storm window
313 : bool Triangle; // True if window is triangular
314 : bool Rectangle; // True if window is rectangular
315 110 : Vector3<Real64> W1; // Window vertices (m)
316 110 : Vector3<Real64> W2;
317 110 : Vector3<Real64> W3;
318 110 : Vector3<Real64> W21; // W1-W2, W3-W2, resp. (m)
319 110 : Vector3<Real64> W23;
320 :
321 : // Spectral data wavelengths for each glass layer in a glazing system
322 110 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> wlt = {0.0};
323 :
324 : // Following data, Spectral data for each layer for each wavelength in wlt
325 110 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> t = {0.0}; // normal transmittance
326 110 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rff = {0.0}; // normal front reflectance
327 110 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbb = {0.0}; // normal back reflectance
328 110 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> tPhi = {0.0}; // transmittance at angle of incidence
329 110 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rfPhi = {0.0}; // front reflectance at angle of incidence
330 110 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbPhi = {0.0}; // back reflectance at angle of incidence
331 :
332 : // Number of spectral data wavelengths for each layer; =2 if no spectra data for a layer
333 110 : std::array<int, maxGlassLayers> numpt = {0};
334 :
335 110 : auto &s_mat = state.dataMaterial;
336 110 : auto &s_surf = state.dataSurface;
337 :
338 110 : W5InitGlassParameters(state);
339 :
340 : // Calculate optical properties of blind-type layers entered with MATERIAL:WindowBlind
341 110 : if (s_mat->NumBlinds > 0) {
342 1 : CalcWindowBlindProperties(state);
343 : }
344 :
345 : // Initialize SurfaceScreen structure
346 110 : if (s_mat->NumScreens > 0) {
347 0 : CalcWindowScreenProperties(state);
348 : }
349 :
350 : // Get glazing system optical properties of constructions with glass or glass plus
351 : // shade, screen or blind
352 : // Loop over constructions and find those that are glazing constructions
353 433 : for (int ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
354 323 : auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
355 323 : if (!thisConstruct.TypeIsWindow) {
356 288 : continue;
357 : }
358 42 : if (thisConstruct.WindowTypeBSDF) {
359 1 : continue; // Skip Complex Fenestrations, they have separate
360 : }
361 41 : if (thisConstruct.WindowTypeEQL) {
362 6 : continue; // skip Equivalent Layer Fenestration
363 : }
364 : // handling of optical properties
365 :
366 : // When pulling in develop, the following block appears to have been modified in develop,
367 : // but removed entirely in this branch. I'm going to leave it commented.
368 : // Pre-calculate constants
369 : // for (int IPhi = 1; IPhi <= 10; ++IPhi) {
370 : // CosPhiIndepVar(IPhi) = std::cos((IPhi - 1) * 10.0 * Constant::DegToRad);
371 : //}
372 :
373 35 : TotLay = thisConstruct.TotLayers;
374 :
375 35 : auto const *mat = s_mat->materials(thisConstruct.LayerPoint(1));
376 :
377 : // First layer must be glass, shade, screen or blind to be a glazing construction
378 35 : if (mat->group != Material::Group::Glass && mat->group != Material::Group::Shade && mat->group != Material::Group::Screen &&
379 12 : mat->group != Material::Group::Blind && mat->group != Material::Group::GlassSimple) {
380 0 : continue;
381 : }
382 :
383 35 : ShadeLayNum = 0;
384 35 : ExtShade = false;
385 35 : IntShade = false;
386 35 : BGShade = false;
387 35 : ExtBlind = false;
388 35 : IntBlind = false;
389 35 : BGBlind = false;
390 35 : ExtScreen = false;
391 35 : StormWinConst = false;
392 35 : wm->lSimpleGlazingSystem = false;
393 :
394 35 : if (mat->group == Material::Group::GlassSimple) {
395 12 : auto const *matWin = dynamic_cast<Material::MaterialGlass const *>(mat);
396 12 : assert(matWin != nullptr);
397 :
398 : // what if outside layer is shade, blind, or screen?
399 12 : wm->lSimpleGlazingSystem = true;
400 12 : wm->SimpleGlazingSHGC = matWin->SimpleWindowSHGC;
401 12 : wm->SimpleGlazingU = matWin->SimpleWindowUfactor;
402 : }
403 :
404 35 : if (has_prefix(thisConstruct.Name, "BARECONSTRUCTIONWITHSTORMWIN") || has_prefix(thisConstruct.Name, "SHADEDCONSTRUCTIONWITHSTORMWIN")) {
405 0 : StormWinConst = true;
406 : }
407 :
408 : // Get layer number of shade/blind
409 35 : if (mat->group == Material::Group::Shade) {
410 0 : ExtShade = true;
411 0 : ShadeLayNum = 1;
412 35 : } else if (s_mat->materials(thisConstruct.LayerPoint(TotLay))->group == Material::Group::Shade) {
413 0 : IntShade = true;
414 0 : ShadeLayNum = TotLay;
415 35 : } else if (thisConstruct.TotLayers == 5) {
416 0 : if (s_mat->materials(thisConstruct.LayerPoint(3))->group == Material::Group::Shade) {
417 0 : BGShade = true;
418 0 : ShadeLayNum = 3;
419 : }
420 35 : } else if (thisConstruct.TotLayers == 7) {
421 0 : if (s_mat->materials(thisConstruct.LayerPoint(5))->group == Material::Group::Shade) {
422 0 : BGShade = true;
423 0 : ShadeLayNum = 5;
424 : }
425 : }
426 :
427 35 : if (mat->group == Material::Group::Blind) {
428 0 : ExtBlind = true;
429 0 : ShadeLayNum = 1;
430 0 : BlNum = thisConstruct.LayerPoint(ShadeLayNum);
431 35 : } else if (s_mat->materials(thisConstruct.LayerPoint(TotLay))->group == Material::Group::Blind) {
432 1 : IntBlind = true;
433 1 : ShadeLayNum = TotLay;
434 1 : BlNum = thisConstruct.LayerPoint(ShadeLayNum);
435 34 : } else if (thisConstruct.TotLayers == 5) {
436 0 : if (s_mat->materials(thisConstruct.LayerPoint(3))->group == Material::Group::Blind) {
437 0 : BGBlind = true;
438 0 : ShadeLayNum = 3;
439 0 : BlNum = thisConstruct.LayerPoint(ShadeLayNum);
440 : }
441 34 : } else if (thisConstruct.TotLayers == 7) {
442 0 : if (s_mat->materials(thisConstruct.LayerPoint(5))->group == Material::Group::Blind) {
443 0 : BGBlind = true;
444 0 : ShadeLayNum = 5;
445 0 : BlNum = thisConstruct.LayerPoint(ShadeLayNum);
446 : }
447 : }
448 :
449 35 : if (mat->group == Material::Group::Screen) {
450 0 : ShadeLayNum = 1;
451 0 : ExtScreen = true;
452 : }
453 :
454 35 : ScreenOn = ExtScreen;
455 35 : BlindOn = IntBlind || ExtBlind || BGBlind;
456 35 : ShadeOn = IntShade || ExtShade || BGShade;
457 35 : wm->BGFlag = BGBlind || BGShade;
458 :
459 : // For construction with interior or exterior shade, get shade thermal absorptance (emissivity)
460 : // (accounting for inter-reflection with glazing) and correct the inside glass InsideAbsorpThermal
461 : // for presence of interior shade. Assumes inner and outer glass layers have zero thermal transmittance.
462 :
463 35 : if (IntShade || ExtShade || ExtScreen) {
464 0 : ShadeLayPtr = thisConstruct.LayerPoint(ShadeLayNum);
465 0 : auto const *matShade = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(ShadeLayPtr));
466 0 : assert(matShade != nullptr);
467 0 : if (ExtScreen) {
468 0 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(matShade);
469 0 : assert(matScreen != nullptr);
470 0 : TauShIR = matScreen->DfTrans;
471 : } else {
472 0 : TauShIR = matShade->TransThermal;
473 : }
474 0 : EpsShIR = matShade->AbsorpThermal;
475 0 : RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
476 0 : if (ExtShade || ExtScreen) { // Exterior shade or screen
477 0 : EpsGlIR = s_mat->materials(thisConstruct.LayerPoint(2))->AbsorpThermalFront;
478 : } else { // Interior shade
479 0 : EpsGlIR = s_mat->materials(thisConstruct.LayerPoint(TotLay - 1))->AbsorpThermalBack;
480 : }
481 0 : RhoGlIR = max(0.0, 1.0 - EpsGlIR);
482 0 : thisConstruct.ShadeAbsorpThermal = EpsShIR * (1.0 + TauShIR * RhoGlIR / (1.0 - RhoShIR * RhoGlIR));
483 0 : if (IntShade) {
484 0 : thisConstruct.InsideAbsorpThermal *= TauShIR / (1.0 - RhoShIR * RhoGlIR);
485 : }
486 : }
487 :
488 : // From the individual glass layer properties, get the glazing system optical properties
489 : // for BARE GLASS (i.e., interior, exterior or between-glass shade or blind, or exterior screen, if present, not in place).
490 : // Get one set of system properties for solar incident on front of
491 : // window and a second set for solar incident on back of window. (The back-incident
492 : // properties are used with interior short-wave radiation striking the window from inside.)
493 :
494 : // After the front and back system optical properties are calculated for bare glass,
495 : // a correction is made for the effect of a shade, screen or blind if one of these
496 : // is present in the construction.
497 :
498 35 : NGlass = thisConstruct.TotGlassLayers;
499 :
500 : //--------------------------------------------------------------------------------------------
501 : // Front calculation (solar incident from outside of room); bare glass portion of construction
502 : //--------------------------------------------------------------------------------------------
503 :
504 35 : lquasi = false;
505 35 : AllGlassIsSpectralAverage = true;
506 35 : wm->LayerNum = {0};
507 :
508 : // Loop over glass layers in the construction
509 80 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
510 45 : int LayNum = 1 + 2 * (IGlass - 1);
511 45 : if (ExtShade || ExtBlind || ExtScreen) {
512 0 : LayNum = 2 + 2 * (IGlass - 1);
513 : }
514 45 : if (BGShade || BGBlind) {
515 0 : LayNum = 1;
516 0 : if (NGlass == 2) {
517 0 : if (IGlass == 2) {
518 0 : LayNum = 5;
519 : }
520 : } else { // NGlass = 3
521 0 : if (IGlass == 2) {
522 0 : LayNum = 3;
523 : }
524 0 : if (IGlass == 3) {
525 0 : LayNum = 7;
526 : }
527 : }
528 : }
529 :
530 45 : wm->LayerNum[IGlass - 1] = LayNum;
531 45 : LayPtr = thisConstruct.LayerPoint(LayNum);
532 45 : auto *matGlass = dynamic_cast<Material::MaterialGlass *>(s_mat->materials(LayPtr));
533 45 : assert(matGlass != nullptr);
534 45 : SpecDataNum = matGlass->GlassSpectralDataPtr;
535 45 : if (SpecDataNum != 0) {
536 4 : if (!wm->BGFlag) {
537 4 : AllGlassIsSpectralAverage = false;
538 : }
539 :
540 4 : auto const &specData = s_mat->SpectralData(SpecDataNum);
541 : // Get the spectral data for the transmittance, front reflectance and
542 : // back reflectance (all at normal incidence) for this layer.
543 : // In this case, "front" means incident from the outside and "back"
544 : // means incident from the inside.
545 4 : numptDAT = specData.NumOfWavelengths;
546 4 : numpt[IGlass - 1] = numptDAT;
547 :
548 1072 : for (int ILam = 1; ILam <= numptDAT; ++ILam) {
549 1068 : wlt[IGlass - 1][ILam - 1] = specData.WaveLength(ILam);
550 1068 : t[IGlass - 1][ILam - 1] = specData.Trans(ILam);
551 1068 : if ((IGlass == 1 || (IGlass == 2 && StormWinConst)) && (!wm->BGFlag)) {
552 441 : t[IGlass - 1][ILam - 1] *= matGlass->GlassTransDirtFactor;
553 : }
554 1068 : rff[IGlass - 1][ILam - 1] = specData.ReflFront(ILam);
555 1068 : rbb[IGlass - 1][ILam - 1] = specData.ReflBack(ILam);
556 : }
557 :
558 : // If there is spectral data for between-glass shades or blinds, calc the average spectral properties for use.
559 4 : if (wm->BGFlag) {
560 : // Add warning message for the glazing defined with full spectral data.
561 0 : ShowWarningError(
562 : state,
563 0 : format(
564 : "Window glazing material \"{}\" was defined with full spectral data and has been converted to average spectral data",
565 0 : matGlass->Name));
566 0 : ShowContinueError(
567 : state,
568 0 : format("due to its use with between-glass shades or blinds of the window construction \"{}\".", thisConstruct.Name));
569 0 : ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage.");
570 0 : ShowContinueError(state,
571 : "If this material is also used in other window constructions without between-glass shades or blinds,");
572 0 : ShowContinueError(state,
573 : "then make a duplicate material (with new name) if you want to model those windows (and reference the new "
574 : "material) using the full spectral data.");
575 : // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack
576 : // assuming wlt same as wle
577 0 : wm->tmpTrans = solarSpectrumAverage(state, t[0]);
578 0 : wm->tmpReflectSolBeamFront = solarSpectrumAverage(state, rff[0]);
579 0 : wm->tmpReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]);
580 :
581 : // visible properties
582 0 : wm->tmpTransVis = visibleSpectrumAverage(state, t[0]);
583 0 : wm->tmpReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]);
584 0 : wm->tmpReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]);
585 :
586 : // set this material to average spectral data
587 0 : matGlass->GlassSpectralDataPtr = 0;
588 0 : matGlass->Trans = wm->tmpTrans;
589 0 : matGlass->TransVis = wm->tmpTransVis;
590 0 : matGlass->ReflectSolBeamFront = wm->tmpReflectSolBeamFront;
591 0 : matGlass->ReflectSolBeamBack = wm->tmpReflectSolBeamBack;
592 0 : matGlass->ReflectVisBeamFront = wm->tmpReflectVisBeamFront;
593 0 : matGlass->ReflectVisBeamBack = wm->tmpReflectVisBeamBack;
594 0 : SpecDataNum = 0;
595 : }
596 : }
597 :
598 : // No spectral data for this layer; use spectral average values
599 45 : if (SpecDataNum == 0 && matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
600 39 : lquasi = true;
601 39 : numpt[IGlass - 1] = 2;
602 39 : t[IGlass - 1][0] = matGlass->Trans;
603 39 : if (IGlass == 1 || (IGlass == 2 && StormWinConst)) {
604 32 : t[IGlass - 1][0] *= matGlass->GlassTransDirtFactor;
605 : }
606 39 : t[IGlass - 1][1] = matGlass->TransVis;
607 39 : if (IGlass == 1 || (IGlass == 2 && StormWinConst)) {
608 32 : t[IGlass - 1][1] *= matGlass->GlassTransDirtFactor;
609 : }
610 39 : rff[IGlass - 1][0] = matGlass->ReflectSolBeamFront;
611 39 : rbb[IGlass - 1][0] = matGlass->ReflectSolBeamBack;
612 39 : rff[IGlass - 1][1] = matGlass->ReflectVisBeamFront;
613 39 : rbb[IGlass - 1][1] = matGlass->ReflectVisBeamBack;
614 : }
615 :
616 45 : if (matGlass->windowOpticalData == Window::OpticalDataModel::SpectralAndAngle) {
617 2 : if (!wm->BGFlag) {
618 2 : AllGlassIsSpectralAverage = false;
619 : }
620 2 : numptDAT = wm->wle.size();
621 2 : numpt[IGlass - 1] = numptDAT;
622 2 : if (wm->BGFlag) {
623 : // 5/16/2012 CR 8793. Add warning message for the glazing defined with full spectral data.
624 0 : ShowWarningError(state,
625 0 : format("Window glazing material \"{}\" was defined with full spectral and angular data and has been "
626 : "converted to average spectral data",
627 0 : matGlass->Name));
628 0 : ShowContinueError(
629 : state,
630 0 : format("due to its use with between-glass shades or blinds of the window construction \"{}\".", thisConstruct.Name));
631 0 : ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage.");
632 0 : ShowContinueError(state,
633 : "If this material is also used in other window constructions without between-glass shades or blinds,");
634 0 : ShowContinueError(state,
635 : "then make a duplicate material (with new name) if you want to model those windows (and reference the new "
636 : "material) using the full spectral data.");
637 : // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack
638 : // assuming wlt same as wle
639 0 : for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
640 0 : Real64 lam = wm->wle[ILam - 1];
641 0 : wlt[IGlass - 1][ILam - 1] = lam;
642 0 : t[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngTransCurve->value(state, 0.0, lam);
643 0 : rff[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngFReflCurve->value(state, 0.0, lam);
644 0 : rbb[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngBReflCurve->value(state, 0.0, lam);
645 : }
646 0 : wm->tmpTrans = solarSpectrumAverage(state, t[0]);
647 0 : wm->tmpReflectSolBeamFront = solarSpectrumAverage(state, rff[0]);
648 0 : wm->tmpReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]);
649 :
650 : // visible properties
651 0 : wm->tmpTransVis = visibleSpectrumAverage(state, t[0]);
652 0 : wm->tmpReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]);
653 0 : wm->tmpReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]);
654 :
655 : // set this material to average spectral data
656 0 : matGlass->windowOpticalData = Window::OpticalDataModel::SpectralAverage;
657 0 : matGlass->Trans = wm->tmpTrans;
658 0 : matGlass->TransVis = wm->tmpTransVis;
659 0 : matGlass->ReflectSolBeamFront = wm->tmpReflectSolBeamFront;
660 0 : matGlass->ReflectSolBeamBack = wm->tmpReflectSolBeamBack;
661 0 : matGlass->ReflectVisBeamFront = wm->tmpReflectVisBeamFront;
662 0 : matGlass->ReflectVisBeamBack = wm->tmpReflectVisBeamBack;
663 0 : SpecDataNum = 0;
664 : }
665 : }
666 : } // End of loop over glass layers in the construction for front calculation
667 :
668 : // Loop over incidence angle from 0 to 90 deg in 10 deg increments.
669 : // Get glass layer properties, then glazing system properties (which include the
670 : // effect of inter-reflection among glass layers) at each incidence angle.
671 :
672 : // <<<<<<< HEAD
673 : // This was not a clear merge conflict, so I'm just taking the branch code and we'll see.
674 : std::array<Real64, numPhis> cosPhisLocal;
675 : // =======
676 : // for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
677 : // // 10 degree increment for incident angle is only value for a construction without a layer = SpectralAndAngle
678 : // Phi = double(IPhi - 1) * 10.0;
679 : // CosPhi = std::cos(Phi * Constant::DegToRad);
680 : // if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
681 : // >>>>>>> origin/develop
682 :
683 385 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
684 350 : cosPhisLocal[iPhi] = std::cos((double)iPhi * dPhiDeg * Constant::DegToRad);
685 : }
686 :
687 385 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
688 : // For each wavelength, get glass layer properties at this angle of incidence
689 : // from properties at normal incidence
690 800 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
691 450 : LayPtr = thisConstruct.LayerPoint(wm->LayerNum[IGlass - 1]);
692 450 : auto *matGlass = dynamic_cast<Material::MaterialGlass *>(s_mat->materials(LayPtr));
693 450 : assert(matGlass != nullptr);
694 450 : if (matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
695 11890 : for (int ILam = 1; ILam <= numpt[IGlass - 1]; ++ILam) {
696 11460 : TransAndReflAtPhi(cosPhisLocal[iPhi],
697 11460 : t[IGlass - 1][ILam - 1],
698 11460 : rff[IGlass - 1][ILam - 1],
699 11460 : rbb[IGlass - 1][ILam - 1],
700 11460 : tPhi[IGlass - 1][ILam - 1],
701 11460 : rfPhi[IGlass - 1][ILam - 1],
702 11460 : rbPhi[IGlass - 1][ILam - 1],
703 11460 : wm->lSimpleGlazingSystem,
704 11460 : wm->SimpleGlazingSHGC,
705 11460 : wm->SimpleGlazingU);
706 : }
707 : } else {
708 4320 : for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
709 2140 : Real64 lam = wm->wle[ILam - 1];
710 2140 : wlt[IGlass - 1][ILam - 1] = lam;
711 2140 : tPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngTransCurve->value(state, iPhi * dPhiDeg, lam);
712 2140 : rfPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngFReflCurve->value(state, iPhi * dPhiDeg, lam);
713 2140 : rbPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngBReflCurve->value(state, iPhi * dPhiDeg, lam);
714 : }
715 : }
716 : // For use with between-glass shade/blind, save angular properties of isolated glass
717 : // for case that all glass layers were input with spectral-average properties
718 : // only used by between-glass shades or blinds
719 450 : if (AllGlassIsSpectralAverage) {
720 390 : tBareSolPhi(IGlass)[iPhi] = tPhi[IGlass - 1][0];
721 390 : tBareVisPhi(IGlass)[iPhi] = tPhi[IGlass - 1][1];
722 390 : rfBareSolPhi(IGlass)[iPhi] = rfPhi[IGlass - 1][0];
723 390 : rfBareVisPhi(IGlass)[iPhi] = rfPhi[IGlass - 1][1];
724 390 : rbBareSolPhi(IGlass)[iPhi] = rbPhi[IGlass - 1][0];
725 390 : rbBareVisPhi(IGlass)[iPhi] = rbPhi[IGlass - 1][1];
726 390 : afBareSolPhi(IGlass)[iPhi] = max(0.0, 1.0 - (tBareSolPhi(IGlass)[iPhi] + rfBareSolPhi(IGlass)[iPhi]));
727 390 : abBareSolPhi(IGlass)[iPhi] = max(0.0, 1.0 - (tBareSolPhi(IGlass)[iPhi] + rbBareSolPhi(IGlass)[iPhi]));
728 : }
729 : }
730 :
731 : // For each wavelength in the solar spectrum, calculate system properties
732 : // stPhi, srfPhi, srbPhi and saPhi at this angle of incidence.
733 : // In the following the argument "1" indicates that spectral average solar values
734 : // should be used for layers without spectral data.
735 :
736 350 : std::array<Real64, nume> stPhi = {0.0}; // Glazing system transmittance at angle of incidence for each wavelength in wle
737 350 : std::array<Real64, nume> srfPhi = {0.0}; // Glazing system front reflectance at angle of incidence for each wavelength in wle
738 350 : std::array<Real64, nume> srbPhi = {0.0}; // Glazing system back reflectance at angle of incidence for each wavelength in wle
739 : // For each layer, glazing system absorptance at angle of incidence
740 350 : Array2D<Real64> saPhi(maxGlassLayers, nume, 0.0);
741 :
742 350 : SystemSpectralPropertiesAtPhi(state, 1, NGlass, 0.0, 2.54, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
743 :
744 : // Get solar properties of system by integrating over solar irradiance spectrum.
745 : // For now it is assumed that the exterior and interior irradiance spectra are the same.
746 350 : tsolPhi[iPhi] = solarSpectrumAverage(state, stPhi);
747 350 : rfsolPhi[iPhi] = solarSpectrumAverage(state, srfPhi);
748 350 : rbsolPhi[iPhi] = solarSpectrumAverage(state, srbPhi);
749 :
750 800 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
751 48600 : for (int ILam = 1; ILam <= nume; ++ILam) {
752 48150 : sabsPhi(ILam) = saPhi(IGlass, ILam);
753 : }
754 450 : solabsPhi(IGlass)[iPhi] = solarSpectrumAverage(state, sabsPhi);
755 : }
756 :
757 : // Get visible properties of system by integrating over solar irradiance
758 : // spectrum weighted by photopic response.
759 : // Need to redo the calculation of system spectral properties here only if
760 : // one or more glass layers have no spectral data (lquasi = .TRUE.); in this
761 : // case the spectral average visible properties will be used for the layers
762 : // without spectral data, as indicated by the argument "2".
763 :
764 350 : if (lquasi) {
765 320 : SystemSpectralPropertiesAtPhi(state, 2, NGlass, 0.37, 0.78, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
766 : }
767 350 : tvisPhi[iPhi] = visibleSpectrumAverage(state, stPhi);
768 350 : rfvisPhi[iPhi] = visibleSpectrumAverage(state, srfPhi);
769 350 : rbvisPhi[iPhi] = visibleSpectrumAverage(state, srbPhi);
770 :
771 350 : } // End of loop over incidence angles for front calculation
772 :
773 : // only used by between-glass shades or blinds
774 35 : if (AllGlassIsSpectralAverage) {
775 71 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
776 39 : W5LsqFit(cosPhisLocal, tBareSolPhi(IGlass), thisConstruct.tBareSolCoef(IGlass));
777 39 : W5LsqFit(cosPhisLocal, tBareVisPhi(IGlass), thisConstruct.tBareVisCoef(IGlass));
778 39 : W5LsqFit(cosPhisLocal, rfBareSolPhi(IGlass), thisConstruct.rfBareSolCoef(IGlass));
779 39 : W5LsqFit(cosPhisLocal, rfBareVisPhi(IGlass), thisConstruct.rfBareVisCoef(IGlass));
780 39 : W5LsqFit(cosPhisLocal, rbBareSolPhi(IGlass), thisConstruct.rbBareSolCoef(IGlass));
781 39 : W5LsqFit(cosPhisLocal, rbBareVisPhi(IGlass), thisConstruct.rbBareVisCoef(IGlass));
782 39 : W5LsqFit(cosPhisLocal, afBareSolPhi(IGlass), thisConstruct.afBareSolCoef(IGlass));
783 39 : W5LsqFit(cosPhisLocal, abBareSolPhi(IGlass), thisConstruct.abBareSolCoef(IGlass));
784 : }
785 : }
786 :
787 35 : thisConstruct.ReflectSolDiffFront = DiffuseAverage(rfsolPhi);
788 35 : thisConstruct.ReflectSolDiffBack = DiffuseAverage(rbsolPhi);
789 35 : thisConstruct.ReflectVisDiffFront = DiffuseAverage(rfvisPhi);
790 35 : thisConstruct.ReflectVisDiffBack = DiffuseAverage(rbvisPhi);
791 :
792 35 : tsolDiff = DiffuseAverage(tsolPhi);
793 35 : tvisDiff = DiffuseAverage(tvisPhi);
794 35 : thisConstruct.TransDiff = tsolDiff;
795 35 : thisConstruct.TransDiffVis = tvisDiff;
796 80 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
797 45 : solabsPhiLay = solabsPhi(IGlass); // Is this a deep copy?
798 45 : solabsDiff(IGlass) = DiffuseAverage(solabsPhiLay);
799 45 : thisConstruct.AbsDiff(IGlass) = solabsDiff(IGlass);
800 :
801 : // For use with between-glass shade/blind, get diffuse properties of isolated glass for case when
802 : // all glass layers were input with spectral-average properties
803 : // only used by between-glass shades or blinds
804 45 : if (AllGlassIsSpectralAverage) {
805 39 : thisConstruct.tBareSolDiff(IGlass) = DiffuseAverage(tBareSolPhi(IGlass));
806 39 : thisConstruct.tBareVisDiff(IGlass) = DiffuseAverage(tBareVisPhi(IGlass));
807 39 : thisConstruct.rfBareSolDiff(IGlass) = DiffuseAverage(rfBareSolPhi(IGlass));
808 39 : thisConstruct.rfBareVisDiff(IGlass) = DiffuseAverage(rfBareVisPhi(IGlass));
809 39 : thisConstruct.rbBareSolDiff(IGlass) = DiffuseAverage(rbBareSolPhi(IGlass));
810 39 : thisConstruct.rbBareVisDiff(IGlass) = DiffuseAverage(rbBareVisPhi(IGlass));
811 39 : thisConstruct.afBareSolDiff(IGlass) = max(0.0, 1.0 - (thisConstruct.tBareSolDiff(IGlass) + thisConstruct.rfBareSolDiff(IGlass)));
812 39 : thisConstruct.abBareSolDiff(IGlass) = max(0.0, 1.0 - (thisConstruct.tBareSolDiff(IGlass) + thisConstruct.rbBareSolDiff(IGlass)));
813 : }
814 : }
815 :
816 : //------------------------------------------------------------------------------------------
817 : // Back calculation (solar incident from inside of room); bare glass portion of construction
818 : //------------------------------------------------------------------------------------------
819 :
820 35 : lquasi = false;
821 35 : wm->LayerNum = {0};
822 :
823 : // Loop over glass layers in the construction.
824 80 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
825 45 : int LayNum = 1 + (NGlass - IGlass) * 2;
826 45 : if (ExtShade || ExtBlind || ExtScreen) {
827 0 : LayNum = 2 + (NGlass - IGlass) * 2;
828 : }
829 45 : if (BGShade || BGBlind) {
830 0 : if (NGlass == 2) {
831 0 : if (IGlass == 1) {
832 0 : LayNum = 5;
833 : }
834 0 : if (IGlass == 2) {
835 0 : LayNum = 1;
836 : }
837 : } else { // NGlass = 3
838 0 : if (IGlass == 1) {
839 0 : LayNum = 7;
840 : }
841 0 : if (IGlass == 2) {
842 0 : LayNum = 3;
843 : }
844 0 : if (IGlass == 3) {
845 0 : LayNum = 1;
846 : }
847 : }
848 : }
849 45 : wm->LayerNum[IGlass - 1] = LayNum;
850 45 : LayPtr = thisConstruct.LayerPoint(LayNum);
851 45 : auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(s_mat->materials(LayPtr));
852 45 : assert(matGlass != nullptr);
853 :
854 45 : if (matGlass->GlassSpectralDataPtr != 0) {
855 4 : auto const &specData = s_mat->SpectralData(matGlass->GlassSpectralDataPtr);
856 : // Get the spectral data for the transmittance, front reflectance and
857 : // back reflectance (all at normal incidence) for this layer.
858 : // In this case, "front" means incident from the inside and "back"
859 : // means incident from the outside.
860 :
861 4 : numptDAT = specData.NumOfWavelengths;
862 4 : numpt[IGlass - 1] = numptDAT;
863 :
864 1072 : for (int ILam = 1; ILam <= numptDAT; ++ILam) {
865 1068 : wlt[IGlass - 1][ILam - 1] = specData.WaveLength(ILam);
866 1068 : t[IGlass - 1][ILam - 1] = specData.Trans(ILam);
867 1068 : if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) {
868 441 : t[IGlass - 1][ILam - 1] *= matGlass->GlassTransDirtFactor;
869 : }
870 1068 : rff[IGlass - 1][ILam - 1] = specData.ReflBack(ILam);
871 1068 : rbb[IGlass - 1][ILam - 1] = specData.ReflFront(ILam);
872 : }
873 :
874 : // No spectral data for this layer; use spectral average values
875 41 : } else if (matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
876 39 : lquasi = true;
877 39 : numpt[IGlass - 1] = 2;
878 39 : t[IGlass - 1][0] = matGlass->Trans;
879 39 : if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) {
880 32 : t[IGlass - 1][0] *= matGlass->GlassTransDirtFactor;
881 : }
882 39 : t[IGlass - 1][1] = matGlass->TransVis;
883 39 : if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) {
884 32 : t[IGlass - 1][1] *= matGlass->GlassTransDirtFactor;
885 : }
886 39 : rff[IGlass - 1][0] = matGlass->ReflectSolBeamBack;
887 39 : rbb[IGlass - 1][0] = matGlass->ReflectSolBeamFront;
888 39 : rff[IGlass - 1][1] = matGlass->ReflectVisBeamBack;
889 39 : rbb[IGlass - 1][1] = matGlass->ReflectVisBeamFront;
890 :
891 : // Using SpectralAndAngle here
892 : } else {
893 2 : numptDAT = wm->wle.size();
894 2 : numpt[IGlass - 1] = numptDAT;
895 : }
896 : } // End of loop over glass layers in the construction for back calculation
897 :
898 : // Loop over incidence angle from 0 to 90 deg in 10 deg increments.
899 : // Get bare glass layer properties, then glazing system properties at each incidence angle.
900 : // The glazing system properties include the effect of inter-reflection among glass layers,
901 : // but exclude the effect of a shade or blind if present in the construction.
902 : // When a construction has a layer = SpectralAndAngle, the 10 degree increment will be overridden.
903 :
904 : // another odd merge conflict, I'm just taking the branch code
905 : //<<<<<<< HEAD
906 385 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
907 : //=======
908 : // for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
909 : // Phi = double(IPhi - 1) * 10.0;
910 : // CosPhi = std::cos(Phi * Constant::DegToRad);
911 : // if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
912 :
913 : // >>>>>>> origin/develop
914 : // For each wavelength, get glass layer properties at this angle of incidence
915 : // from properties at normal incidence
916 800 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
917 450 : LayPtr = thisConstruct.LayerPoint(wm->LayerNum[IGlass - 1]);
918 450 : auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(s_mat->materials(LayPtr));
919 450 : assert(matGlass != nullptr);
920 450 : if (matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
921 11890 : for (int ILam = 1; ILam <= numpt[IGlass - 1]; ++ILam) {
922 :
923 11460 : TransAndReflAtPhi(cosPhisLocal[iPhi],
924 11460 : t[IGlass - 1][ILam - 1],
925 11460 : rff[IGlass - 1][ILam - 1],
926 11460 : rbb[IGlass - 1][ILam - 1],
927 11460 : tPhi[IGlass - 1][ILam - 1],
928 11460 : rfPhi[IGlass - 1][ILam - 1],
929 11460 : rbPhi[IGlass - 1][ILam - 1],
930 11460 : wm->lSimpleGlazingSystem,
931 11460 : wm->SimpleGlazingSHGC,
932 11460 : wm->SimpleGlazingU);
933 : }
934 :
935 : } else {
936 4320 : for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
937 2140 : Real64 lam = wm->wle[ILam - 1];
938 2140 : wlt[IGlass - 1][ILam - 1] = lam;
939 2140 : tPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngTransCurve->value(state, iPhi * dPhiDeg, lam);
940 2140 : rfPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngFReflCurve->value(state, iPhi * dPhiDeg, lam);
941 2140 : rbPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngBReflCurve->value(state, iPhi * dPhiDeg, lam);
942 : }
943 : }
944 : }
945 :
946 : // For each wavelength in the solar spectrum, calculate system properties
947 : // stPhi, srfPhi, srbPhi and saPhi at this angle of incidence
948 350 : std::array<Real64, nume> stPhi = {0.0}; // Glazing system transmittance at angle of incidence for each wavelength in wle
949 350 : std::array<Real64, nume> srfPhi = {0.0}; // Glazing system front reflectance at angle of incidence for each wavelength in wle
950 350 : std::array<Real64, nume> srbPhi = {0.0}; // Glazing system back reflectance at angle of incidence for each wavelength in wle
951 : // For each layer, glazing system absorptance at angle of incidence
952 350 : Array2D<Real64> saPhi(maxGlassLayers, nume, 0.0);
953 :
954 350 : SystemSpectralPropertiesAtPhi(state, 1, NGlass, 0.0, 2.54, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
955 :
956 : // Get back absorptance properties of system by integrating over solar irradiance spectrum.
957 : // For now it is assumed that the exterior and interior irradiance spectra are the same.
958 :
959 800 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
960 48600 : for (int j = 1; j <= nume; ++j) {
961 48150 : sabsPhi(j) = saPhi(IGlass, j);
962 : }
963 450 : solabsBackPhi(IGlass)[iPhi] = solarSpectrumAverage(state, sabsPhi);
964 : }
965 :
966 350 : } // End of loop over incidence angles for back calculation
967 :
968 80 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
969 45 : IGlassBack = NGlass - IGlass + 1;
970 45 : thisConstruct.AbsDiffBack(IGlass) = DiffuseAverage(solabsBackPhi(IGlassBack));
971 : }
972 :
973 : //-----------------------------------------------------------------------
974 : // Correction for effect of shade, screen or blind if present in the construction
975 : //-----------------------------------------------------------------------
976 :
977 : // For construction with shade, screen or blind, get system shading device absorptance
978 : // and correct the system glass layer absorptances for the effect of reflection
979 : // and transmission by shade, screen or blind. Get system reflectance (front and back,
980 : // solar and visible)
981 35 : auto &constr = thisConstruct;
982 :
983 : // Solar and visible properties of isolated shade or blind
984 : // (Note: for shades or screen we go through the following loop over slat angles only once.)
985 :
986 35 : Real64 const tsolDiff_2(pow_2(tsolDiff));
987 35 : Real64 const tvisDiff_2(pow_2(tvisDiff));
988 :
989 35 : if (IntShade) {
990 0 : auto const *matSh = dynamic_cast<Material::MaterialShade const *>(s_mat->materials(constr.LayerPoint(ShadeLayNum)));
991 0 : assert(matSh != nullptr);
992 0 : ShadeAbs = matSh->AbsorpSolar;
993 0 : ShadeTrans = matSh->Trans;
994 0 : ShadeTransVis = matSh->TransVis;
995 0 : ShadeRefl = matSh->ReflectShade;
996 0 : ShadeReflVis = matSh->ReflectShadeVis;
997 0 : rsh = ShadeRefl;
998 0 : rshv = ShadeReflVis;
999 0 : tsh = ShadeTrans;
1000 0 : tshv = ShadeTransVis;
1001 0 : ash = ShadeAbs;
1002 :
1003 : // Correction factors for inter-reflections between glass and shading device
1004 0 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffBack);
1005 0 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffBack);
1006 :
1007 : // Front incident solar, beam, interior shade
1008 0 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
1009 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1010 0 : solabsPhi(IGlass)[iPhi] += tsolPhi[iPhi] * ShadeRefl * ShadeReflFac * constr.AbsDiffBack(IGlass);
1011 : }
1012 0 : solabsShadePhi[iPhi] = tsolPhi[iPhi] * ShadeReflFac * ShadeAbs;
1013 0 : tsolPhi[iPhi] *= ShadeReflFac * ShadeTrans;
1014 0 : tvisPhi[iPhi] *= ShadeReflFacVis * ShadeTransVis;
1015 : }
1016 :
1017 : // Front incident solar, diffuse, interior shade
1018 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1019 0 : constr.AbsDiff(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
1020 : }
1021 :
1022 0 : constr.AbsDiffShade = tsolDiff * ShadeReflFac * ShadeAbs;
1023 0 : constr.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
1024 0 : constr.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1025 0 : constr.ReflectSolDiffFront += tsolDiff_2 * ShadeRefl * ShadeReflFac;
1026 0 : constr.ReflectVisDiffFront += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1027 :
1028 : // Back incident solar, diffuse, interior shade
1029 :
1030 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1031 0 : constr.AbsDiffBack(IGlass) *= ShadeTrans * ShadeReflFac;
1032 : }
1033 :
1034 0 : constr.AbsDiffBackShade = ShadeAbs * (1 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffBack);
1035 0 : constr.ReflectSolDiffBack = ShadeRefl + pow_2(ShadeTrans) * constr.ReflectSolDiffBack * ShadeReflFac;
1036 0 : constr.ReflectVisDiffBack = ShadeReflVis + pow_2(ShadeTransVis) * constr.ReflectVisDiffBack * ShadeReflFacVis;
1037 :
1038 : // Exterior Shade
1039 35 : } else if (ExtShade) {
1040 0 : auto const *matSh = dynamic_cast<Material::MaterialShade const *>(s_mat->materials(constr.LayerPoint(ShadeLayNum)));
1041 0 : assert(matSh != nullptr);
1042 0 : ShadeAbs = matSh->AbsorpSolar;
1043 0 : ShadeTrans = matSh->Trans;
1044 0 : ShadeTransVis = matSh->TransVis;
1045 0 : ShadeRefl = matSh->ReflectShade;
1046 0 : ShadeReflVis = matSh->ReflectShadeVis;
1047 0 : rsh = ShadeRefl;
1048 0 : rshv = ShadeReflVis;
1049 0 : tsh = ShadeTrans;
1050 0 : tshv = ShadeTransVis;
1051 0 : ash = ShadeAbs;
1052 :
1053 : // Correction factors for inter-reflections between glass and shading device
1054 0 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffFront);
1055 0 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffFront);
1056 :
1057 0 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
1058 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1059 0 : solabsPhi(IGlass)[iPhi] = ShadeTrans * solabsDiff(IGlass) * ShadeReflFac;
1060 : }
1061 0 : tsolPhi[iPhi] = ShadeTrans * ShadeReflFac * tsolDiff;
1062 0 : tvisPhi[iPhi] = ShadeTransVis * ShadeReflFacVis * tvisDiff;
1063 0 : solabsShadePhi[iPhi] = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffFront);
1064 : }
1065 :
1066 : // Front incident solar, diffuse, exterior shade/screen/blind
1067 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1068 0 : constr.AbsDiff(IGlass) = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
1069 : }
1070 :
1071 : // Front incident solar, diffuse, exterior shade/screen
1072 0 : constr.AbsDiffShade = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffFront);
1073 0 : constr.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
1074 0 : constr.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1075 0 : constr.ReflectSolDiffFront = ShadeRefl + pow_2(ShadeTrans) * constr.ReflectSolDiffFront * ShadeReflFac;
1076 0 : constr.ReflectVisDiffFront = ShadeReflVis + pow_2(ShadeTransVis) * constr.ReflectVisDiffFront * ShadeReflFacVis;
1077 :
1078 : // Back incident solar, diffuse, exterior shade/screen
1079 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1080 0 : constr.AbsDiffBack(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
1081 : }
1082 0 : constr.AbsDiffBackShade = tsolDiff * ShadeReflFac * ShadeAbs;
1083 0 : constr.ReflectSolDiffBack += tsolDiff_2 * ShadeRefl * ShadeReflFac;
1084 0 : constr.ReflectVisDiffBack += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1085 :
1086 : // Between-glass shade
1087 35 : } else if (BGShade) {
1088 0 : auto const *matSh = dynamic_cast<Material::MaterialShade const *>(s_mat->materials(constr.LayerPoint(ShadeLayNum)));
1089 0 : assert(matSh != nullptr);
1090 0 : ShadeAbs = matSh->AbsorpSolar;
1091 0 : ShadeTrans = matSh->Trans;
1092 0 : ShadeTransVis = matSh->TransVis;
1093 0 : ShadeRefl = matSh->ReflectShade;
1094 0 : ShadeReflVis = matSh->ReflectShadeVis;
1095 0 : rsh = ShadeRefl;
1096 0 : rshv = ShadeReflVis;
1097 0 : tsh = ShadeTrans;
1098 0 : tshv = ShadeTransVis;
1099 0 : ash = ShadeAbs;
1100 :
1101 : // Between-glass shade/blind; assumed to be between glass #2 and glass #3
1102 0 : tsh2 = pow_2(tsh);
1103 0 : tshv2 = pow_2(tshv);
1104 0 : td1 = constr.tBareSolDiff(1);
1105 0 : td2 = constr.tBareSolDiff(2);
1106 0 : td1v = constr.tBareVisDiff(1);
1107 0 : td2v = constr.tBareVisDiff(2);
1108 0 : afd1 = constr.afBareSolDiff(1);
1109 0 : afd2 = constr.afBareSolDiff(2);
1110 0 : abd1 = constr.abBareSolDiff(1);
1111 0 : abd2 = constr.abBareSolDiff(2);
1112 0 : rb1 = constr.rbBareSolDiff(1);
1113 0 : rb2 = constr.rbBareSolDiff(2);
1114 0 : rb1v = constr.rbBareVisDiff(1);
1115 0 : rb2v = constr.rbBareVisDiff(2);
1116 0 : rf1 = constr.rfBareSolDiff(1);
1117 0 : rf2 = constr.rfBareSolDiff(2);
1118 0 : rf1v = constr.rfBareVisDiff(1);
1119 0 : rf2v = constr.rfBareVisDiff(2);
1120 :
1121 0 : if (NGlass == 2) {
1122 :
1123 : // Front incident solar, beam, between-glass shade, NGlass = 2
1124 :
1125 0 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
1126 0 : t1 = tBareSolPhi(1)[iPhi];
1127 0 : t1v = tBareVisPhi(1)[iPhi];
1128 0 : af1 = afBareSolPhi(1)[iPhi];
1129 0 : ab1 = abBareSolPhi(1)[iPhi];
1130 0 : tsolPhi[iPhi] = t1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * td2;
1131 0 : tvisPhi[iPhi] = t1v * (tshv + rshv * rb1v * tshv + tshv * rf2v * rshv) * td2v;
1132 0 : solabsShadePhi[iPhi] = t1 * (ash + rsh * rb1 + tsh * rf2) * ash;
1133 0 : solabsPhi(1)[iPhi] = af1 + t1 * (rsh + rsh * rb1 * rsh + tsh * rf2 * tsh) * abd1;
1134 0 : solabsPhi(2)[iPhi] = t1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * afd2;
1135 : } // End of loop over incidence angles
1136 :
1137 : // Front incident solar, diffuse, between-glass shade, NGlass = 2
1138 :
1139 0 : constr.TransDiff = td1 * (tsh + rsh * rb1 * tsh + tsh * rb2 * rsh) * td2;
1140 0 : constr.TransDiffVis = td1v * (tshv + rshv * rb1v * tshv + tshv * rb2v * rshv) * td2v;
1141 0 : constr.AbsDiffShade = td1 * (ash + rsh * rb1 * ash + tsh * rf2 * ash);
1142 0 : constr.AbsDiff(1) = afd1 + td1 * (rsh + tsh * rb2 * tsh) * abd1;
1143 0 : constr.AbsDiff(2) = td1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * afd2;
1144 0 : constr.ReflectSolDiffFront = rf1 + td1 * (rsh + rsh * rb1 * rsh + tsh * rf2 * tsh) * td1;
1145 0 : constr.ReflectVisDiffFront = rf1v + td1v * (rshv + rshv * rb1v * rshv + tshv * rf2v * tshv) * td1v;
1146 :
1147 : // Back incident solar, diffuse, between-glass shade, NGlass = 2
1148 :
1149 0 : constr.AbsDiffBackShade = td2 * (ash + rsh * rf2 * ash + tsh * rb1 * ash);
1150 0 : constr.AbsDiffBack(1) = td2 * (tsh + rsh * rf2 * tsh + tsh * rb1 * rsh) * abd1;
1151 0 : constr.AbsDiffBack(2) = abd2 + td2 * (rsh + rsh * rf2 * rsh + tsh * rb1 * tsh) * afd2;
1152 0 : constr.ReflectSolDiffBack = rb2 + td2 * (rsh + rsh * rf2 * rsh + tsh * rb1 * tsh) * td2;
1153 0 : constr.ReflectVisDiffBack = rb2v + td2v * (rshv + rshv * rf2v * rshv + tshv * rb1v * tshv) * td2v;
1154 :
1155 0 : } else if (NGlass == 3) {
1156 :
1157 0 : td3 = constr.tBareSolDiff(3);
1158 0 : td3v = constr.tBareVisDiff(3);
1159 0 : afd3 = constr.afBareSolDiff(3);
1160 0 : abd3 = constr.abBareSolDiff(3);
1161 0 : rb3 = constr.rbBareSolDiff(3);
1162 0 : rb3v = constr.rbBareVisDiff(3);
1163 0 : rf3 = constr.rfBareSolDiff(3);
1164 0 : rf3v = constr.rfBareVisDiff(3);
1165 :
1166 : // Front incident solar, beam, between-glass shade, NGlass = 3
1167 :
1168 0 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
1169 0 : t1 = tBareSolPhi(1)[iPhi];
1170 0 : t1v = tBareVisPhi(1)[iPhi];
1171 0 : t2 = tBareSolPhi(2)[iPhi];
1172 0 : t2v = tBareVisPhi(2)[iPhi];
1173 0 : af1 = afBareSolPhi(1)[iPhi];
1174 0 : af2 = afBareSolPhi(2)[iPhi];
1175 0 : ab1 = abBareSolPhi(1)[iPhi];
1176 0 : ab2 = abBareSolPhi(2)[iPhi];
1177 0 : rbmf2 = max(0.0, 1.0 - (t2 + af2));
1178 :
1179 0 : tsolPhi[iPhi] = t1 * t2 * (tsh + tsh * rf3 * rsh + rsh * td2 * rb1 * td2 * tsh + rsh * rb2 * tsh) * td3;
1180 0 : tvisPhi[iPhi] = t1v * t2v * (tshv + tshv * rf3v * rshv + rshv * td2v * rb1v * td2v * tshv + rshv * rb2v * tshv) * td3v;
1181 0 : solabsShadePhi[iPhi] = t1 * t2 * (1 + rsh * td2 * rb1 * td2 + rsh * rb2) * ash;
1182 0 : solabsPhi(1)[iPhi] = af1 + rbmf2 * ab1 + t1 * t2 * rsh * (1 + rf3 * tsh + rb2 * rsh + td2 * rb1 * td2 * rsh) * td2 * abd1;
1183 0 : solabsPhi(2)[iPhi] = t1 * af2 + t1 * t2 * ((rsh + tsh * rf3 * tsh + rsh * rb2 * rsh) * abd2 + rsh * td2 * rb1 * afd2);
1184 0 : solabsPhi(3)[iPhi] = t1 * t2 * (tsh + rsh * (rb2 * tsh + td2 * rb2 * td2 * tsh + rf3 * rsh)) * afd3;
1185 : } // End of loop over incidence angle
1186 :
1187 : // Front incident solar, diffuse, between-glass shade, NGlass = 3
1188 :
1189 0 : constr.TransDiff = td1 * td2 * (tsh + rsh * td2 * rb1 * td2 * tsh + rsh * rb2 * tsh + tsh * rf3 * rsh) * td3;
1190 0 : constr.TransDiffVis = td1v * td2v * (tshv + rshv * td2v * rb1v * td2v * tshv + rshv * rb2v * tshv + tshv * rf3v * rshv) * td3v;
1191 0 : constr.AbsDiffShade = td1 * td2 * (ash * (1 + rsh * td2 * rb1 * td2 + rsh * rb2 * ash) + tsh * rf3 * ash);
1192 0 : constr.AbsDiff(1) =
1193 0 : afd1 + td1 * (rf2 + td2 * (rsh + rsh * rb2 * rsh + tsh * rf3 * tsh + rsh * td2 * rb1 * td2 * rsh) * td2) * abd1;
1194 0 : constr.AbsDiff(2) = td1 * (afd2 + td2 * (rsh + rsh * rb2 * rsh + tsh * rf3 * tsh) * abd2);
1195 0 : constr.AbsDiff(3) = td1 * td2 * (tsh + rsh * rb2 * tsh + rsh * td2 * rb1 * td2 * tsh + tsh * rf3 * rsh) * afd3;
1196 0 : constr.ReflectSolDiffFront =
1197 0 : rf1 + td1 * rf2 * td1 + td1 * td2 * (rsh + tsh * rf3 * tsh + rsh * rb2 * rsh + rsh * td2 * rb1 * td2 * rsh) * td2 * td1;
1198 0 : constr.ReflectVisDiffFront =
1199 0 : rf1v + td1v * rf2v * td1v +
1200 0 : td1v * td2v * (rshv + tshv * rf3v * tshv + rshv * rb2v * rshv + rshv * td2v * rb1v * td2v * rshv) * td2v * td1v;
1201 :
1202 : // Back incident solar, diffuse, between-glass shade, NGlass = 3
1203 :
1204 0 : constr.AbsDiffBackShade = td3 * ((1 + rsh * rf3) * ash + (tsh * td2 * rb1 * td2 + tsh * rb2) * ash);
1205 0 : constr.AbsDiffBack(1) = td3 * (tsh + rsh * rf3 * tsh + tsh * rb2 * rsh + tsh * td2 * rb1 * td2 * rsh) * td2 * abd1;
1206 0 : constr.AbsDiffBack(2) = td3 * ((tsh + rsh * rf3 * tsh) * abd2 + (tsh * td2 * rb1 * td2 + tsh * rb2) * afd2);
1207 0 : constr.AbsDiffBack(3) = abd3 + td3 * (rsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * afd3;
1208 0 : constr.ReflectSolDiffBack = rb3 + td3 * (rsh + rsh * rf3 * rsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * td3;
1209 0 : constr.ReflectVisDiffBack =
1210 0 : rb3v + td3v * (rshv + rshv * rf3 * rshv + tshv * rb2v * tshv + tshv * td2v * rb1v * td2v * tshv) * td3v;
1211 :
1212 : } // End of check if NGlass = 3
1213 :
1214 : // Interior blind
1215 35 : } else if (IntBlind) {
1216 1 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
1217 :
1218 182 : for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
1219 181 : auto const &btar = matBlind->TARs[iSlatAng];
1220 181 : ShadeTrans = btar.Sol.Ft.Df.Tra;
1221 181 : ShadeTransGnd = btar.Sol.Ft.Df.TraGnd;
1222 181 : ShadeTransSky = btar.Sol.Ft.Df.TraSky;
1223 181 : ShadeTransVis = btar.Vis.Ft.Df.Tra;
1224 181 : ShadeAbs = btar.Sol.Ft.Df.Abs;
1225 181 : ShadeRefl = btar.Sol.Ft.Df.Ref;
1226 181 : ShadeReflGnd = btar.Sol.Ft.Df.RefGnd;
1227 181 : ShadeReflSky = btar.Sol.Ft.Df.RefSky;
1228 181 : ShadeReflVis = btar.Vis.Ft.Df.Ref;
1229 :
1230 : // Correction factors for inter-reflections between glass and shading device
1231 181 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * thisConstruct.ReflectSolDiffBack);
1232 181 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * thisConstruct.ReflectVisDiffBack);
1233 :
1234 : // Front incident solar, diffuse, interior blind
1235 362 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1236 181 : auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
1237 181 : dfAbs.Sol.Ft.Df.Abs = constr.AbsDiff(IGlass) + tsolDiff * ShadeRefl * ShadeReflFac * constr.AbsDiffBack(IGlass);
1238 181 : dfAbs.Sol.Ft.Df.AbsGnd = constr.AbsDiff(IGlass) + tsolDiff * ShadeReflGnd * ShadeReflFac * constr.AbsDiffBack(IGlass);
1239 181 : dfAbs.Sol.Ft.Df.AbsSky = constr.AbsDiff(IGlass) + tsolDiff * ShadeReflSky * ShadeReflFac * constr.AbsDiffBack(IGlass);
1240 : }
1241 :
1242 181 : auto &cbtar = constr.blindTARs[iSlatAng];
1243 :
1244 181 : cbtar.Sol.Ft.Df.Abs = tsolDiff * ShadeReflFac * ShadeAbs;
1245 181 : cbtar.Sol.Ft.Df.AbsGnd = tsolDiff * ShadeReflFac * btar.Sol.Ft.Df.AbsGnd;
1246 181 : cbtar.Sol.Ft.Df.AbsSky = tsolDiff * ShadeReflFac * btar.Sol.Ft.Df.AbsSky;
1247 181 : cbtar.Sol.Ft.Df.Tra = tsolDiff * ShadeReflFac * ShadeTrans;
1248 181 : cbtar.Sol.Ft.Df.TraGnd = tsolDiff * ShadeReflFac * ShadeTransGnd;
1249 181 : cbtar.Sol.Ft.Df.TraSky = tsolDiff * ShadeReflFac * ShadeTransSky;
1250 181 : cbtar.Vis.Ft.Df.Tra = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1251 181 : cbtar.Sol.Ft.Df.Ref = constr.ReflectSolDiffFront + tsolDiff_2 * ShadeRefl * ShadeReflFac;
1252 181 : cbtar.Vis.Ft.Df.Ref = constr.ReflectVisDiffFront + tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1253 :
1254 : // Back incident solar, diffuse, interior blind
1255 :
1256 362 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1257 181 : auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
1258 181 : dfAbs.Sol.Bk.Df.Abs = constr.AbsDiffBack(IGlass) * ShadeTrans * ShadeReflFac;
1259 : }
1260 :
1261 181 : cbtar.Sol.Bk.Df.Abs = btar.Sol.Bk.Df.Abs + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffBack * ShadeAbs;
1262 181 : cbtar.Sol.Bk.Df.Ref = btar.Sol.Bk.Df.Ref + pow_2(ShadeTrans) * constr.ReflectSolDiffBack * ShadeReflFac;
1263 181 : cbtar.Vis.Bk.Df.Ref = btar.Vis.Bk.Df.Ref + pow_2(ShadeTransVis) * constr.ReflectVisDiffBack * ShadeReflFacVis;
1264 : }
1265 :
1266 : // Exterior blind
1267 34 : } else if (ExtBlind) {
1268 0 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
1269 :
1270 0 : for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
1271 0 : auto const &btar = matBlind->TARs[iSlatAng];
1272 0 : ShadeTrans = btar.Sol.Ft.Df.Tra;
1273 0 : ShadeTransGnd = btar.Sol.Ft.Df.TraGnd;
1274 0 : ShadeTransSky = btar.Sol.Ft.Df.TraSky;
1275 0 : ShadeTransVis = btar.Vis.Ft.Df.Tra;
1276 0 : ShadeAbs = btar.Sol.Bk.Df.Abs;
1277 0 : ShadeRefl = btar.Sol.Bk.Df.Ref;
1278 0 : ShadeReflVis = btar.Vis.Bk.Df.Ref;
1279 :
1280 : // Correction factors for inter-reflections between glass and shading device
1281 0 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffFront);
1282 0 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffFront);
1283 :
1284 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1285 0 : auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
1286 0 : dfAbs.Sol.Ft.Df.Abs = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
1287 0 : dfAbs.Sol.Ft.Df.AbsGnd = ShadeTransGnd * ShadeReflFac * solabsDiff(IGlass);
1288 0 : dfAbs.Sol.Ft.Df.AbsSky = ShadeTransSky * ShadeReflFac * solabsDiff(IGlass);
1289 : }
1290 :
1291 0 : auto &cbtar = constr.blindTARs[iSlatAng];
1292 0 : cbtar.Sol.Ft.Df.Abs = btar.Sol.Ft.Df.Abs + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
1293 0 : cbtar.Sol.Ft.Df.AbsGnd = btar.Sol.Ft.Df.AbsGnd + ShadeTransGnd * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
1294 0 : cbtar.Sol.Ft.Df.AbsSky = btar.Sol.Ft.Df.AbsSky + ShadeTransSky * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
1295 0 : cbtar.Sol.Ft.Df.Tra = tsolDiff * ShadeReflFac * ShadeTrans;
1296 0 : cbtar.Sol.Ft.Df.TraGnd = tsolDiff * ShadeReflFac * ShadeTransGnd;
1297 0 : cbtar.Sol.Ft.Df.TraSky = tsolDiff * ShadeReflFac * ShadeTransSky;
1298 0 : cbtar.Vis.Ft.Df.Tra = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1299 0 : cbtar.Sol.Ft.Df.Ref = ShadeRefl + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffFront * ShadeReflFac;
1300 0 : cbtar.Vis.Ft.Df.Ref = ShadeReflVis + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffFront * ShadeReflFacVis;
1301 :
1302 : // Back incident solar, diffuse, exterior shade/blind
1303 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1304 0 : auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
1305 0 : dfAbs.Sol.Bk.Df.Abs = constr.AbsDiffBack(IGlass) + tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
1306 : }
1307 :
1308 0 : cbtar.Sol.Bk.Df.Abs = tsolDiff * ShadeReflFac * ShadeAbs;
1309 0 : cbtar.Sol.Bk.Df.Ref = constr.ReflectSolDiffBack + tsolDiff_2 * ShadeRefl * ShadeReflFac;
1310 0 : cbtar.Vis.Bk.Df.Ref = constr.ReflectVisDiffBack + tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1311 : }
1312 :
1313 : // Between-glass blind
1314 34 : } else if (BGBlind) {
1315 0 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
1316 0 : assert(matBlind != nullptr);
1317 :
1318 : // Between-glass shade/blind; assumed to be between glass #2 and glass #3
1319 0 : tsh2 = pow_2(tsh);
1320 0 : tshv2 = pow_2(tshv);
1321 0 : td1 = constr.tBareSolDiff(1);
1322 0 : td2 = constr.tBareSolDiff(2);
1323 0 : td1v = constr.tBareVisDiff(1);
1324 0 : td2v = constr.tBareVisDiff(2);
1325 0 : afd1 = constr.afBareSolDiff(1);
1326 0 : afd2 = constr.afBareSolDiff(2);
1327 0 : abd1 = constr.abBareSolDiff(1);
1328 0 : abd2 = constr.abBareSolDiff(2);
1329 0 : rb1 = constr.rbBareSolDiff(1);
1330 0 : rb2 = constr.rbBareSolDiff(2);
1331 0 : rb1v = constr.rbBareVisDiff(1);
1332 0 : rb2v = constr.rbBareVisDiff(2);
1333 0 : rf1 = constr.rfBareSolDiff(1);
1334 0 : rf2 = constr.rfBareSolDiff(2);
1335 0 : rf1v = constr.rfBareVisDiff(1);
1336 0 : rf2v = constr.rfBareVisDiff(2);
1337 :
1338 0 : for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
1339 0 : auto const &btar = matBlind->TARs[iSlatAng];
1340 0 : tsh = btar.Sol.Ft.Df.Tra;
1341 0 : tshGnd = btar.Sol.Ft.Df.TraGnd;
1342 0 : tshSky = btar.Sol.Ft.Df.TraSky;
1343 0 : tshv = btar.Vis.Ft.Df.Tra;
1344 0 : rfsh = btar.Sol.Ft.Df.Ref;
1345 0 : rfshGnd = btar.Sol.Ft.Df.RefGnd;
1346 0 : rfshSky = btar.Sol.Ft.Df.RefSky;
1347 0 : rfshv = btar.Vis.Ft.Df.Ref;
1348 0 : rbsh = btar.Sol.Bk.Df.Ref;
1349 0 : rbshv = btar.Vis.Bk.Df.Ref;
1350 0 : afsh = btar.Sol.Ft.Df.Abs;
1351 0 : afshGnd = btar.Sol.Ft.Df.AbsGnd;
1352 0 : afshSky = btar.Sol.Ft.Df.AbsSky;
1353 0 : absh = btar.Sol.Bk.Df.Abs;
1354 :
1355 0 : auto &cbtar = constr.blindTARs[iSlatAng];
1356 0 : if (NGlass == 2) {
1357 : // Front incident solar, diffuse, between-glass blind, NGlass = 2
1358 0 : auto &dfAbs1 = constr.layerSlatBlindDfAbs(1)[iSlatAng];
1359 0 : auto &dfAbs2 = constr.layerSlatBlindDfAbs(2)[iSlatAng];
1360 0 : dfAbs1.Sol.Ft.Df.Abs = afd1 + td1 * (rfsh + rfsh * rb1 * rfsh + tsh * rb2 * tsh) * abd1;
1361 0 : dfAbs1.Sol.Ft.Df.AbsGnd = afd1 + td1 * (rfshGnd + rfshGnd * rb1 * rfshGnd + tshGnd * rb2 * tsh) * abd1;
1362 0 : dfAbs1.Sol.Ft.Df.AbsSky = afd1 + td1 * (rfshSky + rfshSky * rb1 * rfshSky + tshSky * rb2 * tsh) * abd1;
1363 0 : dfAbs2.Sol.Ft.Df.Abs = td1 * (tsh + rfsh * rb1 * tsh + tsh * rf2 * rbsh) * afd2;
1364 0 : dfAbs2.Sol.Ft.Df.AbsGnd = td1 * (tshGnd + rfshGnd * rb1 * tsh + tshGnd * rf2 * rbsh) * afd2;
1365 0 : dfAbs2.Sol.Ft.Df.AbsSky = td1 * (tshSky + rfshSky * rb1 * tsh + tshSky * rf2 * rbsh) * afd2;
1366 0 : cbtar.Sol.Ft.Df.Abs = td1 * (afsh + rfsh * rb1 * afsh + tsh * rf2 * absh);
1367 0 : cbtar.Sol.Ft.Df.AbsGnd = td1 * (afshGnd + rfsh * rb1 * afsh + tshGnd * rf2 * absh);
1368 0 : cbtar.Sol.Ft.Df.AbsSky = td1 * (afshSky + rfsh * rb1 * afsh + tshSky * rf2 * absh);
1369 0 : cbtar.Sol.Ft.Df.Tra = td1 * (tsh + rfsh * rb1 * tsh + tsh * rb2 * rbsh) * td2;
1370 0 : cbtar.Sol.Ft.Df.TraGnd = td1 * (tshGnd + rfsh * rb1 * tshGnd + tshGnd * rb2 * rbsh) * td2;
1371 0 : cbtar.Sol.Ft.Df.TraSky = td1 * (tshSky + rfsh * rb1 * tshSky + tshSky * rb2 * rbsh) * td2;
1372 0 : cbtar.Vis.Ft.Df.Tra = td1v * (tshv + rfshv * rb1v * tshv + tshv * rb2v * rbshv) * td2v;
1373 0 : cbtar.Sol.Ft.Df.Ref = rf1 + td1 * (rfsh + rfsh * rb1 * rfsh + tsh * rf2 * tsh) * td1;
1374 0 : cbtar.Vis.Ft.Df.Ref = rf1v + td1v * (rfshv + rfshv * rb1v * rfshv + tshv * rf2v * tshv) * td1v;
1375 :
1376 : // Back incident solar, diffuse, between-glass blind, NGlass = 2
1377 :
1378 0 : dfAbs1.Sol.Bk.Df.Abs = td2 * (tsh + rbsh * rf2 * tsh + tsh * rb1 * rfsh) * abd1;
1379 0 : dfAbs2.Sol.Bk.Df.Abs = abd2 + td2 * (rbsh + rbsh * rf2 * rbsh + tsh * rb1 * tsh) * afd2;
1380 0 : cbtar.Sol.Bk.Df.Abs = td2 * (absh + rbsh * rf2 * absh + tsh * rb1 * afsh);
1381 0 : cbtar.Sol.Bk.Df.Ref = rb2 + td2 * (rbsh + rbsh * rf2 * rbsh + tsh * rb1 * tsh) * td2;
1382 0 : cbtar.Vis.Bk.Df.Ref = rb2v + td2v * (rbshv + rbshv * rf2v * rbshv + tshv * rb1v * tshv) * td2v;
1383 :
1384 0 : } else if (NGlass == 3) {
1385 0 : auto &dfAbs1 = constr.layerSlatBlindDfAbs(1)[iSlatAng];
1386 0 : auto &dfAbs2 = constr.layerSlatBlindDfAbs(2)[iSlatAng];
1387 0 : auto &dfAbs3 = constr.layerSlatBlindDfAbs(3)[iSlatAng];
1388 0 : td3 = constr.tBareSolDiff(3);
1389 0 : td3v = constr.tBareVisDiff(3);
1390 0 : afd3 = constr.afBareSolDiff(3);
1391 0 : abd3 = constr.abBareSolDiff(3);
1392 0 : rb3 = constr.rbBareSolDiff(3);
1393 0 : rb3v = constr.rbBareVisDiff(3);
1394 0 : rf3 = constr.rfBareSolDiff(3);
1395 0 : rf3v = constr.rfBareVisDiff(3);
1396 :
1397 : // Front incident solar, diffuse, between-glass blind, NGlass = 3
1398 :
1399 0 : dfAbs1.Sol.Ft.Df.Abs =
1400 0 : afd1 + td1 * (rf2 + td2 * (rfsh + rfsh * rb2 * rfsh + tsh * rf3 * tsh + rfsh * td2 * rb1 * td2 * rfsh) * td2) * abd1;
1401 0 : dfAbs1.Sol.Ft.Df.AbsGnd =
1402 0 : afd1 +
1403 0 : td1 * (rf2 + td2 * (rfshGnd + rfshGnd * rb2 * rfsh + tshGnd * rf3 * tsh + rfshGnd * td2 * rb1 * td2 * rfsh) * td2) * abd1;
1404 0 : dfAbs1.Sol.Ft.Df.AbsSky =
1405 0 : afd1 +
1406 0 : td1 * (rf2 + td2 * (rfshSky + rfshSky * rb2 * rfsh + tshSky * rf3 * tsh + rfshSky * td2 * rb1 * td2 * rfsh) * td2) * abd1;
1407 0 : dfAbs2.Sol.Ft.Df.Abs = td1 * (afd2 + td2 * (rfsh + rfsh * rb2 * rfsh + tsh * rf3 * tsh) * abd2);
1408 0 : dfAbs2.Sol.Ft.Df.AbsGnd = td1 * (afd2 + td2 * (rfshGnd + rfshGnd * rb2 * rfsh + tshGnd * rf3 * tsh) * abd2);
1409 0 : dfAbs2.Sol.Ft.Df.AbsSky = td1 * (afd2 + td2 * (rfshSky + rfshSky * rb2 * rfsh + tshSky * rf3 * tsh) * abd2);
1410 0 : dfAbs3.Sol.Ft.Df.Abs = td1 * td2 * (tsh + rfsh * rb2 * tsh + rfsh * td2 * rb1 * td2 * tsh + tsh * rf3 * rbsh) * afd3;
1411 0 : dfAbs3.Sol.Ft.Df.AbsGnd =
1412 0 : td1 * td2 * (tshGnd + rfshGnd * rb2 * tsh + rfshGnd * td2 * rb1 * td2 * tsh + tshGnd * rf3 * rbsh) * afd3;
1413 0 : dfAbs3.Sol.Ft.Df.AbsSky =
1414 0 : td1 * td2 * (tshSky + rfshSky * rb2 * tsh + rfshSky * td2 * rb1 * td2 * tsh + tshSky * rf3 * rbsh) * afd3;
1415 0 : cbtar.Sol.Ft.Df.Abs = td1 * td2 * (afsh * (1 + rfsh * td2 * rb1 * td2) + rfsh * rb2 * afsh + tsh * rf3 * absh);
1416 0 : cbtar.Sol.Ft.Df.AbsGnd = td1 * td2 * (afshGnd + afsh * rfsh * (td2 * rb1 * td2 + rb2) + tshGnd * rf3 * absh);
1417 0 : cbtar.Sol.Ft.Df.AbsSky = td1 * td2 * (afshSky + afsh * rfsh * (td2 * rb1 * td2 + rb2) + tshSky * rf3 * absh);
1418 0 : cbtar.Sol.Ft.Df.Tra = td1 * td2 * (tsh + rfsh * td2 * rb1 * td2 * tsh + rfsh * rb2 * tsh + tsh * rf3 * rbsh) * td3;
1419 0 : cbtar.Sol.Ft.Df.TraGnd =
1420 0 : td1 * td2 * (tshGnd + rfsh * td2 * rb1 * td2 * tshGnd + rfsh * rb2 * tshGnd + tshGnd * rf3 * rbsh) * td3;
1421 0 : cbtar.Sol.Ft.Df.TraSky =
1422 0 : td1 * td2 * (tshSky + rfsh * td2 * rb1 * td2 * tshSky + rfsh * rb2 * tshSky + tshSky * rf3 * rbsh) * td3;
1423 0 : cbtar.Vis.Ft.Df.Tra =
1424 0 : td1v * td2v * (tshv + rfshv * td2v * rb1v * td2v * tshv + rfshv * rb2v * tshv + tshv * rf3v * rbshv) * td3v;
1425 0 : cbtar.Sol.Ft.Df.Ref = rf1 + td1 * rf2 * td1 +
1426 0 : td1 * td2 * (rfsh + tsh * rf3 * tsh + rfsh * rb2 * rfsh + rfsh * td2 * rb1 * td2 * rfsh) * td2 * td1;
1427 0 : cbtar.Vis.Ft.Df.Ref =
1428 0 : rf1v + td1v * rf2v * td1v +
1429 0 : td1v * td2v * (rfshv + tshv * rf3v * tshv + rfshv * rb2v * rfshv + rfshv * td2v * rb1v * td2v * rfshv) * td2v * td1v;
1430 :
1431 : // Back incident solar, diffuse, between-glass blind, NGlass = 3
1432 :
1433 0 : dfAbs1.Sol.Bk.Df.Abs = td3 * (tsh + rbsh * rf3 * tsh + tsh * rb2 * rfsh + tsh * td2 * rb1 * td2 * rfsh) * td2 * abd1;
1434 0 : dfAbs2.Sol.Bk.Df.Abs = td3 * ((tsh + rbsh * rf3 * tsh) * abd2 + (tsh * td2 * rb1 * td2 + tsh * rb2) * afd2);
1435 0 : dfAbs3.Sol.Bk.Df.Abs = abd3 + td3 * (rbsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * afd3;
1436 0 : cbtar.Sol.Bk.Df.Abs = td3 * ((1 + rbsh * rf3) * absh + (tsh * td2 * rb1 * td2 + tsh * rb2) * afsh);
1437 0 : cbtar.Sol.Bk.Df.Ref = rb3 + td3 * (rbsh + rbsh * rf3 * rbsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * td3;
1438 0 : cbtar.Vis.Bk.Df.Ref =
1439 0 : rb3v + td3v * (rbshv + rbshv * rf3v * rbshv + tshv * rb2v * tshv + tshv * td2v * rb1v * td2v * tshv) * td3v;
1440 : } // if (NGlass == 3)
1441 : } // for (iSlatAng)
1442 :
1443 : // Exterior screen
1444 34 : } else if (ExtScreen) {
1445 : // diffuse screen properties are calculated during initialization (quarter-hemispherical integration of beam properties)
1446 0 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(s_mat->materials(thisConstruct.LayerPoint(ShadeLayNum)));
1447 0 : assert(matScreen != nullptr);
1448 :
1449 0 : ShadeAbs = matScreen->DfAbs;
1450 0 : ShadeTrans = matScreen->DfTrans;
1451 0 : ShadeTransVis = matScreen->DfTransVis;
1452 0 : ShadeRefl = matScreen->DfRef;
1453 0 : ShadeReflVis = matScreen->DfRefVis;
1454 0 : rsh = ShadeRefl;
1455 0 : rshv = ShadeReflVis;
1456 0 : tsh = ShadeTrans;
1457 0 : tshv = ShadeTransVis;
1458 0 : ash = ShadeAbs;
1459 :
1460 : // Correction factors for inter-reflections between glass and shading device
1461 0 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffFront);
1462 0 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffFront);
1463 :
1464 : // Front incident solar, diffuse, exterior shade/screen/blind
1465 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1466 0 : constr.AbsDiff(IGlass) = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
1467 : }
1468 :
1469 : // Front incident solar, diffuse, exterior shade/screen
1470 0 : constr.AbsDiffShade = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffFront);
1471 0 : constr.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
1472 0 : constr.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1473 0 : constr.ReflectSolDiffFront = ShadeRefl + pow_2(ShadeTrans) * constr.ReflectSolDiffFront * ShadeReflFac;
1474 0 : constr.ReflectVisDiffFront = ShadeReflVis + pow_2(ShadeTransVis) * constr.ReflectVisDiffFront * ShadeReflFacVis;
1475 :
1476 : // Back incident solar, diffuse, exterior shade/screen
1477 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1478 0 : constr.AbsDiffBack(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
1479 : }
1480 0 : constr.AbsDiffBackShade = tsolDiff * ShadeReflFac * ShadeAbs;
1481 0 : constr.ReflectSolDiffBack += tsolDiff_2 * ShadeRefl * ShadeReflFac;
1482 0 : constr.ReflectVisDiffBack += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1483 : } // if (ExtScreen)
1484 :
1485 : // Curve fits to get solar transmittance, reflectance, layer absorptance and
1486 : // visible transmittance as polynomials in cosine of incidence angle
1487 :
1488 35 : if (!BlindOn && !ScreenOn) { // Bare glass or shade on
1489 34 : W5LsqFit(cosPhisLocal, tsolPhi, thisConstruct.TransSolBeamCoef);
1490 34 : W5LsqFit(cosPhisLocal, rfsolPhi, thisConstruct.ReflSolBeamFrontCoef);
1491 34 : W5LsqFit(cosPhisLocal, rbsolPhi, thisConstruct.ReflSolBeamBackCoef);
1492 34 : W5LsqFit(cosPhisLocal, tvisPhi, thisConstruct.TransVisBeamCoef);
1493 :
1494 78 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1495 : // Front absorptance coefficients for glass layers
1496 44 : W5LsqFit(cosPhisLocal, solabsPhi(IGlass), thisConstruct.AbsBeamCoef(IGlass));
1497 :
1498 : // Back absorptance coefficients for glass layers
1499 44 : IGlassBack = NGlass - IGlass + 1;
1500 44 : W5LsqFit(cosPhisLocal, solabsBackPhi(IGlassBack), thisConstruct.AbsBeamBackCoef(IGlass));
1501 : }
1502 :
1503 : // To check goodness of fit //Tuned
1504 :
1505 374 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
1506 340 : tsolPhiFit[iPhi] = 0.0;
1507 340 : tvisPhiFit[iPhi] = 0.0;
1508 :
1509 : //<<<<<<< HEAD
1510 2380 : for (int CoefNum = 0; CoefNum < maxPolyCoef; ++CoefNum) {
1511 2040 : tsolPhiFit[iPhi] += thisConstruct.TransSolBeamCoef[CoefNum] * cosPhisLocal[iPhi];
1512 2040 : tvisPhiFit[iPhi] += thisConstruct.TransVisBeamCoef[CoefNum] * cosPhisLocal[iPhi];
1513 : //=======
1514 : // Phi = double(IPhi - 1) * 10.0;
1515 : // CosPhi = std::cos(Phi * Constant::DegToRad);
1516 : // if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
1517 : // Real64 cos_pow(1.0);
1518 : // for (int CoefNum = 1; CoefNum <= 6; ++CoefNum) {
1519 : // cos_pow *= CosPhi;
1520 : // tsolPhiFit(IPhi) += thisConstruct.TransSolBeamCoef(CoefNum) * cos_pow;
1521 : // tvisPhiFit(IPhi) += thisConstruct.TransVisBeamCoef(CoefNum) * cos_pow;
1522 : // >>>>>>> origin/develop
1523 : }
1524 : }
1525 : }
1526 :
1527 35 : if (ShadeOn) {
1528 0 : W5LsqFit(cosPhisLocal, solabsShadePhi, thisConstruct.AbsBeamShadeCoef);
1529 : }
1530 :
1531 : } // End of loop over constructions
1532 :
1533 : // Get effective glass and shade/blind emissivities for windows that have interior blind or
1534 : // shade. These are used to calculate zone MRT contribution from window when
1535 : // interior blind/shade is deployed.
1536 :
1537 : // Loop for ordinary windows
1538 940 : for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
1539 830 : auto const &surf = s_surf->Surface(SurfNum);
1540 830 : if (!surf.HeatTransSurf) {
1541 18 : continue;
1542 : }
1543 812 : if (!state.dataConstruction->Construct(surf.Construction).TypeIsWindow) {
1544 760 : continue;
1545 : }
1546 52 : if (s_surf->SurfWinWindowModelType(SurfNum) == WindowModel::BSDF) {
1547 0 : continue; // Irrelevant for Complex Fen
1548 : }
1549 52 : if (state.dataConstruction->Construct(surf.Construction).WindowTypeEQL) {
1550 7 : continue; // not required
1551 : }
1552 :
1553 45 : ConstrNumSh = surf.activeShadedConstruction;
1554 45 : if (ConstrNumSh == 0) {
1555 36 : continue;
1556 : }
1557 9 : TotLay = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
1558 :
1559 9 : auto &surfShade = s_surf->surfShades(SurfNum);
1560 :
1561 9 : auto const *mat = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay));
1562 9 : auto const *matFen = dynamic_cast<Material::MaterialFen const *>(mat);
1563 9 : assert(matFen != nullptr);
1564 :
1565 9 : if (mat->group == Material::Group::Shade) {
1566 0 : EpsGlIR = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay - 1))->AbsorpThermalBack;
1567 0 : RhoGlIR = 1 - EpsGlIR;
1568 0 : TauShIR = matFen->TransThermal;
1569 0 : EpsShIR = matFen->AbsorpThermal;
1570 0 : RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
1571 0 : surfShade.effShadeEmi = EpsShIR * (1.0 + RhoGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR));
1572 0 : surfShade.effGlassEmi = EpsGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR);
1573 :
1574 9 : } else if (mat->group == Material::Group::Blind) {
1575 8 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(mat);
1576 8 : assert(matBlind != nullptr);
1577 8 : surfShade.glass.epsIR = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay - 1))->AbsorpThermalBack;
1578 8 : surfShade.glass.rhoIR = 1 - surfShade.glass.epsIR;
1579 :
1580 : // surfShade.blind has not been initialized yet
1581 8 : surfShade.blind.slatAngDeg = matBlind->SlatAngle;
1582 8 : surfShade.blind.slatAng = surfShade.blind.slatAngDeg * Constant::DegToRad;
1583 :
1584 8 : Material::GetSlatIndicesInterpFac(
1585 8 : surfShade.blind.slatAng, surfShade.blind.slatAngIdxLo, surfShade.blind.slatAngIdxHi, surfShade.blind.slatAngInterpFac);
1586 8 : surfShade.blind.TAR.interpSlatAng(
1587 8 : matBlind->TARs[surfShade.blind.slatAngIdxLo], matBlind->TARs[surfShade.blind.slatAngIdxHi], surfShade.blind.slatAngInterpFac);
1588 :
1589 8 : TauShIR = surfShade.blind.TAR.IR.Ft.Tra;
1590 8 : EpsShIR = surfShade.blind.TAR.IR.Bk.Emi;
1591 8 : RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
1592 8 : surfShade.effShadeEmi = EpsShIR * (1.0 + surfShade.glass.rhoIR * TauShIR / (1.0 - surfShade.glass.rhoIR * RhoShIR));
1593 8 : surfShade.effGlassEmi = surfShade.glass.epsIR * TauShIR / (1.0 - surfShade.glass.rhoIR * RhoShIR);
1594 :
1595 : } // End of check if interior shade or interior blind
1596 : } // End of surface loop
1597 :
1598 940 : for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
1599 830 : auto const &surf = s_surf->Surface(SurfNum);
1600 830 : if (surf.Construction <= 0) {
1601 16 : continue;
1602 : }
1603 814 : auto const &construct = state.dataConstruction->Construct(surf.Construction);
1604 814 : if (!construct.TypeIsWindow) {
1605 762 : continue;
1606 : }
1607 :
1608 : // Total thickness of glazing system (used in calculation of inside reveal reflection/absorption
1609 52 : s_surf->SurfWinTotGlazingThickness(SurfNum) = 0.0;
1610 164 : for (int LayNum = 1; LayNum <= construct.TotLayers; ++LayNum) {
1611 112 : s_surf->SurfWinTotGlazingThickness(SurfNum) += s_mat->materials(construct.LayerPoint(LayNum))->Thickness;
1612 : }
1613 : // Sine and cosine of azimuth and tilt
1614 : // SurfaceWindow(SurfNum)%SinAzim = Surface(SurfNum)%SinAzim
1615 : // SurfaceWindow(SurfNum)%CosAzim = Surface(SurfNum)%CosAzim
1616 : // SurfaceWindow(SurfNum)%SinTilt = Surface(SurfNum)%SinTilt
1617 : // SurfaceWindow(SurfNum)%CosTilt = Surface(SurfNum)%CosTilt
1618 : // ! Outward normal unit vector (pointing away from room)
1619 : // SurfaceWindow(SurfNum)%OutNormVec(1) = Surface(SurfNum)%OutNormVec(1)
1620 : // SurfaceWindow(SurfNum)%OutNormVec(2) = Surface(SurfNum)%OutNormVec(2)
1621 : // SurfaceWindow(SurfNum)%OutNormVec(3) = Surface(SurfNum)%OutNormVec(3)
1622 : // write(outputfiledebug,*) 'window='//TRIM(surface(SurfNum)%name)
1623 : // write(outputfiledebug,*) ' swindow%outnormvec=',surfacewindow(SurfNum)%outnormvec
1624 : // write(outputfiledebug,*) ' surface%outnormvec=',surface(SurfNum)%outnormvec
1625 : // Window center
1626 52 : Rectangle = false;
1627 52 : Triangle = false;
1628 52 : if (surf.Sides == 3) {
1629 0 : Triangle = true;
1630 : }
1631 52 : if (surf.Sides == 4) {
1632 52 : Rectangle = true;
1633 : }
1634 52 : if (Rectangle) {
1635 : // Vertices of window (numbered counter-clockwise starting at upper left as viewed from inside of room).
1636 : // Assumes original vertices are numbered counter-clockwise from upper left as viewed from outside.
1637 52 : W3 = surf.Vertex(2);
1638 52 : W2 = surf.Vertex(3);
1639 52 : W1 = surf.Vertex(4);
1640 0 : } else if (Triangle) {
1641 0 : W3 = surf.Vertex(2);
1642 0 : W2 = surf.Vertex(3);
1643 0 : W1 = surf.Vertex(1);
1644 : }
1645 52 : W21 = W1 - W2;
1646 52 : W23 = W3 - W2;
1647 52 : if (Rectangle) {
1648 52 : s_surf->SurfaceWindow(SurfNum).WinCenter = W2 + (W23 + W21) / 2.0;
1649 0 : } else if (Triangle) {
1650 0 : s_surf->SurfaceWindow(SurfNum).WinCenter = W2 + (W23 + W21) / 3.0;
1651 : }
1652 : } // End of surface loop
1653 :
1654 110 : ReportGlass(state);
1655 110 : } // InitGlassOpticalCalculations()
1656 :
1657 : //*****************************************************************************************
1658 :
1659 111 : void W5InitGlassParameters(EnergyPlusData &state)
1660 : {
1661 : // Initializes variables used in the window optical and thermal calculation.
1662 :
1663 : Real64 FrWidth; // Window frame width {m}
1664 : Real64 FrEdgeWidth; // Frame edge width {m}
1665 : Real64 DivWidth; // Window divider width {m}
1666 : Real64 DivEdgeWidth; // Divider edge width {m}
1667 : Real64 GlHeight; // Height of glazed part of window {m}
1668 : Real64 GlWidth; // Width of glazed part of window {m}
1669 : int NumHorDividers; // Number of horizontal divider elements
1670 : int NumVertDividers; // Number of vertical divider elements
1671 : int DifOverrideCount; // Count the number of SolarDiffusing material overrides
1672 :
1673 111 : auto &s_mat = state.dataMaterial;
1674 111 : auto &s_surf = state.dataSurface;
1675 :
1676 435 : for (auto &constr : state.dataConstruction->Construct) {
1677 324 : if (constr.FromWindow5DataFile) {
1678 0 : continue;
1679 : }
1680 324 : if (constr.WindowTypeBSDF) {
1681 1 : continue;
1682 : }
1683 323 : constr.TransDiff = 0.0;
1684 323 : constr.TransDiffVis = 0.0;
1685 323 : constr.AbsDiffBackShade = 0.0;
1686 323 : constr.ShadeAbsorpThermal = 0.0;
1687 323 : constr.ReflectSolDiffBack = 0.0;
1688 323 : constr.ReflectSolDiffFront = 0.0;
1689 323 : constr.ReflectVisDiffFront = 0.0;
1690 :
1691 323 : std::fill(constr.AbsBeamShadeCoef.begin(), constr.AbsBeamShadeCoef.end(), 0.0);
1692 323 : std::fill(constr.TransSolBeamCoef.begin(), constr.TransSolBeamCoef.end(), 0.0);
1693 323 : std::fill(constr.ReflSolBeamFrontCoef.begin(), constr.ReflSolBeamFrontCoef.end(), 0.0);
1694 323 : std::fill(constr.ReflSolBeamBackCoef.begin(), constr.ReflSolBeamBackCoef.begin(), 0.0);
1695 323 : std::fill(constr.TransVisBeamCoef.begin(), constr.TransVisBeamCoef.end(), 0.0);
1696 323 : constr.AbsDiff = 0.0;
1697 323 : constr.AbsDiffBack = 0.0;
1698 2512 : for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
1699 15323 : for (int index = 0; index < maxPolyCoef; ++index) {
1700 13134 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).AbsBeamCoef(Layer)[index] = 0.0;
1701 13134 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).AbsBeamBackCoef(Layer)[index] = 0.0;
1702 : }
1703 : }
1704 : }
1705 :
1706 : // Set some static exterior-window frame and divider SurfaceWindow values
1707 : // from values in FrameDivider derived type
1708 943 : for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
1709 832 : auto const &surf = s_surf->Surface(SurfNum);
1710 832 : if (surf.FrameDivider == 0) {
1711 825 : continue;
1712 : }
1713 :
1714 7 : auto &surfWin = s_surf->SurfaceWindow(SurfNum);
1715 7 : auto const &frdiv = s_surf->FrameDivider(surf.FrameDivider);
1716 :
1717 7 : FrWidth = frdiv.FrameWidth;
1718 7 : GlHeight = surf.Height;
1719 7 : GlWidth = surf.Width;
1720 7 : NumVertDividers = frdiv.VertDividers;
1721 7 : NumHorDividers = frdiv.HorDividers;
1722 7 : s_surf->SurfWinFrameConductance(SurfNum) = frdiv.FrameConductance;
1723 7 : s_surf->SurfWinFrameSolAbsorp(SurfNum) = frdiv.FrameSolAbsorp;
1724 7 : s_surf->SurfWinFrameVisAbsorp(SurfNum) = frdiv.FrameVisAbsorp;
1725 7 : s_surf->SurfWinFrameEmis(SurfNum) = frdiv.FrameEmis;
1726 7 : s_surf->SurfWinFrEdgeToCenterGlCondRatio(SurfNum) = frdiv.FrEdgeToCenterGlCondRatio;
1727 7 : s_surf->SurfWinDividerType(SurfNum) = DataSurfaces::FrameDividerType::DividedLite;
1728 7 : if (frdiv.DividerType == DataSurfaces::FrameDividerType::Suspended) {
1729 0 : s_surf->SurfWinDividerType(SurfNum) = DataSurfaces::FrameDividerType::Suspended;
1730 : }
1731 7 : DivWidth = frdiv.DividerWidth;
1732 7 : s_surf->SurfWinDividerConductance(SurfNum) = frdiv.DividerConductance;
1733 7 : s_surf->SurfWinDividerSolAbsorp(SurfNum) = frdiv.DividerSolAbsorp;
1734 7 : s_surf->SurfWinDividerVisAbsorp(SurfNum) = frdiv.DividerVisAbsorp;
1735 7 : s_surf->SurfWinDividerEmis(SurfNum) = frdiv.DividerEmis;
1736 7 : s_surf->SurfWinDivEdgeToCenterGlCondRatio(SurfNum) = frdiv.DivEdgeToCenterGlCondRatio;
1737 :
1738 7 : s_surf->SurfWinOutsideRevealSolAbs(SurfNum) = frdiv.OutsideRevealSolAbs;
1739 7 : s_surf->SurfWinInsideSillDepth(SurfNum) = frdiv.InsideSillDepth;
1740 7 : s_surf->SurfWinInsideReveal(SurfNum) = frdiv.InsideReveal;
1741 7 : s_surf->SurfWinInsideSillSolAbs(SurfNum) = frdiv.InsideSillSolAbs;
1742 7 : s_surf->SurfWinInsideRevealSolAbs(SurfNum) = frdiv.InsideRevealSolAbs;
1743 :
1744 7 : FrEdgeWidth = frdiv.FrameEdgeWidth;
1745 7 : DivEdgeWidth = frdiv.DividerEdgeWidth;
1746 7 : s_surf->SurfWinFrameEdgeArea(SurfNum) =
1747 7 : 2 * FrEdgeWidth * (GlHeight - FrEdgeWidth - NumHorDividers * DivWidth + GlWidth - FrEdgeWidth - NumVertDividers * DivWidth);
1748 7 : s_surf->SurfWinDividerEdgeArea(SurfNum) =
1749 14 : 2 * DivEdgeWidth * (NumHorDividers * (GlWidth - 2 * FrEdgeWidth) + NumVertDividers * (GlHeight - 2 * FrEdgeWidth)) -
1750 7 : NumHorDividers * NumVertDividers * (4 * pow_2(DivEdgeWidth) + 4 * FrEdgeWidth * DivWidth);
1751 7 : surfWin.centerGlassArea = surf.Area - s_surf->SurfWinFrameEdgeArea(SurfNum) - s_surf->SurfWinDividerEdgeArea(SurfNum);
1752 7 : surfWin.edgeGlassCorrFac =
1753 7 : (s_surf->SurfWinFrameEdgeArea(SurfNum) * s_surf->SurfWinFrEdgeToCenterGlCondRatio(SurfNum) +
1754 7 : s_surf->SurfWinDividerEdgeArea(SurfNum) * s_surf->SurfWinDivEdgeToCenterGlCondRatio(SurfNum) + surfWin.centerGlassArea) /
1755 7 : (s_surf->SurfWinFrameEdgeArea(SurfNum) + s_surf->SurfWinDividerEdgeArea(SurfNum) + surfWin.centerGlassArea);
1756 : } // for (SurfNum)
1757 :
1758 : // Set SolarDiffusing to true for exterior windows that have a construction with an innermost diffusing glass layer
1759 111 : DifOverrideCount = 0;
1760 943 : for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
1761 832 : auto const &surf = s_surf->Surface(SurfNum);
1762 832 : s_surf->SurfWinSolarDiffusing(SurfNum) = false;
1763 832 : if (surf.Class != SurfaceClass::Window || surf.ExtBoundCond != ExternalEnvironment || s_surf->SurfWinStormWinConstr(SurfNum) != 0) {
1764 778 : continue;
1765 : }
1766 :
1767 54 : int ConstrNum = surf.Construction;
1768 54 : int MatNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(state.dataConstruction->Construct(ConstrNum).TotLayers);
1769 54 : auto const *mat = s_mat->materials(MatNum);
1770 54 : if (mat->group != Material::Group::Glass) {
1771 24 : continue;
1772 : }
1773 :
1774 30 : if (!dynamic_cast<Material::MaterialGlass const *>(mat)->SolarDiffusing) {
1775 30 : continue;
1776 : }
1777 :
1778 0 : if (!surf.HasShadeControl) {
1779 0 : s_surf->SurfWinSolarDiffusing(SurfNum) = true;
1780 : // There is a shading control
1781 0 : } else if (s_surf->WindowShadingControl(surf.activeWindowShadingControl).ShadingType == WinShadingType::SwitchableGlazing) {
1782 0 : s_surf->SurfWinSolarDiffusing(SurfNum) = true;
1783 : } else {
1784 0 : s_surf->SurfWinSolarDiffusing(SurfNum) = false;
1785 0 : ++DifOverrideCount;
1786 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1787 0 : ShowWarningError(state,
1788 0 : format("W5InitGlassParameters: Window=\"{}\" has interior material with Solar Diffusing=Yes, but "
1789 : "existing Window Shading Device sets Diffusing=No.",
1790 0 : surf.Name));
1791 : }
1792 : }
1793 : } // for (SurfNum)
1794 :
1795 111 : if (DifOverrideCount > 0) {
1796 0 : if (!state.dataGlobal->DisplayExtraWarnings) {
1797 0 : ShowWarningError(state,
1798 0 : format("W5InitGlassParameters: {} Windows had Solar Diffusing=Yes overridden by presence of Window Shading Device.",
1799 : DifOverrideCount));
1800 : } else {
1801 0 : ShowMessage(state,
1802 0 : format("W5InitGlassParameters: {} Windows had Solar Diffusing=Yes overridden by presence of Window Shading Device.",
1803 : DifOverrideCount));
1804 : }
1805 : }
1806 111 : } // W5InitGlassParameters()
1807 :
1808 : //****************************************************************************
1809 : // WINDOW 5 Optical Calculation Subroutines
1810 : //****************************************************************************
1811 :
1812 1020 : void SystemSpectralPropertiesAtPhi(EnergyPlusData &state,
1813 : int const iquasi, // When there is no spectral data, this is the wavelength
1814 : int const ngllayer, // Number of glass layers in construction
1815 : Real64 const wlbot, // Lowest and highest wavelength considered
1816 : Real64 const wltop,
1817 : std::array<int, maxGlassLayers> const &numpt,
1818 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &wlt,
1819 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &tPhi,
1820 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &rfPhi,
1821 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &rbPhi,
1822 : std::array<Real64, nume> &stPhi,
1823 : std::array<Real64, nume> &srfPhi,
1824 : std::array<Real64, nume> &srbPhi,
1825 : Array2D<Real64> &saPhi)
1826 : {
1827 :
1828 : // SUBROUTINE INFORMATION:
1829 : // AUTHOR Adapted by F.Winkelmann from WINDOW 5
1830 : // subroutine opcalc
1831 : // DATE WRITTEN August 1999
1832 : // MODIFIED na
1833 : // RE-ENGINEERED na
1834 :
1835 : // PURPOSE OF THIS SUBROUTINE:
1836 : // For a particular angle of incidence, calculates system properties
1837 : // for a multi-layer glazing for each wavelength in the solar spectrum.
1838 : // Handles the special case of one or more layers that do not have spectral data.
1839 :
1840 : // Returns, for a particular angle of incidence:
1841 : // stPhi transmissivity of system at each wavelength in swl
1842 : // srfPhi front reflectance of system at each wavelength in swl
1843 : // srbPhi back reflectance of system at each wavelength in swl
1844 : // sabsPhi absorptance by layer at each wavelength in swl
1845 :
1846 1020 : Array1D<Real64> sabsPhi(5); // System solar absorptance in each glass layer for
1847 : // particular angle of incidence
1848 :
1849 : // transmittance at angle of incidence
1850 1020 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> tadjPhi = {0.0};
1851 : // front reflectance at angle of incidence
1852 1020 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rfadjPhi = {0.0};
1853 : // back reflectance at angle of incidence
1854 1020 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbadjPhi = {0.0};
1855 :
1856 1020 : auto const &wm = state.dataWindowManager;
1857 : // For each glass layer find tPhi, rfPhi, and rbPhi at each wavelength
1858 :
1859 2310 : for (int in = 1; in <= ngllayer; ++in) {
1860 139320 : for (int iwl = 1; iwl <= nume; ++iwl) {
1861 138030 : Real64 wl = wm->wle[iwl - 1];
1862 138030 : if (wl < wlbot || wl > wltop) {
1863 28080 : continue;
1864 : }
1865 : // In the following numpt is the number of spectral data points for each layer;
1866 : // numpt = 2 if there is no spectral data for a layer.
1867 109950 : if (numpt[in - 1] <= 2) {
1868 97110 : tadjPhi[in - 1][iwl - 1] = tPhi[in - 1][iquasi - 1];
1869 97110 : rfadjPhi[in - 1][iwl - 1] = rfPhi[in - 1][iquasi - 1];
1870 97110 : rbadjPhi[in - 1][iwl - 1] = rbPhi[in - 1][iquasi - 1];
1871 : } else {
1872 : // Interpolate to get properties at the solar spectrum wavelengths
1873 12840 : tadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], tPhi[in - 1], numpt[in - 1], wl);
1874 12840 : rfadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], rfPhi[in - 1], numpt[in - 1], wl);
1875 12840 : rbadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], rbPhi[in - 1], numpt[in - 1], wl);
1876 : }
1877 : }
1878 : }
1879 :
1880 : // Calculate system properties at each wavelength
1881 110160 : for (int j = 1; j <= nume; ++j) {
1882 109140 : Real64 wl = wm->wle[j - 1];
1883 109140 : if (wl < wlbot || wl > wltop) {
1884 23040 : continue;
1885 : }
1886 :
1887 : // Set diagonal of matrix for subroutine SystemPropertiesAtLambdaAndPhi
1888 196050 : for (int i = 1; i <= ngllayer; ++i) {
1889 109950 : wm->top[i - 1][i - 1] = tadjPhi[i - 1][j - 1];
1890 109950 : wm->rfop[i - 1][i - 1] = rfadjPhi[i - 1][j - 1];
1891 109950 : wm->rbop[i - 1][i - 1] = rbadjPhi[i - 1][j - 1];
1892 : }
1893 :
1894 : // Calculate glazing system properties
1895 86100 : if (ngllayer == 1) { // Single-layer system
1896 62250 : stPhi[j - 1] = wm->top[0][0];
1897 62250 : srfPhi[j - 1] = wm->rfop[0][0];
1898 62250 : srbPhi[j - 1] = wm->rbop[0][0];
1899 62250 : sabsPhi(1) = 1.0 - stPhi[j - 1] - srfPhi[j - 1];
1900 : } else { // Multilayer system
1901 : // Get glazing system properties stPhi, etc., at this wavelength and incidence angle
1902 23850 : SystemPropertiesAtLambdaAndPhi(state, ngllayer, stPhi[j - 1], srfPhi[j - 1], srbPhi[j - 1], sabsPhi);
1903 : }
1904 :
1905 196050 : for (int i = 1; i <= ngllayer; ++i) {
1906 109950 : saPhi(i, j) = sabsPhi(i);
1907 : }
1908 :
1909 : } // End of wavelength loop
1910 1020 : } // SystemSpectralPropertiesAtPhi()
1911 :
1912 : //************************************************************************
1913 :
1914 23850 : void SystemPropertiesAtLambdaAndPhi(EnergyPlusData &state,
1915 : int const n, // Number of glass layers
1916 : Real64 &tt, // System transmittance
1917 : Real64 &rft, // System front and back reflectance
1918 : Real64 &rbt,
1919 : Array1A<Real64> aft // System absorptance of each glass layer
1920 : )
1921 : {
1922 :
1923 : // SUBROUTINE INFORMATION:
1924 : // AUTHOR Adapted by F. Winkelmann from WINDOW 5
1925 : // subroutine op
1926 : // DATE WRITTEN August 1999
1927 : // MODIFIED na
1928 : // RE-ENGINEERED na
1929 :
1930 : // PURPOSE OF THIS SUBROUTINE:
1931 : // For a given angle of incidence, finds the overall properties of
1932 : // of a series of layers at a particular wavelength
1933 :
1934 : // Argument array dimensioning
1935 23850 : aft.dim(5);
1936 :
1937 : Real64 denom; // Intermediate variables
1938 : Real64 denom1;
1939 : Real64 denom2;
1940 : Real64 t0; // Transmittance, back reflectance and front
1941 : Real64 rb0;
1942 : Real64 rf0;
1943 : // reflectance variables
1944 : Real64 af; // Front and back absorptance variables
1945 : Real64 ab;
1946 :
1947 23850 : auto &wm = state.dataWindowManager;
1948 : // Calculate perimeter elements of rt matrix
1949 47700 : for (int i = 1; i <= n - 1; ++i) {
1950 47700 : for (int j = i + 1; j <= n; ++j) {
1951 23850 : denom = 1.0 - wm->rfop[j - 1][j - 1] * wm->rbop[i - 1][j - 2];
1952 23850 : if (denom == 0.0) {
1953 148 : wm->top[j - 1][i - 1] = 0.0;
1954 148 : wm->rfop[j - 1][i - 1] = 1.0;
1955 148 : wm->rbop[i - 1][j - 1] = 1.0;
1956 : } else {
1957 23702 : wm->top[j - 1][i - 1] = wm->top[j - 2][i - 1] * wm->top[j - 1][j - 1] / denom;
1958 23702 : wm->rfop[j - 1][i - 1] = wm->rfop[j - 2][i - 1] + pow_2(wm->top[j - 2][i - 1]) * wm->rfop[j - 1][j - 1] / denom;
1959 23702 : wm->rbop[i - 1][j - 1] = wm->rbop[j - 1][j - 1] + pow_2(wm->top[j - 1][j - 1]) * wm->rbop[i - 1][j - 2] / denom;
1960 : }
1961 : }
1962 : }
1963 : // System properties: transmittance, front and back reflectance
1964 23850 : tt = wm->top[n - 1][0];
1965 23850 : rft = wm->rfop[n - 1][0];
1966 23850 : rbt = wm->rbop[0][n - 1];
1967 :
1968 : // Absorptance in each layer
1969 71550 : for (int j = 1; j <= n; ++j) {
1970 47700 : if (j == 1) {
1971 23850 : t0 = 1.0;
1972 23850 : rb0 = 0.0;
1973 : } else {
1974 23850 : t0 = wm->top[j - 2][0];
1975 23850 : rb0 = wm->rbop[0][j - 2];
1976 : }
1977 :
1978 47700 : if (j == n) {
1979 23850 : rf0 = 0.0;
1980 : } else {
1981 23850 : rf0 = wm->rfop[n - 1][j];
1982 : }
1983 :
1984 47700 : af = 1.0 - wm->top[j - 1][j - 1] - wm->rfop[j - 1][j - 1];
1985 47700 : ab = 1.0 - wm->top[j - 1][j - 1] - wm->rbop[j - 1][j - 1];
1986 47700 : denom1 = 1.0 - wm->rfop[n - 1][j - 1] * rb0;
1987 47700 : denom2 = 1.0 - wm->rbop[0][j - 1] * rf0;
1988 :
1989 47700 : if (denom1 == 0.0 || denom2 == 0.0) {
1990 296 : aft(j) = 0.0;
1991 : } else {
1992 47404 : aft(j) = (t0 * af) / denom1 + (wm->top[j - 1][0] * rf0 * ab) / denom2;
1993 : }
1994 : }
1995 23850 : } // SystemPropertiesAtLambdaAndPhi()
1996 :
1997 1950 : Real64 solarSpectrumAverage(EnergyPlusData const &state, gsl::span<Real64 const> p)
1998 : {
1999 1950 : Real64 num = 0.0;
2000 1950 : Real64 denom = 0.0;
2001 1950 : auto const &wm = state.dataWindowManager;
2002 :
2003 208650 : for (int i = 1; i <= nume - 1; ++i) {
2004 206700 : Real64 const esol = (wm->wle[i] - wm->wle[i - 1]) * 0.5 * (wm->e[i - 1] + wm->e[i]);
2005 206700 : num += 0.5 * (p[i - 1] + p[i]) * esol;
2006 206700 : denom += esol;
2007 : }
2008 1950 : return num / denom; // dangerous, doesn't check for zero denominator
2009 : }
2010 :
2011 1050 : Real64 visibleSpectrumAverage(EnergyPlusData const &state, gsl::span<Real64 const> p)
2012 : {
2013 : // AUTHOR Adapted by F.Winkelmann from WINDOW 5
2014 : // subroutine w4vis
2015 : // DATE WRITTEN August 1999
2016 :
2017 : // Calculates visible average of property p by weighting with solar
2018 : // spectral irradiance, e, and photopic response, y30
2019 :
2020 1050 : Real64 num = 0.0;
2021 1050 : Real64 denom = 0.0;
2022 1050 : Real64 y30new = 0.0;
2023 1050 : Real64 y30ils1 = 0.0;
2024 :
2025 1050 : auto const &wm = state.dataWindowManager;
2026 :
2027 112350 : for (int i = 2; i <= nume; ++i) { // Autodesk:BoundsViolation e|wle|p(i-1) @ i=1: Changed start index from 1 to 2: wle
2028 : // values prevented this violation from occurring in practice
2029 : // Restrict to visible range
2030 111300 : if (wm->wle[i - 1] >= 0.37 && wm->wle[i - 1] <= 0.78) {
2031 36750 : y30new = Interpolate(wm->wlt3, wm->y30, numt3, wm->wle[i - 1]);
2032 36750 : Real64 evis = wm->e[i - 2] * 0.5 * (y30new + y30ils1) * (wm->wle[i - 1] - wm->wle[i - 2]);
2033 36750 : num += 0.5 * (p[i - 1] + p[i - 2]) * evis;
2034 36750 : denom += evis;
2035 36750 : y30ils1 = y30new;
2036 : }
2037 : }
2038 1050 : return num / denom; // dangerous, doesn't check for zero denominator
2039 : }
2040 :
2041 75270 : Real64 Interpolate(gsl::span<Real64 const> x, // Array of data points for independent variable
2042 : gsl::span<Real64 const> y, // Array of data points for dependent variable
2043 : int const npts, // Number of data pairs
2044 : Real64 const xin // Given value of x
2045 : )
2046 : {
2047 :
2048 : // SUBROUTINE INFORMATION:
2049 : // AUTHOR Adapted by F.Winkelmann from WINDOW 5 subroutine interp
2050 : // DATE WRITTEN August 1999
2051 : // MODIFIED na
2052 : // RE-ENGINEERED na
2053 :
2054 : // PURPOSE OF THIS SUBROUTINE:
2055 : // Linearly interpolates between data points. Outputs yout, interpolated
2056 : // value of y corresponding to xin
2057 :
2058 4660920 : for (int i = 1; i <= npts; ++i) {
2059 4660680 : if (xin <= x[i - 1]) {
2060 75030 : if (i - 1 == 0) {
2061 2460 : return y[0];
2062 : } else {
2063 72570 : return y[i - 2] + (y[i - 1] - y[i - 2]) * (xin - x[i - 2]) / (x[i - 1] - x[i - 2]);
2064 : }
2065 : }
2066 : }
2067 :
2068 : // Past the end of the array, so return endpoint
2069 240 : return y[npts - 1];
2070 : }
2071 :
2072 : //***********************************************************************************
2073 : // Window Thermal Calculation Subroutines
2074 : //***********************************************************************************
2075 :
2076 88568 : void CalcWindowHeatBalance(EnergyPlusData &state,
2077 : int const SurfNum, // Surface number
2078 : Real64 const HextConvCoeff, // Outside air film conductance coefficient
2079 : Real64 &SurfInsideTemp, // Inside window surface temperature
2080 : Real64 &SurfOutsideTemp // Outside surface temperature (C)
2081 : )
2082 : {
2083 : // SUBROUTINE INFORMATION:
2084 : // AUTHOR S. Vidanovic
2085 : // DATE WRITTEN June 2016
2086 : // MODIFIED na
2087 : // RE-ENGINEERED na
2088 : //
2089 : // PURPOSE OF THIS SUBROUTINE:
2090 : // Subroutine to direct whether to use exterior or interior window routines
2091 88568 : auto const &wm = state.dataWindowManager;
2092 :
2093 88568 : if (state.dataGlobal->KickOffSizing || state.dataGlobal->KickOffSimulation) {
2094 321 : return;
2095 : }
2096 :
2097 88247 : if (wm->inExtWindowModel->isExternalLibraryModel()) {
2098 0 : CalcWindowHeatBalanceExternalRoutines(state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp);
2099 : } else {
2100 88247 : CalcWindowHeatBalanceInternalRoutines(state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp);
2101 : }
2102 : }
2103 :
2104 88247 : void CalcWindowHeatBalanceInternalRoutines(EnergyPlusData &state,
2105 : int const SurfNum, // Surface number
2106 : Real64 const HextConvCoeff, // Outside air film conductance coefficient
2107 : Real64 &SurfInsideTemp, // Inside window surface temperature
2108 : Real64 &SurfOutsideTemp // Outside surface temperature (C)
2109 : )
2110 : {
2111 :
2112 : // SUBROUTINE INFORMATION:
2113 : // AUTHOR F. Winkelmann
2114 : // DATE WRITTEN November 1999
2115 : // MODIFIED FW, July 2000 (call better solution method)
2116 : // FW, June 2001 (handle window blinds)
2117 : // FW, Dec 2002 (add between-glass shades and blinds)
2118 : // FW, Mar 2003 (extend condensation flag to airflow windows)
2119 : // CC, Jul 2003 (set the reference temperatures for inside surface heat balance
2120 : // depending on convection algorithms and/or air models used)
2121 : // FW, Sep 2003 (increment ZoneWinHeatGain only for exterior windows)
2122 : // RR, May 2006 (add exterior window screen)
2123 : // TH, Dec 2008 (add thermochromic windows)
2124 : // RE-ENGINEERED na
2125 :
2126 : // PURPOSE OF THIS SUBROUTINE:
2127 : // Sets up information needed to calculate the window thermal behavior.
2128 : // Calls SolveForWindowTemperatures, which calculates the inside and outside
2129 : // face temperature of each glass layer by solving the heat balance
2130 : // equations on each face. Also calls CalcWinFrameAndDividerTemps,
2131 : // which calculates the outside and inside face temperatures of the
2132 : // window frame and divider if either of these are present.
2133 : // The resulting inside face temperature of the inner glass pane and the
2134 : // inside surface temperatures of frame and divider are used in the zone
2135 : // heat balance calculation. The inside face temperature of an interior shade
2136 : // or blind, if present, and the natural convection air flow between the
2137 : // shade/blind and inside glass face also appear in the zone heat balance calculation.
2138 : // The logical variable NRSolution is currently set to false, which means
2139 : // that the Newton-Raphson solution method for the glass layer heat balance
2140 : // is not used (because it sometimes didn't converge for 3- and 4-pane
2141 : // constructions with one or more low-emissivity layers). Instead, a more
2142 : // robust solution method is used that successively solves linearized heat
2143 : // balance equations until convergence is reached (see SolveForWindowTemperatures).
2144 : // CalcWindowHeatBalance is called by CalcHeatBalanceInsideSurface once each
2145 : // time step for each window.
2146 :
2147 : // Using/Aliasing
2148 : using namespace DataBSDFWindow;
2149 :
2150 : // SUBROUTINE ARGUMENT DEFINITIONS:
2151 : // (temperature of innermost face) [C]
2152 :
2153 : int SurfNumAdj; // An interzone surface's number in the adjacent zone
2154 : // (sum of solid layers and gap layers)
2155 : int TotGlassLay; // Total number of glass layers in a construction
2156 : int LayPtr; // Material number for a layer
2157 : WinShadingType ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position
2158 : // REAL(r64) :: tsky ! Sky temperature [K]
2159 : int ShadeLayPtr; // Material number corresponding to a shade layer
2160 : Real64 dth1; // Temperature difference across glass layers [K]
2161 : Real64 dth2;
2162 : Real64 dth3;
2163 : Real64 dth4;
2164 : Real64 EffShBlEmiss; // Effective interior shade or blind emissivity
2165 : Real64 EffGlEmiss; // Effective inside glass emissivity when interior shade or blind
2166 : Real64 RoomHumRat; // Room air humidity ratio
2167 : Real64 RoomDewPoint; // Room air dewpoint temperature (C)
2168 : Real64 InsideGlassTemp; // Temperature of room side of innermost glass layer (C)
2169 : Real64 Tleft; // For airflow windows, temperature of the glass faces adjacent
2170 : Real64 Tright;
2171 :
2172 : Real64 SrdSurfTempAbs; // Absolute temperature of a surrounding surface
2173 : Real64 OutSrdIR; // LWR from surrounding srfs
2174 :
2175 : // New variables for thermochromic windows calc
2176 : Real64 locTCSpecTemp; // The temperature corresponding to the specified optical properties of the TC layer
2177 : Real64 locTCLayerTemp; // TC layer temperature at each time step. C
2178 :
2179 88247 : auto &s_mat = state.dataMaterial;
2180 88247 : auto &s_surf = state.dataSurface;
2181 88247 : auto &wm = state.dataWindowManager;
2182 :
2183 : Real64 SurfOutsideEmiss; // temporary for result of outside surface emissivity
2184 : Real64 Tsout; // temporary for result of outside surface temp in Kelvin
2185 :
2186 : // Shorthand references
2187 88247 : auto &surf = s_surf->Surface(SurfNum);
2188 88247 : auto &surfWin = s_surf->SurfaceWindow(SurfNum);
2189 88247 : int ConstrNum = s_surf->SurfActiveConstruction(SurfNum);
2190 88247 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(surf.Zone);
2191 :
2192 88247 : if (s_surf->SurfWinWindowModelType(SurfNum) == WindowModel::BSDF) {
2193 :
2194 0 : int temp = 0;
2195 :
2196 : // Simon: Complex fenestration state works only with tarcog
2197 0 : WindowComplexManager::CalcComplexWindowThermal(
2198 : state, SurfNum, temp, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp, SurfOutsideEmiss, DataBSDFWindow::Condition::Invalid);
2199 :
2200 0 : auto const &constr = state.dataConstruction->Construct(ConstrNum);
2201 0 : wm->ngllayer = constr.TotSolidLayers; // Simon: This is necessary to keep for frame calculations
2202 : // Simon: need to transfer surface temperatures because of frames calculation
2203 :
2204 0 : for (int i = 1; i <= 2 * constr.TotSolidLayers; ++i) {
2205 0 : wm->thetas[i - 1] = surfWin.thetaFace[i];
2206 : }
2207 0 : wm->hcout = HextConvCoeff;
2208 0 : wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
2209 0 : wm->tin = thisZoneHB.MAT + Constant::Kelvin; // Inside air temperature
2210 :
2211 : // This is code repeating and it is necessary to calculate report variables. Do not know
2212 : // how to solve this in more elegant way :(
2213 0 : if (surf.ExtWind) { // Window is exposed to wind (and possibly rain)
2214 0 : if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
2215 0 : wm->tout = s_surf->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
2216 : } else { // Dry
2217 0 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2218 : }
2219 : } else { // Window not exposed to wind
2220 0 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2221 : }
2222 :
2223 0 : wm->Ebout = Constant::StefanBoltzmann * pow_4(wm->tout);
2224 0 : wm->Outir =
2225 0 : surf.ViewFactorSkyIR * (s_surf->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(state.dataEnvrn->SkyTempKelvin) +
2226 0 : (1.0 - s_surf->SurfAirSkyRadSplit(SurfNum)) * wm->Ebout) +
2227 0 : surf.ViewFactorGroundIR * wm->Ebout;
2228 :
2229 88247 : } else if (s_surf->SurfWinWindowModelType(SurfNum) == WindowModel::EQL) {
2230 :
2231 2352 : WindowEquivalentLayer::EQLWindowSurfaceHeatBalance(
2232 : state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp, SurfOutsideEmiss, DataBSDFWindow::Condition::Invalid);
2233 2352 : wm->hcout = HextConvCoeff;
2234 : // Required for report variables calculations.
2235 2352 : if (surf.ExtWind) { // Window is exposed to wind (and possibly rain)
2236 2352 : if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
2237 0 : wm->tout = s_surf->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
2238 : } else { // Dry
2239 2352 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2240 : }
2241 : } else { // Window not exposed to wind
2242 0 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2243 : }
2244 :
2245 : } else { // regular window, not BSDF, not EQL Window
2246 : // Added for thermochromic windows
2247 85895 : auto const &constr = state.dataConstruction->Construct(ConstrNum);
2248 85895 : wm->locTCFlag = (constr.isTCWindow);
2249 :
2250 85895 : if (wm->locTCFlag) {
2251 0 : locTCSpecTemp = constr.specTemp;
2252 0 : s_surf->SurfWinSpecTemp(SurfNum) = locTCSpecTemp;
2253 : // Check to see whether needs to switch to a new TC window construction
2254 0 : locTCLayerTemp = s_surf->SurfWinTCLayerTemp(SurfNum);
2255 0 : Real64 dT0 = std::abs(locTCLayerTemp - locTCSpecTemp);
2256 0 : if (dT0 >= 1) {
2257 :
2258 : // Find the TC construction that is closed to the TCLayerTemp
2259 0 : auto const &constrTCMaster = state.dataConstruction->Construct(constr.TCMasterConstrNum);
2260 :
2261 0 : for (int iTCConstr = 1; iTCConstr <= constrTCMaster.numTCChildConstrs; ++iTCConstr) {
2262 0 : Real64 dT1 = std::abs(locTCLayerTemp - constrTCMaster.TCChildConstrs(iTCConstr).specTemp);
2263 :
2264 0 : if (dT1 < dT0) {
2265 0 : surf.Construction = s_surf->SurfActiveConstruction(SurfNum) = constrTCMaster.TCChildConstrs(iTCConstr).constrNum;
2266 0 : s_surf->SurfWinSpecTemp(SurfNum) = constrTCMaster.TCChildConstrs(iTCConstr).specTemp;
2267 0 : dT0 = dT1;
2268 : }
2269 : }
2270 : }
2271 : }
2272 : // end new TC code
2273 :
2274 85895 : TotGlassLay = constr.TotGlassLayers;
2275 85895 : wm->ngllayer = TotGlassLay;
2276 85895 : wm->nglface = 2 * wm->ngllayer;
2277 85895 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
2278 85895 : wm->tilt = surf.Tilt;
2279 85895 : wm->tiltr = wm->tilt * Constant::DegToRad;
2280 85895 : SurfNumAdj = surf.ExtBoundCond;
2281 85895 : wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum); // Room-side surface convective film conductance
2282 85895 : Real64 RefAirTemp = s_surf->Surface(SurfNum).getInsideAirTemperature(state, SurfNum);
2283 85895 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = RefAirTemp;
2284 85895 : wm->tin = RefAirTemp + Constant::Kelvin; // Inside air temperature
2285 :
2286 : // Reset hcin if necessary since too small a value sometimes causes non-convergence
2287 : // of window layer heat balance solution.
2288 85895 : if (s_surf->surfIntConv(SurfNum).model == Convect::HcInt::SetByZone) {
2289 : // may be redundant now, check is also in HeatBalanceConvectionCoeffs.cc
2290 85895 : if (wm->hcin <= state.dataHeatBal->LowHConvLimit) {
2291 : // hcin = 3.076d0 !BG this is rather high value and abrupt change. changed to set to lower limit
2292 101 : wm->hcin = state.dataHeatBal->LowHConvLimit;
2293 101 : state.dataHeatBalSurf->SurfHConvInt(SurfNum) = wm->hcin; // store for accurate reporting.
2294 : }
2295 : }
2296 :
2297 : // IR incident on window from zone surfaces and high-temp radiant sources
2298 85895 : wm->Rmir = s_surf->SurfWinIRfromParentZone(SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum);
2299 :
2300 : // Short-wave radiation (from interior and exterior solar and zone lights)
2301 : // absorbed at each face. Assumes equal split between faces of short-wave absorbed in glass layer.
2302 :
2303 195987 : for (int IGlass = 1; IGlass <= TotGlassLay; ++IGlass) {
2304 110092 : wm->AbsRadGlassFace[2 * IGlass - 2] = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, IGlass) / 2.0;
2305 110092 : wm->AbsRadGlassFace[2 * IGlass - 1] = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, IGlass) / 2.0;
2306 : }
2307 :
2308 : // IR from zone internal gains (lights, equipment and people) absorbed on zone-side face
2309 : // (assumes inside glass layer is opaque to IR, so no contribution to other layers)
2310 85895 : wm->AbsRadGlassFace[2 * TotGlassLay - 1] += state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNum);
2311 :
2312 : // Fill the layer properties needed for the thermal calculation.
2313 : // For switchable glazing it is assumed that thermal properties, such
2314 : // as surface emissivity, are the same for the unswitched and switched state,
2315 : // so the thermal properties of the unswitched state are used.
2316 : // For windows with a blind or shade it is assumed
2317 : // that the blind or shade does not affect the thermal properties of the glazing,
2318 : // so the thermal properties of the construction without the blind or shade are used.
2319 :
2320 : // The layer and face numbering are as follows (for the triple glazing case):
2321 : // Glass layers are 1,2 and 3, where 1 is the outside (outside environment facing)
2322 : // layer and 3 is the inside (room-facing) layer;
2323 : // Faces (also called surfaces) are 1,2,3,4,5 and 6, where face 1 is the
2324 : // outside (front) face of glass layer 1, face 2 is the inside (back)
2325 : // face of glass layer 1, face 3 is the outer face of glass layer 2, face 4 is the
2326 : // inner face of glass layer 2, etc.
2327 : // Gap layers are 1 and 2, where gap layer 1 is between glass layers 1 and 2
2328 : // and gap layer 2 is between glass layers 2 and 3.
2329 : // If an exterior, interior or between-glass blind or shade is in place, 7 and 8
2330 : // are the blind/shade faces, from outside to inside. If an exterior or interior
2331 : // blind/shade is in place, gap layer 3 is between the blind/shade and adjacent
2332 : // glass layer and is assumed to be air.
2333 : // Between-glass blind/shade is modeled only for double and triple glazing.
2334 : // For double glazing, gap 1 is between glass 1 and blind/shade and gap 2 is between
2335 : // blind/shade and glass 2.
2336 : // For triple glazing, the blind/shade is assumed to be between the inner two glass
2337 : // layers, i.e., between glass layers 2 and 3. In this case gap 1 is between glass 1
2338 : // and glass 2, gap 2 is between glass 2 and blind/shade, and gap 3 is between
2339 : // blind/shade and glass 3.
2340 :
2341 85895 : int IConst = surf.Construction;
2342 85895 : if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
2343 0 : IConst = s_surf->SurfWinActiveShadedConstruction(SurfNum);
2344 : }
2345 85895 : int TotLay = state.dataConstruction->Construct(IConst).TotLayers;
2346 85895 : int IGlass = 0;
2347 85895 : int IGap = 0;
2348 :
2349 : // Fill window layer properties needed for window layer heat balance calculation
2350 :
2351 220186 : for (int Lay = 1; Lay <= TotLay; ++Lay) {
2352 134291 : LayPtr = state.dataConstruction->Construct(IConst).LayerPoint(Lay);
2353 134291 : auto const *mat = s_mat->materials(LayPtr);
2354 :
2355 134291 : if (mat->group == Material::Group::Glass || mat->group == Material::Group::GlassSimple) {
2356 110092 : ++IGlass;
2357 110092 : auto const *matGlass = dynamic_cast<Material::MaterialFen const *>(mat);
2358 110092 : assert(matGlass != nullptr);
2359 110092 : wm->thick[IGlass - 1] = matGlass->Thickness;
2360 110092 : wm->scon[IGlass - 1] = matGlass->Conductivity / matGlass->Thickness;
2361 110092 : wm->emis[2 * IGlass - 2] = matGlass->AbsorpThermalFront;
2362 110092 : wm->emis[2 * IGlass - 1] = matGlass->AbsorpThermalBack;
2363 110092 : wm->tir[2 * IGlass - 2] = matGlass->TransThermal;
2364 110092 : wm->tir[2 * IGlass - 1] = matGlass->TransThermal;
2365 :
2366 134291 : } else if (mat->group == Material::Group::Shade || mat->group == Material::Group::Blind || mat->group == Material::Group::Screen) {
2367 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
2368 0 : ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers);
2369 : }
2370 0 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2371 0 : ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1);
2372 : }
2373 0 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
2374 0 : ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(3);
2375 0 : if (TotGlassLay == 3) {
2376 0 : ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(5);
2377 : }
2378 : }
2379 0 : auto const *matShade = dynamic_cast<Material::MaterialFen const *>(s_mat->materials(ShadeLayPtr));
2380 0 : assert(matShade != nullptr);
2381 :
2382 0 : if (ANY_SHADE_SCREEN(ShadeFlag)) {
2383 : // Shade or screen on
2384 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
2385 : // check to make sure the user hasn't messed up the shade control values
2386 0 : if (matShade->group == Material::Group::Blind) {
2387 0 : ShowSevereError(
2388 : state,
2389 0 : format("CalcWindowHeatBalance: ShadeFlag indicates Shade but Blind=\"{}\" is being used.", matShade->Name));
2390 0 : ShowContinueError(state, "This is most likely a fault of the EMS values for shading control.");
2391 0 : ShowFatalError(state, "Preceding condition terminates program.");
2392 : }
2393 : }
2394 0 : wm->thick[TotGlassLay] = matShade->Thickness;
2395 0 : wm->scon[TotGlassLay] = matShade->Conductivity / matShade->Thickness;
2396 :
2397 0 : if (ShadeFlag == WinShadingType::ExtScreen) {
2398 0 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(matShade);
2399 0 : assert(matScreen != nullptr);
2400 0 : wm->emis[wm->nglface] = matScreen->AbsorpThermalFront;
2401 0 : wm->tir[wm->nglface] = matScreen->DfTrans;
2402 0 : wm->tir[wm->nglface + 1] = matScreen->DfTrans;
2403 : } else {
2404 0 : wm->emis[wm->nglface] = matShade->AbsorpThermal;
2405 0 : wm->tir[wm->nglface] = matShade->TransThermal;
2406 0 : wm->tir[wm->nglface + 1] = matShade->TransThermal;
2407 : }
2408 0 : wm->emis[wm->nglface + 1] = matShade->AbsorpThermal;
2409 :
2410 : } else {
2411 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
2412 : // check to make sure the user hasn't messed up the shade control values
2413 0 : if (matShade->group == Material::Group::Shade || matShade->group == Material::Group::Screen) {
2414 0 : ShowSevereError(state,
2415 0 : format("CalcWindowHeatBalance: ShadeFlag indicates Blind but Shade/Screen=\"{}\" is being used.",
2416 0 : matShade->Name));
2417 0 : ShowContinueError(state, "This is most likely a fault of the EMS values for shading control.");
2418 0 : ShowFatalError(state, "Preceding condition terminates program.");
2419 : }
2420 : }
2421 :
2422 : // Blind on
2423 0 : auto &surfShade = s_surf->surfShades(SurfNum);
2424 0 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(surfShade.blind.matNum));
2425 0 : assert(matBlind != nullptr);
2426 0 : wm->thick[TotGlassLay] = matBlind->SlatThickness;
2427 0 : wm->scon[TotGlassLay] = matBlind->SlatConductivity / matBlind->SlatThickness;
2428 :
2429 0 : wm->emis[wm->nglface] = surfShade.blind.TAR.IR.Ft.Emi;
2430 0 : wm->emis[wm->nglface + 1] = surfShade.blind.TAR.IR.Bk.Emi;
2431 0 : wm->tir[wm->nglface] = surfShade.blind.TAR.IR.Ft.Tra;
2432 0 : wm->tir[wm->nglface + 1] = surfShade.blind.TAR.IR.Bk.Tra;
2433 : }
2434 :
2435 24199 : } else if (mat->group == Material::Group::Gas || mat->group == Material::Group::GasMixture) {
2436 24196 : ++IGap;
2437 24196 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(LayPtr));
2438 24196 : assert(matGas != nullptr);
2439 24196 : wm->gaps[IGap - 1].width = matGas->Thickness;
2440 24196 : wm->gaps[IGap - 1].numGases = matGas->numGases;
2441 48392 : for (int IMix = 0; IMix < wm->gaps[IGap - 1].numGases; ++IMix) {
2442 24196 : wm->gaps[IGap - 1].gases[IMix] = matGas->gases[IMix];
2443 24196 : wm->gaps[IGap - 1].gasFracts[IMix] = matGas->gasFracts[IMix];
2444 : }
2445 : }
2446 :
2447 : } // End of loop over glass, gap and blind/shade layers in a window construction
2448 :
2449 85895 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2450 : // Interior or exterior blind, shade or screen is on.
2451 : // Fill gap between blind/shade and adjacent glass with air properties.
2452 0 : ++IGap;
2453 0 : wm->gaps[IGap - 1].width = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(ShadeLayPtr))->toGlassDist;
2454 0 : wm->gaps[IGap - 1].numGases = 1;
2455 :
2456 0 : wm->gaps[IGap - 1].gases[0] = Material::gases[(int)Material::GasType::Air];
2457 0 : wm->gaps[IGap - 1].gasFracts[0] = 1;
2458 : }
2459 :
2460 : // Exterior convection coefficient, exterior air temperature and IR radiance
2461 : // of exterior surround. Depend on whether window is interzone (in an interzone
2462 : // wall or exterior (in an exterior wall).
2463 :
2464 85895 : wm->hcout = HextConvCoeff; // Exterior convection coefficient is passed in from outer routine
2465 : // tsky = SkyTemp + TKelvin
2466 :
2467 85895 : if (SurfNumAdj > 0) { // Interzone window
2468 :
2469 0 : RefAirTemp = s_surf->Surface(SurfNumAdj).getInsideAirTemperature(state, SurfNumAdj);
2470 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNumAdj) = RefAirTemp;
2471 0 : wm->tout = RefAirTemp + Constant::Kelvin; // outside air temperature
2472 :
2473 : // Add long-wave radiation from adjacent zone absorbed by glass layer closest to the adjacent zone.
2474 0 : wm->AbsRadGlassFace[0] += state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNumAdj);
2475 :
2476 : // The IR radiance of this window's "exterior" surround is the IR radiance
2477 : // from surfaces and high-temp radiant sources in the adjacent zone
2478 :
2479 0 : wm->Outir = s_surf->SurfWinIRfromParentZone(SurfNumAdj) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNumAdj);
2480 :
2481 : } else { // Exterior window (Ext BoundCond = 0)
2482 : // Calculate LWR from surrounding surfaces if defined for an exterior window
2483 85895 : OutSrdIR = 0;
2484 85895 : if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
2485 1 : if (s_surf->Surface(SurfNum).SurfHasSurroundingSurfProperty) {
2486 1 : SrdSurfTempAbs = surf.SrdSurfTemp + Constant::Kelvin;
2487 1 : OutSrdIR = Constant::StefanBoltzmann * surf.ViewFactorSrdSurfs * pow_4(SrdSurfTempAbs);
2488 : }
2489 : }
2490 85895 : if (surf.ExtWind) { // Window is exposed to wind (and possibly rain)
2491 85895 : if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
2492 0 : wm->tout = s_surf->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
2493 : } else { // Dry
2494 85895 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2495 : }
2496 : } else { // Window not exposed to wind
2497 0 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2498 : }
2499 85895 : wm->Ebout = Constant::StefanBoltzmann * pow_4(wm->tout);
2500 85895 : wm->Outir =
2501 85895 : surf.ViewFactorSkyIR * (s_surf->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(state.dataEnvrn->SkyTempKelvin) +
2502 85895 : (1.0 - s_surf->SurfAirSkyRadSplit(SurfNum)) * wm->Ebout) +
2503 85895 : surf.ViewFactorGroundIR * wm->Ebout + OutSrdIR;
2504 : }
2505 :
2506 : // Factors used in window layer temperature solution
2507 85895 : if (wm->ngllayer >= 2) {
2508 24197 : wm->A23P = -wm->emis[2] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
2509 24197 : wm->A32P = wm->emis[1] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
2510 24197 : wm->A23 = wm->emis[1] * Constant::StefanBoltzmann * wm->A23P;
2511 : }
2512 :
2513 85895 : if (wm->ngllayer >= 3) {
2514 0 : wm->A45P = -wm->emis[4] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
2515 0 : wm->A54P = wm->emis[3] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
2516 0 : wm->A45 = wm->emis[3] * Constant::StefanBoltzmann * wm->A45P;
2517 : }
2518 :
2519 85895 : if (wm->ngllayer == 4) {
2520 0 : wm->A67P = -wm->emis[6] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
2521 0 : wm->A76P = wm->emis[5] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
2522 0 : wm->A67 = wm->emis[5] * Constant::StefanBoltzmann * wm->A67P;
2523 : }
2524 :
2525 85895 : wm->thetas = {0.0};
2526 85895 : wm->thetasPrev = {0.0};
2527 :
2528 : // Calculate window face temperatures
2529 :
2530 85895 : SolveForWindowTemperatures(state, SurfNum);
2531 :
2532 : // Temperature difference across glass layers (for debugging)
2533 :
2534 85895 : dth1 = wm->thetas[1] - wm->thetas[0];
2535 85895 : dth2 = wm->thetas[3] - wm->thetas[2];
2536 85895 : dth3 = wm->thetas[5] - wm->thetas[4];
2537 85895 : dth4 = wm->thetas[7] - wm->thetas[6];
2538 :
2539 85895 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
2540 0 : auto const &surfShade = s_surf->surfShades(SurfNum);
2541 0 : SurfInsideTemp = wm->thetas[2 * wm->ngllayer + 1] - Constant::Kelvin;
2542 0 : EffShBlEmiss = surfShade.effShadeEmi;
2543 0 : EffGlEmiss = surfShade.effGlassEmi;
2544 :
2545 0 : s_surf->SurfWinEffInsSurfTemp(SurfNum) =
2546 0 : (EffShBlEmiss * SurfInsideTemp + EffGlEmiss * (wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin)) /
2547 0 : (EffShBlEmiss + EffGlEmiss);
2548 : } else {
2549 85895 : SurfInsideTemp = wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin;
2550 : }
2551 85895 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2552 0 : SurfOutsideTemp = wm->thetas[2 * wm->ngllayer] - Constant::Kelvin; // this index looks suspicious (CR 8202)
2553 : // SurfOutsideEmiss = emis(1) ! this index should be coordinated with previous line
2554 0 : SurfOutsideEmiss = wm->emis[2 * wm->ngllayer]; // fix for CR 8202
2555 : } else {
2556 85895 : SurfOutsideEmiss = wm->emis[0];
2557 85895 : SurfOutsideTemp = wm->thetas[0] - Constant::Kelvin;
2558 : }
2559 :
2560 : // Save temperatures for use next time step
2561 :
2562 306079 : for (int k = 1; k <= wm->nglfacep; ++k) {
2563 220184 : surfWin.thetaFace[k] = wm->thetas[k - 1];
2564 : }
2565 :
2566 : // Added TH 12/23/2008 for thermochromic windows to save the current TC layer temperature
2567 85895 : if (wm->locTCFlag) {
2568 0 : s_surf->SurfWinTCLayerTemp(SurfNum) =
2569 0 : (wm->thetas[2 * constr.TCGlassNum - 2] + wm->thetas[2 * constr.TCGlassNum - 1]) / 2 - Constant::Kelvin; // degree C
2570 : }
2571 : } // regular window, not BSDF, not EQL
2572 :
2573 : // Set condensation flag to 1 if condensation expected to occur on the innermost glass face,
2574 : // or, for airflow windows, on either or the two glass faces in the airflow gap
2575 88247 : if (!state.dataConstruction->Construct(surf.Construction).WindowTypeEQL) {
2576 85895 : InsideGlassTemp = wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin;
2577 85895 : RoomHumRat = thisZoneHB.airHumRat;
2578 85895 : RoomDewPoint = Psychrometrics::PsyTdpFnWPb(state, RoomHumRat, state.dataEnvrn->OutBaroPress);
2579 85895 : s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 0;
2580 85895 : if (InsideGlassTemp < RoomDewPoint) {
2581 21843 : s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
2582 : }
2583 : // If airflow window, is there condensation on either glass face of the airflow gap?
2584 85895 : if (s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
2585 0 : Tleft = wm->thetas[2 * wm->ngllayer - 3] - Constant::Kelvin;
2586 0 : Tright = wm->thetas[2 * wm->ngllayer - 2] - Constant::Kelvin;
2587 0 : if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
2588 0 : if (Tleft < RoomDewPoint || Tright < RoomDewPoint) {
2589 0 : s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
2590 : }
2591 0 : } else if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Outdoor) {
2592 0 : if (Tleft < state.dataEnvrn->OutDewPointTemp || Tright < state.dataEnvrn->OutDewPointTemp) {
2593 0 : s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
2594 : }
2595 : }
2596 : }
2597 :
2598 : // Do frame and divider calculation
2599 85895 : if (s_surf->SurfWinFrameArea(SurfNum) > 0.0 || s_surf->SurfWinDividerArea(SurfNum) > 0.0) {
2600 9 : CalcWinFrameAndDividerTemps(state, SurfNum, wm->tout, wm->tin, wm->hcout, wm->hcin, wm->Outir, ConstrNum);
2601 : }
2602 85895 : if (s_surf->SurfWinFrameArea(SurfNum) > 0.0) {
2603 9 : s_surf->SurfWinInsideFrameCondensationFlag(SurfNum) = 0;
2604 9 : if (s_surf->SurfWinFrameTempIn(SurfNum) < RoomDewPoint) {
2605 3 : s_surf->SurfWinInsideFrameCondensationFlag(SurfNum) = 1;
2606 : }
2607 : }
2608 85895 : if (s_surf->SurfWinDividerArea(SurfNum) > 0.0) {
2609 9 : s_surf->SurfWinInsideDividerCondensationFlag(SurfNum) = 0;
2610 9 : if (s_surf->SurfWinDividerTempIn(SurfNum) < RoomDewPoint) {
2611 3 : s_surf->SurfWinInsideDividerCondensationFlag(SurfNum) = 1;
2612 : }
2613 : }
2614 : }
2615 : // update exterior environment surface heat loss reporting
2616 88247 : Tsout = SurfOutsideTemp + Constant::Kelvin;
2617 88247 : state.dataHeatBalSurf->SurfQdotConvOutPerArea(SurfNum) = -wm->hcout * (Tsout - wm->tout);
2618 :
2619 88247 : Real64 const Tsout_4(pow_4(Tsout)); // Tuned To reduce pow calls and redundancies
2620 88247 : Real64 const Tout_4(pow_4(wm->tout));
2621 88247 : Real64 const emiss_sigma_product(SurfOutsideEmiss * Constant::StefanBoltzmann);
2622 88247 : Real64 rad_out_lw_srd_per_area = 0;
2623 :
2624 88247 : if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
2625 1 : if (surf.SurfHasSurroundingSurfProperty) {
2626 : // update SurfHSrdSurfExt if the windows has exterior shade or blind
2627 1 : state.dataHeatBalSurf->SurfHSrdSurfExt(SurfNum) =
2628 1 : Convect::SurroundingSurfacesRadCoeffAverage(state, SurfNum, Tsout, SurfOutsideEmiss);
2629 1 : rad_out_lw_srd_per_area = state.dataHeatBalSurf->SurfHSrdSurfExt(SurfNum) * (surf.SrdSurfTemp - SurfOutsideTemp);
2630 : }
2631 : }
2632 :
2633 : Real64 const rad_out_air_per_area =
2634 88247 : -emiss_sigma_product * (1.0 - s_surf->SurfAirSkyRadSplit(SurfNum)) * surf.ViewFactorSkyIR * (Tsout_4 - Tout_4);
2635 88247 : Real64 const rad_out_ground_per_area = -emiss_sigma_product * surf.ViewFactorGroundIR * (Tsout_4 - Tout_4);
2636 : Real64 const rad_out_sky_per_area =
2637 88247 : -emiss_sigma_product * s_surf->SurfAirSkyRadSplit(SurfNum) * surf.ViewFactorSkyIR * (Tsout_4 - pow_4(state.dataEnvrn->SkyTempKelvin));
2638 88247 : Real64 const rad_out_per_area = rad_out_air_per_area + rad_out_sky_per_area + rad_out_ground_per_area + rad_out_lw_srd_per_area;
2639 :
2640 88247 : state.dataHeatBalSurf->SurfHAirExt(SurfNum) = rad_out_air_per_area / (Tsout - wm->tout);
2641 88247 : state.dataHeatBalSurf->SurfQRadLWOutSrdSurfs(SurfNum) = rad_out_lw_srd_per_area;
2642 88247 : state.dataHeatBalSurf->SurfQdotRadOutRepPerArea(SurfNum) = rad_out_per_area;
2643 88247 : } // CalcWindowHeatBalanceInternalRoutines()
2644 :
2645 : //****************************************************************************
2646 :
2647 : //****************************************************************************
2648 :
2649 596 : void GetHeatBalanceEqCoefMatrixSimple(EnergyPlusData &state,
2650 : int const nglasslayer, // Number of glass layers
2651 : Array1D<Real64> const &hr, // Radiative conductance (W/m2-K)
2652 : Array1A<Real64> &hgap, // Gap gas conductive conductance (W/m2-K)
2653 : Array2D<Real64> &Aface, // Coefficient in equation Aface*thetas = Bface
2654 : Array1D<Real64> &Bface // Coefficient in equation Aface*thetas = Bface
2655 : )
2656 : {
2657 : Real64 gr; // Grashof number of gas in a gap
2658 : Real64 con; // Gap gas conductivity
2659 : Real64 pr; // Gap gas Prandtl number
2660 : Real64 nu; // Gap gas Nusselt number
2661 :
2662 596 : auto const &wm = state.dataWindowManager;
2663 :
2664 596 : if (nglasslayer == 1) {
2665 508 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2666 508 : Bface(2) = wm->Rmir * wm->emis[1] + wm->hcin * wm->tin + wm->AbsRadGlassFace[1];
2667 :
2668 508 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2669 508 : Aface(2, 1) = -wm->scon[0];
2670 508 : Aface(1, 2) = -wm->scon[0];
2671 508 : Aface(2, 2) = hr(2) + wm->scon[0] + wm->hcin;
2672 :
2673 88 : } else if (nglasslayer == 2) {
2674 88 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2675 88 : NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2676 88 : hgap(1) = con / wm->gaps[0].width * nu;
2677 :
2678 88 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2679 88 : Bface(2) = wm->AbsRadGlassFace[1];
2680 88 : Bface(3) = wm->AbsRadGlassFace[2];
2681 88 : Bface(4) = wm->Rmir * wm->emis[3] + wm->hcin * wm->tin + wm->AbsRadGlassFace[3];
2682 :
2683 88 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2684 88 : Aface(2, 1) = -wm->scon[0];
2685 :
2686 88 : Aface(1, 2) = -wm->scon[0];
2687 88 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2688 88 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2689 :
2690 88 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2691 88 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2692 88 : Aface(4, 3) = -wm->scon[1];
2693 :
2694 88 : Aface(3, 4) = -wm->scon[1];
2695 88 : Aface(4, 4) = hr(4) + wm->scon[1] + wm->hcin;
2696 :
2697 0 : } else if (nglasslayer == 3) {
2698 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2699 0 : NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2700 0 : hgap(1) = con / wm->gaps[0].width * nu;
2701 :
2702 0 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
2703 0 : NusseltNumber(state, 0, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
2704 0 : hgap(2) = con / wm->gaps[1].width * nu;
2705 :
2706 0 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2707 0 : Bface(2) = wm->AbsRadGlassFace[1];
2708 0 : Bface(3) = wm->AbsRadGlassFace[2];
2709 0 : Bface(4) = wm->AbsRadGlassFace[3];
2710 0 : Bface(5) = wm->AbsRadGlassFace[4];
2711 0 : Bface(6) = wm->Rmir * wm->emis[5] + wm->hcin * wm->tin + wm->AbsRadGlassFace[5];
2712 :
2713 0 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2714 0 : Aface(2, 1) = -wm->scon[0];
2715 :
2716 0 : Aface(1, 2) = -wm->scon[0];
2717 0 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2718 0 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2719 :
2720 0 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2721 0 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2722 0 : Aface(4, 3) = -wm->scon[1];
2723 :
2724 0 : Aface(3, 4) = -wm->scon[1];
2725 0 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
2726 0 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
2727 :
2728 0 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
2729 0 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
2730 0 : Aface(6, 5) = -wm->scon[2];
2731 :
2732 0 : Aface(5, 6) = -wm->scon[2];
2733 0 : Aface(6, 6) = hr(6) + wm->scon[2] + wm->hcin;
2734 :
2735 0 : } else if (nglasslayer == 4) {
2736 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2737 0 : NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2738 0 : hgap(1) = con / wm->gaps[0].width * nu;
2739 :
2740 0 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
2741 0 : NusseltNumber(state, 0, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
2742 0 : hgap(2) = con / wm->gaps[1].width * nu;
2743 :
2744 0 : WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
2745 0 : NusseltNumber(state, 0, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
2746 0 : hgap(3) = con / wm->gaps[2].width * nu;
2747 :
2748 0 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2749 0 : Bface(2) = wm->AbsRadGlassFace[1];
2750 0 : Bface(3) = wm->AbsRadGlassFace[2];
2751 0 : Bface(4) = wm->AbsRadGlassFace[3];
2752 0 : Bface(5) = wm->AbsRadGlassFace[4];
2753 0 : Bface(6) = wm->AbsRadGlassFace[5];
2754 0 : Bface(7) = wm->AbsRadGlassFace[6];
2755 0 : Bface(8) = wm->Rmir * wm->emis[7] + wm->hcin * wm->tin + wm->AbsRadGlassFace[7];
2756 :
2757 0 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2758 0 : Aface(2, 1) = -wm->scon[0];
2759 :
2760 0 : Aface(1, 2) = -wm->scon[0];
2761 0 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2762 0 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2763 :
2764 0 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2765 0 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2766 0 : Aface(4, 3) = -wm->scon[1];
2767 :
2768 0 : Aface(3, 4) = -wm->scon[1];
2769 0 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
2770 0 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
2771 :
2772 0 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
2773 0 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
2774 0 : Aface(6, 5) = -wm->scon[2];
2775 :
2776 0 : Aface(5, 6) = -wm->scon[2];
2777 0 : Aface(6, 6) = wm->scon[2] + hgap(3) - wm->A67P * hr(6);
2778 0 : Aface(7, 6) = -hgap(3) - wm->A76P * hr(7);
2779 :
2780 0 : Aface(6, 7) = -hgap(3) + wm->A67P * hr(6);
2781 0 : Aface(7, 7) = hgap(3) + wm->scon[3] + wm->A76P * hr(7);
2782 0 : Aface(8, 7) = -wm->scon[3];
2783 :
2784 0 : Aface(7, 8) = -wm->scon[3];
2785 0 : Aface(8, 8) = hr(8) + wm->scon[3] + wm->hcin;
2786 : }
2787 596 : } // GetHeatBalanceEqCoefMatrixSimple()
2788 :
2789 149363 : void GetHeatBalanceEqCoefMatrix(EnergyPlusData &state,
2790 : int const SurfNum,
2791 : int const nglasslayer,
2792 : WinShadingType const ShadeFlag,
2793 : Real64 const sconsh,
2794 : Real64 const TauShIR,
2795 : Real64 const EpsShIR1,
2796 : Real64 const EpsShIR2,
2797 : Real64 const RhoShIR1,
2798 : Real64 const RhoShIR2,
2799 : Real64 const ShGlReflFacIR,
2800 : Real64 const RhoGlIR1,
2801 : Real64 const RhoGlIR2,
2802 : Real64 const hcv, // Convection coefficient from gap glass or shade/blind to gap air (W/m2-K)
2803 : Real64 const TGapNew, // Current-iteration average air temp in airflow gap (K)
2804 : Real64 const TAirflowGapNew, // Average air temp in airflow gap between glass panes (K)
2805 : Real64 const hcvAirflowGap, // Convection coefficient from airflow gap glass to airflow gap air (W/m2-K)
2806 : Array1A<Real64> const &hcvBG, // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
2807 : Array1A<Real64> const &TGapNewBG,
2808 : Array1A<Real64> const &AbsRadShadeFace,
2809 : Array1D<Real64> const &hr,
2810 : Array2D<Real64> &Aface,
2811 : Array1D<Real64> &Bface)
2812 : {
2813 149363 : auto &wm = state.dataWindowManager;
2814 :
2815 : Real64 gr; // Grashof number of gas in a gap
2816 : Real64 con; // Gap gas conductivity
2817 : Real64 pr; // Gap gas Prandtl number
2818 : Real64 nu; // Gap gas Nusselt number
2819 :
2820 : Real64 FacRhoIR25; // Intermediate variable
2821 : Real64 FacRhoIR63; // Intermediate variable
2822 : Real64 RhoIRfp; // Intermediate variable
2823 : Real64 RhoIRbp; // Intermediate variable
2824 : Real64 FacRhoIR2fp; // Intermediate variable
2825 : Real64 FacRhoIR3bp; // Intermediate variable
2826 : Real64 FacRhoIR2fpRhoIR63; // Intermediate variable
2827 : Real64 FacRhoIR3bpRhoIR25; // Intermediate variable
2828 : Real64 FacRhoIR47; // Intermediate variable
2829 : Real64 FacRhoIR85; // Intermediate variable
2830 : Real64 FacRhoIR4fp; // Intermediate variable
2831 : Real64 FacRhoIR5bp; // Intermediate variable
2832 : Real64 FacRhoIR4fpRhoIR85; // Intermediate variable
2833 : Real64 FacRhoIR5bpRhoIR47; // Intermediate variable
2834 :
2835 149363 : Array1D<Real64> hgap(maxGlassLayers); // Gap gas conductance (W/m2-K)
2836 :
2837 149363 : auto &s_surf = state.dataSurface;
2838 :
2839 149363 : auto const &surfWin = s_surf->SurfaceWindow(SurfNum);
2840 :
2841 149363 : if (nglasslayer == 1) {
2842 109093 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2843 109093 : Bface(2) = wm->Rmir * wm->emis[1] + wm->hcin * wm->tin + wm->AbsRadGlassFace[1];
2844 :
2845 109093 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2846 109093 : Aface(2, 1) = -wm->scon[0];
2847 109093 : Aface(1, 2) = -wm->scon[0];
2848 109093 : Aface(2, 2) = hr(2) + wm->scon[0] + wm->hcin;
2849 :
2850 109093 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
2851 : // interior shade, single pane
2852 : // || ||
2853 : // outside 1||2 3||4
2854 : // || ||
2855 : // gl bl/sh/sc
2856 0 : Bface(2) = wm->Rmir * wm->emis[1] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[1];
2857 0 : Bface(3) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
2858 0 : Bface(4) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
2859 :
2860 0 : Aface(2, 2) = hr(2) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[0] + hcv;
2861 0 : Aface(3, 2) = -wm->emis[1] * hr(3) / ShGlReflFacIR;
2862 0 : Aface(2, 3) = -hr(2) * EpsShIR1 / ShGlReflFacIR;
2863 0 : Aface(3, 3) = hr(3) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
2864 0 : Aface(4, 3) = -sconsh;
2865 0 : Aface(3, 4) = -sconsh;
2866 0 : Aface(4, 4) = hr(4) + sconsh + wm->hcin;
2867 : }
2868 :
2869 109093 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2870 : // exterior shade, single pane
2871 : // || ||
2872 : // outside 3||4 1||2
2873 : // || ||
2874 : // bl/sh/sc gl
2875 0 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
2876 0 : Bface(3) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
2877 0 : Bface(4) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
2878 :
2879 0 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
2880 0 : Aface(4, 1) = -wm->emis[0] * hr(4) / ShGlReflFacIR;
2881 0 : Aface(3, 3) = hr(3) + sconsh + wm->hcout;
2882 0 : Aface(4, 3) = -sconsh;
2883 0 : Aface(1, 4) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
2884 0 : Aface(3, 4) = -sconsh;
2885 0 : Aface(4, 4) = hr(4) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
2886 : }
2887 :
2888 40270 : } else if (nglasslayer == 2) {
2889 40270 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2890 40270 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2891 40270 : hgap(1) = con / wm->gaps[0].width * nu;
2892 40270 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
2893 0 : wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
2894 0 : hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
2895 : }
2896 :
2897 40270 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2898 40270 : Bface(2) = wm->AbsRadGlassFace[1];
2899 40270 : Bface(3) = wm->AbsRadGlassFace[2];
2900 40270 : Bface(4) = wm->Rmir * wm->emis[3] + wm->hcin * wm->tin + wm->AbsRadGlassFace[3];
2901 :
2902 40270 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2903 40270 : Aface(2, 1) = -wm->scon[0];
2904 :
2905 40270 : Aface(1, 2) = -wm->scon[0];
2906 40270 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2907 40270 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2908 :
2909 40270 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2910 40270 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2911 40270 : Aface(4, 3) = -wm->scon[1];
2912 :
2913 40270 : Aface(3, 4) = -wm->scon[1];
2914 40270 : Aface(4, 4) = hr(4) + wm->scon[1] + wm->hcin;
2915 :
2916 40270 : if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
2917 0 : Bface(2) = wm->AbsRadGlassFace[1] + hcvAirflowGap * TAirflowGapNew;
2918 0 : Bface(3) = wm->AbsRadGlassFace[2] + hcvAirflowGap * TAirflowGapNew;
2919 0 : Aface(2, 2) = wm->scon[0] + hcvAirflowGap - wm->A23P * hr(2);
2920 0 : Aface(3, 2) = -wm->A32P * hr(3);
2921 0 : Aface(2, 3) = wm->A23P * hr(2);
2922 0 : Aface(3, 3) = hcvAirflowGap + wm->scon[1] + wm->A32P * hr(3);
2923 : }
2924 :
2925 40270 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
2926 0 : Bface(4) = wm->Rmir * wm->emis[3] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[3];
2927 0 : Bface(5) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
2928 0 : Bface(6) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
2929 :
2930 0 : Aface(4, 4) = hr(4) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[1] + hcv;
2931 0 : Aface(5, 4) = -wm->emis[3] * hr(5) / ShGlReflFacIR;
2932 0 : Aface(4, 5) = -hr(4) * EpsShIR1 / ShGlReflFacIR;
2933 0 : Aface(5, 5) = hr(5) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
2934 0 : Aface(6, 5) = -sconsh;
2935 0 : Aface(5, 6) = -sconsh;
2936 0 : Aface(6, 6) = hr(6) + sconsh + wm->hcin;
2937 : }
2938 :
2939 40270 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2940 0 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
2941 0 : Bface(5) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
2942 0 : Bface(6) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
2943 :
2944 0 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
2945 0 : Aface(6, 1) = -wm->emis[0] * hr(6) / ShGlReflFacIR;
2946 0 : Aface(5, 5) = hr(5) + sconsh + wm->hcout;
2947 0 : Aface(6, 5) = -sconsh;
2948 0 : Aface(1, 6) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
2949 0 : Aface(5, 6) = -sconsh;
2950 0 : Aface(6, 6) = hr(6) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
2951 : }
2952 :
2953 40270 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
2954 0 : Array1D<Real64> RhoIR(6); // Face IR reflectance
2955 :
2956 0 : for (int i = 1; i <= 6; ++i) {
2957 0 : RhoIR(i) = max(0.0, 1.0 - wm->tir[i - 1] - wm->emis[i - 1]);
2958 : }
2959 0 : FacRhoIR25 = 1.0 - RhoIR(2) * RhoIR(5);
2960 0 : FacRhoIR63 = 1.0 - RhoIR(6) * RhoIR(3);
2961 0 : Real64 const tir_5_squared(pow_2(wm->tir[4]));
2962 0 : RhoIRfp = RhoIR(5) + tir_5_squared * RhoIR(3) / FacRhoIR63;
2963 0 : RhoIRbp = RhoIR(6) + tir_5_squared * RhoIR(2) / FacRhoIR25;
2964 0 : FacRhoIR2fp = 1.0 - RhoIRfp * RhoIR(2);
2965 0 : FacRhoIR3bp = 1.0 - RhoIRbp * RhoIR(3);
2966 0 : FacRhoIR2fpRhoIR63 = FacRhoIR2fp * FacRhoIR63;
2967 0 : FacRhoIR3bpRhoIR25 = FacRhoIR3bp * FacRhoIR25;
2968 0 : Aface(2, 2) = wm->scon[0] + hcvBG(1) + hr(2) * (1 - RhoIRfp * (wm->emis[1] + RhoIR(2))) / FacRhoIR2fp;
2969 0 : Aface(3, 2) = -wm->emis[1] * hr(3) * wm->tir[4] / FacRhoIR2fpRhoIR63;
2970 0 : Aface(5, 2) = -wm->emis[1] * hr(5) / FacRhoIR2fp;
2971 0 : Aface(6, 2) = -wm->emis[1] * hr(6) * RhoIR(3) * wm->tir[4] / FacRhoIR2fpRhoIR63;
2972 0 : Bface(2) = hcvBG(1) * TGapNewBG(1) + wm->AbsRadGlassFace[1];
2973 0 : Aface(2, 3) = -wm->emis[2] * hr(2) * wm->tir[4] / FacRhoIR3bpRhoIR25;
2974 0 : Aface(3, 3) = wm->scon[1] + hcvBG(2) + hr(3) * (1 - RhoIRbp * (wm->emis[2] + RhoIR(3))) / FacRhoIR3bp;
2975 0 : Aface(5, 3) = -wm->emis[2] * hr(5) * RhoIR(2) * wm->tir[4] / FacRhoIR3bpRhoIR25;
2976 0 : Aface(6, 3) = -wm->emis[2] * hr(6) / FacRhoIR3bp;
2977 0 : Bface(3) = hcvBG(2) * TGapNewBG(2) + wm->AbsRadGlassFace[2];
2978 0 : Aface(2, 5) = -wm->emis[4] * hr(2) / FacRhoIR2fp;
2979 0 : Aface(3, 5) = -hr(3) * wm->tir[4] * RhoIR(2) * wm->emis[4] / FacRhoIR2fpRhoIR63;
2980 0 : Aface(5, 5) = sconsh + hcvBG(1) + hr(5) * (1 - RhoIR(2) * wm->emis[4] / FacRhoIR2fp);
2981 0 : Aface(6, 5) = -sconsh - hr(6) * RhoIR(2) * wm->tir[4] * RhoIR(3) * wm->emis[4] / FacRhoIR2fpRhoIR63;
2982 0 : Bface(5) = hcvBG(1) * TGapNewBG(1) + AbsRadShadeFace(1);
2983 0 : Aface(2, 6) = -hr(2) * wm->tir[4] * RhoIR(3) * wm->emis[5] / FacRhoIR3bpRhoIR25;
2984 0 : Aface(3, 6) = -wm->emis[5] * hr(3) / FacRhoIR3bp;
2985 0 : Aface(5, 6) = -sconsh - hr(5) * RhoIR(3) * wm->tir[4] * RhoIR(2) * wm->emis[5] / FacRhoIR3bpRhoIR25;
2986 0 : Aface(6, 6) = sconsh + hcvBG(2) + hr(6) * (1 - RhoIR(3) * wm->emis[5] / FacRhoIR3bp);
2987 0 : Bface(6) = hcvBG(2) * TGapNewBG(2) + AbsRadShadeFace(2);
2988 0 : }
2989 :
2990 0 : } else if (nglasslayer == 3) {
2991 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2992 0 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2993 0 : hgap(1) = con / wm->gaps[0].width * nu;
2994 0 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
2995 0 : wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
2996 0 : hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
2997 : }
2998 :
2999 0 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
3000 0 : NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
3001 0 : hgap(2) = con / wm->gaps[1].width * nu;
3002 0 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3003 0 : wm->hrgap[1] = 0.5 * std::abs(wm->A45) * pow_3(wm->thetas[3] + wm->thetas[4]);
3004 0 : hgap(2) = hgap(2) * surfWin.edgeGlassCorrFac + wm->hrgap[1] * (surfWin.edgeGlassCorrFac - 1.0);
3005 : }
3006 :
3007 0 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
3008 0 : Bface(2) = wm->AbsRadGlassFace[1];
3009 0 : Bface(3) = wm->AbsRadGlassFace[2];
3010 0 : Bface(4) = wm->AbsRadGlassFace[3];
3011 0 : Bface(5) = wm->AbsRadGlassFace[4];
3012 0 : Bface(6) = wm->Rmir * wm->emis[5] + wm->hcin * wm->tin + wm->AbsRadGlassFace[5];
3013 :
3014 0 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
3015 0 : Aface(2, 1) = -wm->scon[0];
3016 :
3017 0 : Aface(1, 2) = -wm->scon[0];
3018 0 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
3019 0 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
3020 :
3021 0 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
3022 0 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
3023 0 : Aface(4, 3) = -wm->scon[1];
3024 :
3025 0 : Aface(3, 4) = -wm->scon[1];
3026 0 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
3027 0 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
3028 :
3029 0 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
3030 0 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
3031 0 : Aface(6, 5) = -wm->scon[2];
3032 :
3033 0 : Aface(5, 6) = -wm->scon[2];
3034 0 : Aface(6, 6) = hr(6) + wm->scon[2] + wm->hcin;
3035 :
3036 0 : if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
3037 0 : Bface(4) = wm->AbsRadGlassFace[3] + hcvAirflowGap * TAirflowGapNew;
3038 0 : Bface(5) = wm->AbsRadGlassFace[4] + hcvAirflowGap * TAirflowGapNew;
3039 0 : Aface(4, 4) = wm->scon[1] + hcvAirflowGap - wm->A45P * hr(4);
3040 0 : Aface(5, 4) = -wm->A54P * hr(5);
3041 0 : Aface(4, 5) = wm->A45P * hr(4);
3042 0 : Aface(5, 5) = hcvAirflowGap + wm->scon[2] + wm->A54P * hr(5);
3043 : }
3044 :
3045 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3046 0 : Bface(6) = wm->Rmir * wm->emis[5] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[5];
3047 0 : Bface(7) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
3048 0 : Bface(8) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
3049 :
3050 0 : Aface(6, 6) = hr(6) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[2] + hcv;
3051 0 : Aface(7, 6) = -wm->emis[5] * hr(7) / ShGlReflFacIR;
3052 0 : Aface(6, 7) = -hr(6) * EpsShIR1 / ShGlReflFacIR;
3053 0 : Aface(7, 7) = hr(7) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
3054 0 : Aface(8, 7) = -sconsh;
3055 0 : Aface(7, 8) = -sconsh;
3056 0 : Aface(8, 8) = hr(8) + sconsh + wm->hcin;
3057 0 : } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
3058 0 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
3059 0 : Bface(7) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
3060 0 : Bface(8) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
3061 :
3062 0 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
3063 0 : Aface(8, 1) = -wm->emis[0] * hr(8) / ShGlReflFacIR;
3064 0 : Aface(7, 7) = hr(7) + sconsh + wm->hcout;
3065 0 : Aface(8, 7) = -sconsh;
3066 0 : Aface(1, 8) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
3067 0 : Aface(7, 8) = -sconsh;
3068 0 : Aface(8, 8) = hr(8) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
3069 0 : } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
3070 0 : Array1D<Real64> RhoIR(8); // Face IR reflectance
3071 0 : for (int i = 1; i <= 8; ++i) {
3072 0 : RhoIR(i) = max(0.0, 1.0 - wm->tir[i - 1] - wm->emis[i - 1]);
3073 : }
3074 0 : FacRhoIR47 = 1 - RhoIR(4) * RhoIR(7);
3075 0 : FacRhoIR85 = 1 - RhoIR(8) * RhoIR(5);
3076 0 : Real64 const tir_7_squared(pow_2(wm->tir[6]));
3077 0 : RhoIRfp = RhoIR(7) + tir_7_squared * RhoIR(5) / FacRhoIR85;
3078 0 : RhoIRbp = RhoIR(8) + tir_7_squared * RhoIR(4) / FacRhoIR47;
3079 0 : FacRhoIR4fp = 1 - RhoIRfp * RhoIR(4);
3080 0 : FacRhoIR5bp = 1 - RhoIRbp * RhoIR(5);
3081 0 : FacRhoIR4fpRhoIR85 = FacRhoIR4fp * FacRhoIR85;
3082 0 : FacRhoIR5bpRhoIR47 = FacRhoIR5bp * FacRhoIR47;
3083 0 : Aface(4, 4) = wm->scon[1] + hcvBG(1) + hr(4) * (1 - RhoIRfp * (wm->emis[3] + RhoIR(4))) / FacRhoIR4fp;
3084 0 : Aface(5, 4) = -wm->emis[3] * hr(5) * wm->tir[6] / FacRhoIR4fpRhoIR85;
3085 0 : Aface(7, 4) = -wm->emis[3] * hr(7) / FacRhoIR4fp;
3086 0 : Aface(8, 4) = -wm->emis[3] * hr(8) * RhoIR(5) * wm->tir[6] / FacRhoIR4fpRhoIR85;
3087 0 : Bface(4) = hcvBG(1) * TGapNewBG(1) + wm->AbsRadGlassFace[3];
3088 0 : Aface(4, 5) = -wm->emis[4] * hr(4) * wm->tir[6] / FacRhoIR5bpRhoIR47;
3089 0 : Aface(5, 5) = wm->scon[2] + hcvBG(2) + hr(5) * (1 - RhoIRbp * (wm->emis[4] + RhoIR(5))) / FacRhoIR5bp;
3090 0 : Aface(7, 5) = -wm->emis[4] * hr(7) * RhoIR(4) * wm->tir[6] / FacRhoIR5bpRhoIR47;
3091 0 : Aface(8, 5) = -wm->emis[4] * hr(8) / FacRhoIR5bp;
3092 0 : Bface(5) = hcvBG(2) * TGapNewBG(2) + wm->AbsRadGlassFace[4];
3093 0 : Aface(4, 7) = -wm->emis[6] * hr(4) / FacRhoIR4fp;
3094 0 : Aface(5, 7) = -hr(5) * wm->tir[6] * RhoIR(4) * wm->emis[6] / FacRhoIR4fpRhoIR85;
3095 0 : Aface(7, 7) = sconsh + hcvBG(1) + hr(7) * (1 - RhoIR(4) * wm->emis[6] / FacRhoIR4fp);
3096 0 : Aface(8, 7) = -sconsh - hr(8) * RhoIR(4) * wm->tir[6] * RhoIR(5) * wm->emis[6] / FacRhoIR4fpRhoIR85;
3097 0 : Bface(7) = hcvBG(1) * TGapNewBG(1) + AbsRadShadeFace(1);
3098 0 : Aface(4, 8) = -hr(4) * wm->tir[6] * RhoIR(5) * wm->emis[7] / FacRhoIR5bpRhoIR47;
3099 0 : Aface(5, 8) = -wm->emis[7] * hr(5) / FacRhoIR5bp;
3100 0 : Aface(7, 8) = -sconsh - hr(7) * RhoIR(5) * wm->tir[6] * RhoIR(4) * wm->emis[7] / FacRhoIR5bpRhoIR47;
3101 0 : Aface(8, 8) = sconsh + hcvBG(2) + hr(8) * (1 - RhoIR(5) * wm->emis[7] / FacRhoIR5bp);
3102 0 : Bface(8) = hcvBG(2) * TGapNewBG(2) + AbsRadShadeFace(2);
3103 0 : }
3104 :
3105 0 : } else if (nglasslayer == 4) {
3106 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
3107 0 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
3108 0 : hgap(1) = con / wm->gaps[0].width * nu;
3109 0 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3110 0 : wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
3111 0 : hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
3112 : }
3113 :
3114 0 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
3115 0 : NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
3116 0 : hgap(2) = con / wm->gaps[1].width * nu;
3117 0 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3118 0 : wm->hrgap[1] = 0.5 * std::abs(wm->A45) * pow_3(wm->thetas[3] + wm->thetas[4]);
3119 0 : hgap(2) = hgap(2) * surfWin.edgeGlassCorrFac + wm->hrgap[1] * (surfWin.edgeGlassCorrFac - 1.0);
3120 : }
3121 :
3122 0 : WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
3123 0 : NusseltNumber(state, SurfNum, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
3124 0 : hgap(3) = con / wm->gaps[2].width * nu;
3125 0 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3126 0 : wm->hrgap[2] = 0.5 * std::abs(wm->A67) * pow_3(wm->thetas[5] + wm->thetas[6]);
3127 0 : hgap(3) = hgap(3) * surfWin.edgeGlassCorrFac + wm->hrgap[2] * (surfWin.edgeGlassCorrFac - 1.0);
3128 : }
3129 0 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
3130 0 : Bface(2) = wm->AbsRadGlassFace[1];
3131 0 : Bface(3) = wm->AbsRadGlassFace[2];
3132 0 : Bface(4) = wm->AbsRadGlassFace[3];
3133 0 : Bface(5) = wm->AbsRadGlassFace[4];
3134 0 : Bface(6) = wm->AbsRadGlassFace[5];
3135 0 : Bface(7) = wm->AbsRadGlassFace[6];
3136 0 : Bface(8) = wm->Rmir * wm->emis[7] + wm->hcin * wm->tin + wm->AbsRadGlassFace[7];
3137 :
3138 0 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
3139 0 : Aface(2, 1) = -wm->scon[0];
3140 :
3141 0 : Aface(1, 2) = -wm->scon[0];
3142 0 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
3143 0 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
3144 :
3145 0 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
3146 0 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
3147 0 : Aface(4, 3) = -wm->scon[1];
3148 :
3149 0 : Aface(3, 4) = -wm->scon[1];
3150 0 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
3151 0 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
3152 :
3153 0 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
3154 0 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
3155 0 : Aface(6, 5) = -wm->scon[2];
3156 :
3157 0 : Aface(5, 6) = -wm->scon[2];
3158 0 : Aface(6, 6) = wm->scon[2] + hgap(3) - wm->A67P * hr(6);
3159 0 : Aface(7, 6) = -hgap(3) - wm->A76P * hr(7);
3160 :
3161 0 : Aface(6, 7) = -hgap(3) + wm->A67P * hr(6);
3162 0 : Aface(7, 7) = hgap(3) + wm->scon[3] + wm->A76P * hr(7);
3163 0 : Aface(8, 7) = -wm->scon[3];
3164 :
3165 0 : Aface(7, 8) = -wm->scon[3];
3166 0 : Aface(8, 8) = hr(8) + wm->scon[3] + wm->hcin;
3167 :
3168 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3169 0 : Bface(8) = wm->Rmir * wm->emis[7] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[7];
3170 0 : Bface(9) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
3171 0 : Bface(10) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
3172 :
3173 0 : Aface(8, 8) = hr(8) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[3] + hcv;
3174 0 : Aface(9, 8) = -wm->emis[7] * hr(9) / ShGlReflFacIR;
3175 0 : Aface(8, 9) = -hr(8) * EpsShIR1 / ShGlReflFacIR;
3176 0 : Aface(9, 9) = hr(9) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
3177 0 : Aface(10, 9) = -sconsh;
3178 0 : Aface(9, 10) = -sconsh;
3179 0 : Aface(10, 10) = hr(10) + sconsh + wm->hcin;
3180 : }
3181 :
3182 0 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
3183 0 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
3184 0 : Bface(9) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
3185 0 : Bface(10) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
3186 :
3187 0 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
3188 0 : Aface(10, 1) = -wm->emis[0] * hr(10) / ShGlReflFacIR;
3189 0 : Aface(9, 9) = hr(9) + sconsh + wm->hcout;
3190 0 : Aface(10, 9) = -sconsh;
3191 0 : Aface(1, 10) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
3192 0 : Aface(9, 10) = -sconsh;
3193 0 : Aface(10, 10) = hr(10) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
3194 : }
3195 :
3196 : } else {
3197 0 : ShowFatalError(state, format("SolveForWindowTemperatures: Invalid number of Glass Layers={}, up to 4 allowed.", wm->ngllayer));
3198 : }
3199 149363 : } // GetHeatBalanceEqCoefMatrix()
3200 :
3201 85895 : void SolveForWindowTemperatures(EnergyPlusData &state, int const SurfNum) // Surface number
3202 : {
3203 :
3204 : // SUBROUTINE INFORMATION:
3205 : // AUTHOR F. Winkelmann
3206 : // DATE WRITTEN July 2000
3207 : // MODIFIED Oct 2000, FW: modify edge-of-glass correction to account
3208 : // for gap radiative conductance affects
3209 : // Feb 2001, FW: add interior or exterior shade to layer
3210 : // heat balance calculation.
3211 : // Mar 2001, FW: relax error tolerance if MaxIterations reached.
3212 : // Jun 2001, FW: add interior or exterior blind
3213 : // Nov 2002, FW: add relaxation on face temperatures
3214 : // to improve convergence for multipane cases where outer pane
3215 : // has high solar absorptance: temp --> 0.5*(temp + previous temp);
3216 : // also, increase MaxIterations from 50 to 100.
3217 : // Dec 2002, FW: add between-glass shade/blind for double and triple glazing.
3218 : // Mar 2003, FW: remove redundant relaxation on radiative conductances
3219 : // Mar 2003, FW: increase convergence tolerance from 0.01 to 0.02 to enhance
3220 : // convergence in difficult cases.
3221 : // June 2003, FW: correct the expression for convective gain to zone air
3222 : // from airflow windows with airflow destination = InsideAir. Previously
3223 : // convective gain of air as it passed through gap was used, which is correct
3224 : // for airflow source = InsideAir but incorrect for airflow source = OutsideAir.
3225 : // Save SurfaceWindow%TAirflowGapOutlet for use in calculating convective heat
3226 : // gain to return air when airflow source = InsideAir, destination = ReturnAir.
3227 : // Dec 2003, FW: enhance converge for difficult cases by increasing relaxation
3228 : // in layer surface temperatures for iterations > MaxIterations/4
3229 : // May 2006, RR: add exterior window screen
3230 : // January 2009, BG: inserted call to recalc inside face convection inside iteration loop
3231 : // per ISO 15099 Section 8.3.2.2
3232 : // RE-ENGINEERED na
3233 :
3234 : // PURPOSE OF THIS SUBROUTINE:
3235 : // Evaluates the coefficients Aface and Bface in the system of linear
3236 : // algebraic equations
3237 : // Sum [Aface(i,j)*thetas(j)] = Bface(i), i = 1,nglfacep, j=1,nglfacep
3238 : // where
3239 : // nglface = number of glass faces (= 2 * number of glass layers), or, if shade or blind is present,
3240 : // nglgacep = number of glass faces + 2
3241 : // thetas(j) = temperature of face j
3242 : // If an interior, exterior or between-glass shade or blind, or exterior screen is present
3243 : // the face numbering is as follows:
3244 : // 1 to 2*nglface are glass faces, from outside to inside;
3245 : // 2*nglface+1 and 2*nglface+2 are the shade or blind faces, from outside to inside
3246 : // For example, the following diagram shows the face number for an exterior shade, screen or blind
3247 : // on double glazing:
3248 : // || || ||
3249 : // 5||6 1||2 3||4
3250 : // || || ||
3251 : // bl/sh/sc gl gl
3252 :
3253 : // And for a between-glass shade/blind in triple glazing:
3254 : // || || || ||
3255 : // 1||2 3||4 7||8 5||6
3256 : // || || || ||
3257 : // gl gl bl/sh gl
3258 :
3259 : // METHODOLOGY EMPLOYED:
3260 : // The Aface and Bface coefficients are determined by the equations for
3261 : // heat balance at the glass and shade/blind faces. The system of linear equations is solved
3262 : // by LU decomposition.
3263 :
3264 85895 : constexpr int MaxIterations(100); // Maximum allowed number of iterations (increased 9/01 from 15 to 50,
3265 : // increased 11/02 from 50 to 100)
3266 85895 : constexpr Real64 errtemptol(0.02); // Tolerance on errtemp for convergence (increased from 0.01, 3/4/03)
3267 :
3268 : int ZoneNum; // Zone number corresponding to SurfNum
3269 : int d; // +1 if number of row interchanges is even,
3270 : // -1 if odd (in LU decomposition
3271 :
3272 85895 : auto &wm = state.dataWindowManager;
3273 :
3274 85895 : int iter = 0; // Iteration number
3275 85895 : Real64 errtemp = 0.0; // Absolute value of sum of face temperature differences between iterations, divided by number of faces
3276 85895 : Real64 VGap = 0.0; // Air velocity in gap between glass and shade/blind (m/s)
3277 85895 : Real64 VAirflowGap = 0.0; // Air velocity in airflow gap between glass panes (m/s)
3278 85895 : Real64 VGapPrev = 0.0; // Value of VGap from previous iteration
3279 85895 : Real64 TGapNew = 0.0; // Average air temp in gap between glass and shade/blind (K)
3280 85895 : Real64 TAirflowGapNew = 0.0; // Average air temp in airflow gap between glass panes (K)
3281 85895 : Real64 TGapOutlet = 0.0; // Temperature of air leaving gap between glass and shade/blind (K)
3282 85895 : Real64 TAirflowGapOutlet = 0.0; // Temperature of air leaving airflow gap between glass panes (K)
3283 85895 : Real64 TAirflowGapOutletC = 0.0; // Temperature of air leaving airflow gap between glass panes (C)
3284 85895 : Real64 hcv = 0.0; // Convection coefficient from gap glass or shade/blind to gap air (W/m2-K)
3285 85895 : Real64 hcvAirflowGap = 0.0; // Convection coefficient from airflow gap glass to airflow gap air (W/m2-K)
3286 85895 : Real64 hcvPrev = 0.0; // Value of hcv from previous iteration
3287 85895 : Real64 ConvHeatFlowForced = 0.0; // Convective heat flow from forced airflow gap (W)
3288 85895 : Real64 ShGlReflFacIR = 0.0; // Factor for long-wave inter-reflection between shade/blind and adjacent glass
3289 85895 : Real64 RhoGlIR1 = 0.0; // Long-wave reflectance of glass surface facing shade/blind; 1=exterior shade/blind,
3290 85895 : Real64 RhoGlIR2 = 0.0;
3291 : // 2=exterior shade/blind
3292 85895 : Real64 EpsShIR1 = 0.0; // Long-wave emissivity of shade/blind surface facing glass; 1=interior shade/blind,
3293 85895 : Real64 EpsShIR2 = 0.0;
3294 : // 2=interior shade/blind
3295 85895 : Real64 RhoShIR1 = 0.0; // Long-wave reflectance of shade/blind surface facing glass; 1=interior shade/blind,
3296 85895 : Real64 RhoShIR2 = 0.0;
3297 : // 2=exterior shade/blind
3298 85895 : Real64 TauShIR = 0.0; // Long-wave transmittance of isolated shade/blind
3299 85895 : Real64 sconsh = 0.0; // shade/blind conductance (W/m2-K)
3300 :
3301 : // radiation from lights and zone equipment absorbed by faces of shade/blind (W/m2)
3302 85895 : Real64 ShadeArea = 0.0; // shade/blind area (m2)
3303 : // Real64 CondHeatGainGlass = 0.0; // Conduction through inner glass layer, outside to inside (W)
3304 : // Real64 CondHeatGainShade = 0.0; // Conduction through shade/blind, outside to inside (W)
3305 : // shade/blind is present. Zero if shade/blind has zero IR transmittance (W)
3306 : // Real64 IncidentSolar = 0.0; // Solar incident on outside of window (W)
3307 85895 : Real64 TotAirflowGap = 0.0; // Total volumetric airflow through window gap (m3/s)
3308 85895 : Real64 CpAirOutlet = 0.0; // Heat capacity of air from window gap (J/kg-K)
3309 85895 : Real64 CpAirZone = 0.0; // Heat capacity of zone air (J/kg-K)
3310 85895 : Real64 InletAirHumRat = 0.0; // Humidity ratio of air from window gap entering fan
3311 :
3312 85895 : Array1D<Real64> hr = Array1D<Real64>(2 * maxGlassLayers); // Radiative conductance (W/m2-K)
3313 85895 : Array1D<Real64> AbsRadShadeFace(2); // Solar radiation, short-wave radiation from lights, and long-wave
3314 85895 : Array1D<Real64> TGapNewBG(2); // For between-glass shade/blind, average gas temp in gaps on either
3315 : // side of shade/blind (K)
3316 85895 : Array1D<Real64> hcvBG(2); // For between-glass shade/blind, convection coefficient from gap glass or
3317 : // shade/blind to gap gas on either side of shade/blind (W/m2-K)
3318 :
3319 85895 : Array2D<Real64> Aface(2 * maxGlassLayers, 2 * maxGlassLayers); // Coefficient in equation Aface*thetas = Bface
3320 85895 : Array1D<Real64> Bface(2 * maxGlassLayers); // Coefficient in equation Aface*thetas = Bface
3321 85895 : Array1D_int indx(2 * maxGlassLayers); // Vector of row permutations in LU decomposition
3322 :
3323 85895 : auto &s_surf = state.dataSurface;
3324 :
3325 85895 : wm->nglfacep = wm->nglface;
3326 85895 : WinShadingType ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
3327 85895 : ZoneNum = s_surf->Surface(SurfNum).Zone;
3328 85895 : AbsRadShadeFace = 0.0;
3329 :
3330 85895 : if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
3331 0 : wm->nglfacep = wm->nglface + 2;
3332 0 : AbsRadShadeFace(1) = DataSurfaces::AbsFrontSide(state, SurfNum);
3333 0 : AbsRadShadeFace(2) = DataSurfaces::AbsBackSide(state, SurfNum);
3334 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3335 0 : AbsRadShadeFace(2) += s_surf->SurfWinIntLWAbsByShade(SurfNum);
3336 : }
3337 0 : sconsh = wm->scon[wm->ngllayer];
3338 0 : TauShIR = wm->tir[wm->nglface];
3339 0 : EpsShIR1 = wm->emis[wm->nglface];
3340 0 : EpsShIR2 = wm->emis[wm->nglface + 1];
3341 0 : RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1);
3342 0 : RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2);
3343 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3344 0 : RhoGlIR2 = 1.0 - wm->emis[2 * wm->ngllayer - 1];
3345 0 : ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1;
3346 0 : } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
3347 0 : RhoGlIR1 = 1.0 - wm->emis[0];
3348 0 : ShGlReflFacIR = 1.0 - RhoGlIR1 * RhoShIR2;
3349 : }
3350 : } // End of check if shade or blind is on
3351 :
3352 : // Initialize face temperatures.
3353 :
3354 85895 : StartingWindowTemps(state, SurfNum, AbsRadShadeFace);
3355 :
3356 85895 : hcvPrev = 0.0;
3357 85895 : VGapPrev = 0.0;
3358 :
3359 : // Calculate radiative conductances
3360 :
3361 85895 : errtemp = errtemptol * 2.0;
3362 :
3363 235258 : while (iter < MaxIterations && errtemp > errtemptol) {
3364 :
3365 528629 : for (int i = 1; i <= wm->nglfacep; ++i) {
3366 379266 : hr(i) = wm->emis[i - 1] * Constant::StefanBoltzmann * pow_3(wm->thetas[i - 1]);
3367 : // Following line is redundant since thetas is being relaxed;
3368 : // removed by FCW, 3/4/03
3369 : //! fw if ( iter >= 1 ) hr(i) = 0.5*(hrprev(i)+hr(i))
3370 : }
3371 :
3372 : // call for new interior film coeff (since it is temperature dependent) if using Detailed inside coef model
3373 149363 : if (((s_surf->surfIntConv(SurfNum).model == Convect::HcInt::SetByZone) &&
3374 169205 : (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo == Convect::HcInt::ASHRAETARP)) ||
3375 19842 : (s_surf->surfIntConv(SurfNum).model == Convect::HcInt::ASHRAETARP)) {
3376 : // coef model is "detailed" and not prescribed by user
3377 : // need to find inside face index, varies with shade/blind etc.
3378 : int InsideFaceIndex; // intermediate variable for index of inside face in thetas
3379 129521 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3380 0 : InsideFaceIndex = wm->nglfacep;
3381 : } else {
3382 129521 : InsideFaceIndex = wm->nglface;
3383 : }
3384 129521 : Convect::CalcISO15099WindowIntConvCoeff(
3385 129521 : state, SurfNum, wm->thetas[InsideFaceIndex - 1] - Constant::Kelvin, wm->tin - Constant::Kelvin);
3386 129521 : wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
3387 : }
3388 :
3389 149363 : Aface = 0.0;
3390 149363 : Bface = 0.0;
3391 :
3392 : // If interior or exterior shade or blind is present, get heat transfer
3393 : // coefficient from glass and shade/blind to gap between glass and shade/blind,
3394 : // effective gap air temperature, velocity of air in gap and gap outlet temperature.
3395 :
3396 149363 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag) || ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3397 0 : ExtOrIntShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNew, TGapOutlet, hcv, s_surf->SurfWinConvHeatFlowNatural(SurfNum));
3398 0 : if (iter >= 1) {
3399 0 : hcv = 0.5 * (hcvPrev + hcv);
3400 0 : VGap = 0.5 * (VGapPrev + VGap);
3401 : }
3402 0 : hcvPrev = hcv;
3403 0 : VGapPrev = VGap;
3404 : }
3405 :
3406 149363 : TAirflowGapOutlet = 0.0;
3407 : // If between-glass shade or blind is not present and this is an airflow window
3408 : // (i.e., with forced airflow in the gap for double glass or in the inner gap for triple glass)
3409 : // get glass-to-air forced convection heat transfer coefficient, average gap air temperature, and
3410 : // convective heat flow from gap.
3411 :
3412 149363 : if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
3413 0 : BetweenGlassForcedFlow(state, SurfNum, iter, VAirflowGap, TAirflowGapNew, TAirflowGapOutlet, hcvAirflowGap, ConvHeatFlowForced);
3414 : }
3415 :
3416 : // If between-glass shade or blind is present, get convective heat transfer
3417 : // coefficients from glass and shade/blind to the two gaps on either side of the shade/matBlind->
3418 : // Also get average gas temperature in the two gaps, and, for airflow window, the sum of the
3419 : // convective heat flows from the gaps.
3420 :
3421 149363 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
3422 0 : if (s_surf->SurfWinAirflowThisTS(SurfNum) == 0.0) { // Natural convection in gaps
3423 0 : BetweenGlassShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNewBG, hcvBG);
3424 : } else { // Forced convection in gaps
3425 0 : BetweenGlassShadeForcedFlow(state, SurfNum, iter, VGap, TGapNewBG, TAirflowGapOutlet, hcvBG, ConvHeatFlowForced);
3426 : }
3427 : }
3428 :
3429 149363 : ++iter;
3430 :
3431 : // Calculations based on number of glass layers
3432 298726 : GetHeatBalanceEqCoefMatrix(state,
3433 : SurfNum,
3434 149363 : wm->ngllayer,
3435 : ShadeFlag,
3436 : sconsh,
3437 : TauShIR,
3438 : EpsShIR1,
3439 : EpsShIR2,
3440 : RhoShIR1,
3441 : RhoShIR2,
3442 : ShGlReflFacIR,
3443 : RhoGlIR1,
3444 : RhoGlIR2,
3445 : hcv,
3446 : TGapNew,
3447 : TAirflowGapNew,
3448 : hcvAirflowGap,
3449 : hcvBG,
3450 : TGapNewBG,
3451 : AbsRadShadeFace,
3452 : hr,
3453 : Aface,
3454 : Bface);
3455 149363 : LUdecomposition(state, Aface, wm->nglfacep, indx, d); // Note that these routines change Aface;
3456 149363 : LUsolution(state, Aface, wm->nglfacep, indx, Bface); // face temperatures are returned in Bface
3457 :
3458 528629 : for (int i = 1; i <= wm->nglfacep; ++i) {
3459 379266 : wm->thetasPrev[i - 1] = wm->thetas[i - 1];
3460 379266 : if (iter < MaxIterations / 4) {
3461 379266 : wm->thetas[i - 1] = 0.5 * wm->thetas[i - 1] + 0.5 * Bface(i);
3462 : } else {
3463 0 : wm->thetas[i - 1] = 0.75 * wm->thetas[i - 1] + 0.25 * Bface(i);
3464 : }
3465 : }
3466 :
3467 149363 : errtemp = 0.0;
3468 528629 : for (int i = 1; i <= wm->nglfacep; ++i) {
3469 379266 : errtemp += std::abs(wm->thetas[i - 1] - wm->thetasPrev[i - 1]);
3470 : }
3471 149363 : errtemp /= wm->nglfacep;
3472 : }
3473 :
3474 85895 : s_surf->SurfWinWindowCalcIterationsRep(SurfNum) = iter;
3475 :
3476 : // We have reached iteration limit or we have converged. If we have reached the
3477 : // iteration limit the following test relaxes the convergence tolerance.
3478 : // If we have converged (errtemp <= errtemptol) the following test has not effect.
3479 :
3480 85895 : if (errtemp < 10 * errtemptol) {
3481 :
3482 : // Window heat balance solution has converged.
3483 :
3484 : // For interior shade, add convective gain from glass/shade gap air flow to zone convective gain;
3485 : // For all cases, get total window heat gain for reporting. See CalcWinFrameAndDividerTemps for
3486 : // contribution of frame and divider.
3487 : // IncidentSolar = s_surf->Surface(SurfNum).Area * state.dataHeatBal->SurfQRadSWOutIncident(SurfNum);
3488 85895 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3489 : // Interior shade or blind
3490 : // Window heat gain from glazing and shade/blind to zone. Consists of transmitted solar, convection
3491 : // from air exiting gap, convection from zone-side of shade/blind, net IR to zone from shade and net IR to
3492 : // zone from the glass adjacent to the shade/blind (zero if shade/blind IR transmittance is zero).
3493 : // Following assumes glazed area = window area (i.e., dividers ignored) in calculating
3494 : // IR to zone from glass when interior shade/blind is present.
3495 0 : ShadeArea = s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum);
3496 : // CondHeatGainShade = ShadeArea * sconsh *
3497 : // (wm->thetas(wm->nglfacep - 1) -
3498 : // wm->thetas[wm->nglfacep-1]);
3499 0 : s_surf->SurfWinGainIRShadeToZoneRep(SurfNum) =
3500 0 : ShadeArea * EpsShIR2 * (Constant::StefanBoltzmann * pow_4(wm->thetas[wm->nglfacep - 1]) - wm->Rmir) +
3501 0 : EpsShIR1 * (Constant::StefanBoltzmann * pow_4(wm->thetas[wm->nglfacep - 2]) - wm->Rmir) * RhoGlIR2 * TauShIR / ShGlReflFacIR;
3502 0 : s_surf->SurfWinGainIRGlazToZoneRep(SurfNum) = ShadeArea * (wm->emis[2 * wm->ngllayer - 1] * TauShIR / ShGlReflFacIR) *
3503 0 : (Constant::StefanBoltzmann * pow_4(wm->thetas[2 * wm->ngllayer - 1]) - wm->Rmir);
3504 0 : s_surf->SurfWinGainConvShadeToZoneRep(SurfNum) = ShadeArea * wm->hcin * (wm->thetas[wm->nglfacep - 1] - wm->tin);
3505 0 : s_surf->SurfWinHeatGain(SurfNum) = s_surf->SurfWinTransSolar(SurfNum) + s_surf->SurfWinConvHeatFlowNatural(SurfNum) +
3506 0 : s_surf->SurfWinGainConvShadeToZoneRep(SurfNum) + s_surf->SurfWinGainIRGlazToZoneRep(SurfNum) +
3507 0 : s_surf->SurfWinGainIRShadeToZoneRep(SurfNum);
3508 : } else {
3509 : // Interior shade or blind not present; innermost layer is glass
3510 : // CondHeatGainGlass = s_surf->Surface(SurfNum).Area * wm->scon(wm->ngllayer) *
3511 : // (wm->thetas(2 * wm->ngllayer - 1) -
3512 : // wm->thetas[2 * wm->ngllayer - 1]);
3513 171790 : s_surf->SurfWinGainIRGlazToZoneRep(SurfNum) = s_surf->Surface(SurfNum).Area * wm->emis[2 * wm->ngllayer - 1] *
3514 85895 : (Constant::StefanBoltzmann * pow_4(wm->thetas[2 * wm->ngllayer - 1]) - wm->Rmir);
3515 85895 : s_surf->SurfWinGainConvGlazToZoneRep(SurfNum) =
3516 85895 : s_surf->Surface(SurfNum).Area * wm->hcin * (wm->thetas[2 * wm->ngllayer - 1] - wm->tin);
3517 85895 : s_surf->SurfWinHeatGain(SurfNum) =
3518 85895 : s_surf->SurfWinTransSolar(SurfNum) + s_surf->SurfWinGainConvGlazToZoneRep(SurfNum) + s_surf->SurfWinGainIRGlazToZoneRep(SurfNum);
3519 : }
3520 :
3521 : // Add convective heat gain from airflow window
3522 : // Note: effect of fan heat on gap outlet temperature is neglected since fan power (based
3523 : // on pressure drop through the gap) is extremely small
3524 :
3525 85895 : s_surf->SurfWinGapConvHtFlowRep(SurfNum) = 0.0;
3526 85895 : s_surf->SurfWinGapConvHtFlowRepEnergy(SurfNum) = 0.0;
3527 85895 : TotAirflowGap = s_surf->SurfWinAirflowThisTS(SurfNum) * s_surf->Surface(SurfNum).Width;
3528 85895 : TAirflowGapOutletC = TAirflowGapOutlet - Constant::Kelvin;
3529 85895 : s_surf->SurfWinTAirflowGapOutlet(SurfNum) = TAirflowGapOutletC;
3530 85895 : if (s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
3531 0 : s_surf->SurfWinGapConvHtFlowRep(SurfNum) = ConvHeatFlowForced;
3532 0 : s_surf->SurfWinGapConvHtFlowRepEnergy(SurfNum) = s_surf->SurfWinGapConvHtFlowRep(SurfNum) * state.dataGlobal->TimeStepZoneSec;
3533 : // Add heat from gap airflow to zone air if destination is inside air; save the heat gain to return
3534 : // air in case it needs to be sent to the zone (due to no return air determined in HVAC simulation)
3535 0 : if (s_surf->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Indoor ||
3536 0 : s_surf->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Return) {
3537 0 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
3538 0 : if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
3539 0 : InletAirHumRat = thisZoneHB.airHumRat;
3540 : } else { // AirflowSource = outside air
3541 0 : InletAirHumRat = state.dataEnvrn->OutHumRat;
3542 : }
3543 0 : Real64 ZoneTemp = thisZoneHB.MAT; // this should be Tin (account for different reference temps)
3544 0 : CpAirOutlet = Psychrometrics::PsyCpAirFnW(InletAirHumRat);
3545 0 : CpAirZone = Psychrometrics::PsyCpAirFnW(thisZoneHB.airHumRat);
3546 0 : s_surf->SurfWinRetHeatGainToZoneAir(SurfNum) = TotAirflowGap * (CpAirOutlet * (TAirflowGapOutletC)-CpAirZone * ZoneTemp);
3547 0 : if (s_surf->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Indoor) {
3548 0 : s_surf->SurfWinHeatGain(SurfNum) += s_surf->SurfWinRetHeatGainToZoneAir(SurfNum);
3549 : }
3550 : }
3551 : // For AirflowDestination = ReturnAir in a controlled (i.e., conditioned) zone with return air, see CalcZoneLeavingConditions
3552 : // for calculation of modification of return-air temperature due to airflow from window gaps into return air.
3553 : }
3554 :
3555 : // Correct WinHeatGain for interior diffuse shortwave (solar and shortwave from lights) transmitted
3556 : // back out window
3557 85895 : int const ConstrNum = s_surf->SurfActiveConstruction(SurfNum);
3558 85895 : int const ConstrNumSh = s_surf->SurfWinActiveShadedConstruction(SurfNum);
3559 :
3560 85895 : Real64 reflDiff = 0.0; // Diffuse shortwave back reflectance
3561 85895 : if (NOT_SHADED(ShadeFlag)) {
3562 85895 : reflDiff = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack;
3563 0 : } else if (ANY_SHADE_SCREEN(ShadeFlag)) {
3564 0 : reflDiff = state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack;
3565 0 : } else if (ANY_BLIND(ShadeFlag)) {
3566 0 : auto const &surfShade = s_surf->surfShades(SurfNum);
3567 0 : auto const &constrSh = state.dataConstruction->Construct(ConstrNumSh);
3568 0 : reflDiff = Interp(constrSh.blindTARs[surfShade.blind.slatAngIdxLo].Sol.Bk.Df.Ref,
3569 0 : constrSh.blindTARs[surfShade.blind.slatAngIdxHi].Sol.Bk.Df.Ref,
3570 0 : surfShade.blind.slatAngInterpFac);
3571 0 : } else if (ShadeFlag == WinShadingType::SwitchableGlazing) {
3572 0 : reflDiff = InterpSw(s_surf->SurfWinSwitchingFactor(SurfNum),
3573 0 : state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack,
3574 0 : state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack);
3575 : }
3576 : // shouldn't this be + outward flowing fraction of absorbed SW? -- do not know whose comment this is? LKL (9/2012)
3577 85895 : s_surf->SurfWinLossSWZoneToOutWinRep(SurfNum) =
3578 85895 : state.dataHeatBal->EnclSolQSWRad(s_surf->Surface(SurfNum).SolarEnclIndex) * s_surf->Surface(SurfNum).Area * (1 - reflDiff) +
3579 85895 : state.dataHeatBalSurf->SurfWinInitialBeamSolInTrans(SurfNum);
3580 171790 : s_surf->SurfWinHeatGain(SurfNum) -= (s_surf->SurfWinLossSWZoneToOutWinRep(SurfNum) +
3581 85895 : state.dataHeatBalSurf->SurfWinInitialDifSolInTrans(SurfNum) * s_surf->Surface(SurfNum).Area);
3582 :
3583 85895 : if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
3584 0 : s_surf->SurfWinShadingAbsorbedSolar(SurfNum) =
3585 0 : (s_surf->SurfWinExtBeamAbsByShade(SurfNum) + s_surf->SurfWinExtDiffAbsByShade(SurfNum)) *
3586 0 : (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum));
3587 0 : s_surf->SurfWinShadingAbsorbedSolarEnergy(SurfNum) = s_surf->SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec;
3588 : }
3589 85895 : if (state.dataEnvrn->SunIsUp) {
3590 :
3591 42964 : s_surf->SurfWinSysSolTransmittance(SurfNum) =
3592 42964 : s_surf->SurfWinTransSolar(SurfNum) /
3593 42964 : (state.dataHeatBal->SurfQRadSWOutIncident(SurfNum) * (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum)) +
3594 : 0.0001);
3595 42964 : s_surf->SurfWinSysSolAbsorptance(SurfNum) =
3596 42964 : (state.dataHeatBal->SurfWinQRadSWwinAbsTot(SurfNum) + s_surf->SurfWinShadingAbsorbedSolar(SurfNum)) /
3597 42964 : (state.dataHeatBal->SurfQRadSWOutIncident(SurfNum) * (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum)) +
3598 : 0.0001);
3599 42964 : s_surf->SurfWinSysSolReflectance(SurfNum) =
3600 42964 : 1.0 - s_surf->SurfWinSysSolTransmittance(SurfNum) - s_surf->SurfWinSysSolAbsorptance(SurfNum);
3601 : } else {
3602 42931 : s_surf->SurfWinSysSolTransmittance(SurfNum) = 0.0;
3603 42931 : s_surf->SurfWinSysSolAbsorptance(SurfNum) = 0.0;
3604 42931 : s_surf->SurfWinSysSolReflectance(SurfNum) = 0.0;
3605 : }
3606 :
3607 : // Save hcv for use in divider calc with interior or exterior shade (see CalcWinFrameAndDividerTemps)
3608 85895 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
3609 0 : s_surf->SurfWinConvCoeffWithShade(SurfNum) = hcv;
3610 : }
3611 : } else {
3612 : // No convergence after MaxIterations even with relaxed error tolerance
3613 0 : ShowSevereError(state, format("Convergence error in SolveForWindowTemperatures for window {}", s_surf->Surface(SurfNum).Name));
3614 0 : ShowContinueErrorTimeStamp(state, "");
3615 :
3616 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3617 : // report out temperatures
3618 0 : for (int i = 1; i <= wm->nglfacep; ++i) {
3619 0 : ShowContinueError(state,
3620 0 : format("Glazing face index = {} ; new temperature ={:.4R}C ; previous temperature = {:.4R}C",
3621 : i,
3622 0 : wm->thetas[i - 1] - Constant::Kelvin,
3623 0 : wm->thetasPrev[i - 1] - Constant::Kelvin));
3624 : }
3625 : }
3626 :
3627 0 : ShowFatalError(
3628 : state,
3629 0 : format("Program halted because of convergence error in SolveForWindowTemperatures for window {}", s_surf->Surface(SurfNum).Name));
3630 : }
3631 85895 : } // SolveForWindowTemperatures()
3632 :
3633 : //****************************************************************************
3634 :
3635 0 : void ExtOrIntShadeNaturalFlow(EnergyPlusData &state,
3636 : int const SurfNum, // Surface number
3637 : int const iter, // Iteration number for glass heat balance calculation
3638 : Real64 &VGap, // Air velocity in glass-shade/blind gap (m/s)
3639 : Real64 &TGapNew, // Current-iteration average air temp in glass-shade/blind gap (K)
3640 : Real64 &TGapOutlet, // Temperature of air leaving glass-shade/blind gap at top for upward
3641 : Real64 &hcv, // Convection coefficient from gap glass or shade to gap air (W/m2-K)
3642 : Real64 &QConvGap // Convective heat gain from glass-shade/blind gap for interior shade (W)
3643 : )
3644 : {
3645 :
3646 : // SUBROUTINE INFORMATION:
3647 : // AUTHOR F. Winkelmann
3648 : // DATE WRITTEN December 2000
3649 : // MODIFIED June 2001: add window blinds
3650 : // May 2006 (RR): add exterior window screens
3651 : // RE-ENGINEERED na
3652 :
3653 : // PURPOSE OF THIS SUBROUTINE:
3654 : // Called by SolveForWindowTemperatures for windows that have an interior
3655 : // or exterior blind or shade in place.
3656 : // Solves for air flow in gap between glass and shade/blind.
3657 : // Finds temperature of gap air and coefficient for convective heat transfer
3658 : // from glass to gap air and shade/blind to gap air.
3659 :
3660 : // METHODOLOGY EMPLOYED:
3661 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
3662 : // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
3663 :
3664 : // SUBROUTINE ARGUMENT DEFINITIONS:
3665 : // air flow or bottom for downward air flow (K)
3666 :
3667 : int ConstrNumSh; // Shaded construction number
3668 : int MatNumSh; // Material number of shade/blind layer
3669 : int nglassfaces; // Number of glass faces in construction
3670 : Real64 TGapInlet; // Temperature of air entering glass-shade/blind gap at bottom for upward
3671 : // air flow or top for downward air flow (K)
3672 : Real64 TGlassFace; // Temperature of glass surface facing glass-shade/blind gap (K)
3673 : Real64 TShadeFace; // Temperature of shade surface facing glass-shade/blind gap (K)
3674 : Real64 hGapStill; // Still-air glass-shade/blind gap conduction/convection coeff (W/m2-K)
3675 : Real64 TGapOld; // Previous-iteration average air temp in glass-shade/blind gap (K)
3676 : Real64 GapHeight; // Vertical length of glass-shade/blind gap (m)
3677 : Real64 GapDepth; // Distance from shade to glass (m)
3678 : Real64 RhoAir; // Density of glass-shade/blind gap air at a temperature of TGapOld (kg/m3)
3679 : Real64 RhoTRef; // Density of glass-shade/blind air at reference temp = KelvinConv (kg/m3)
3680 : Real64 ViscAir; // Viscosity of glass-shade/blind gap air at a temperature of TGapOld (kg/m3)
3681 : Real64 AGap; // Cross sectional area of glass-shade/blind gap (m2); for vertical window, this
3682 : // is in horizontal plane normal to window.
3683 : Real64 ATopGap; // Area of the top and bottom openings (m2)
3684 : Real64 ABotGap;
3685 : Real64 ALeftGap; // Area of the left and right openings (m2)
3686 : Real64 ARightGap;
3687 : Real64 AHolesGap; // Area of the holes in the shade (assumed homogeneously
3688 : // distributed) (m2)
3689 : Real64 ATopLRH; // Intermediate variables
3690 : Real64 ABotLRH;
3691 : Real64 AEqInlet; // Equivalent inlet and outlet opening areas (m2)
3692 : Real64 AEqOutlet;
3693 : Real64 Zinlet; // Inlet and outlet pressure loss factors
3694 : Real64 Zoutlet;
3695 : Real64 AVGap; // Coeff. of VGap**2 term in pressure balance equation
3696 : Real64 BVGap; // Coeff. of VGap term in pressure balance equation
3697 : Real64 CVGap; // VGap-independent term in pressure balance equation
3698 : Real64 GapHeightChar; // Characteristic height of the gap air temperature profile (m)
3699 : Real64 TAve; // Average of TGlass and TShade (K)
3700 : // REAL(r64) :: AirProps(8) ! Air properties
3701 : int TotGaps; // Glass/glass gaps + glass-shade/blind gap
3702 : Real64 con; // Gap conductivity and derivative
3703 : Real64 gr; // glass-shade/blind gap Grashof number
3704 : Real64 pr; // glass-shade/blind gap Prandtl number
3705 : Real64 nu; // glass-shade/blind gap Nusselt number
3706 : WinShadingType ShadeFlag; // Shading flag
3707 :
3708 0 : auto &s_mat = state.dataMaterial;
3709 0 : auto &s_surf = state.dataSurface;
3710 0 : auto &wm = state.dataWindowManager;
3711 :
3712 0 : auto &surf = s_surf->Surface(SurfNum);
3713 :
3714 : // Air properties
3715 : // Dens dDens/dT Con dCon/dT Vis dVis/dT Prandtl dPrandtl/dT
3716 : // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72, 1.8d-3 /
3717 :
3718 0 : ConstrNumSh = s_surf->SurfWinActiveShadedConstruction(SurfNum);
3719 0 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
3720 0 : nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
3721 0 : TotGaps = state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
3722 :
3723 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { // Interior shade or blind
3724 0 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(nglassfaces);
3725 0 : TGapInlet = wm->tin;
3726 0 : TGlassFace = wm->thetas[nglassfaces - 1];
3727 0 : TShadeFace = wm->thetas[nglassfaces];
3728 : } else { // Exterior shade, screen or blind
3729 0 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1);
3730 0 : TGapInlet = wm->tout;
3731 0 : TGlassFace = wm->thetas[0];
3732 0 : TShadeFace = wm->thetas[nglassfaces + 1];
3733 : }
3734 0 : TAve = 0.5 * (TGlassFace + TShadeFace);
3735 :
3736 0 : if (iter == 0) {
3737 0 : TGapOld = 0.5 * (TAve + TGapInlet);
3738 : } else {
3739 0 : TGapOld = TGapNew;
3740 : }
3741 :
3742 : // Conductance of gap between glass and shade assuming gap is sealed
3743 0 : WindowGasConductance(state, TGlassFace, TShadeFace, TotGaps, con, pr, gr);
3744 0 : NusseltNumber(state, SurfNum, TGlassFace, TShadeFace, TotGaps, gr, pr, nu);
3745 0 : hGapStill = con / wm->gaps[TotGaps - 1].width * nu;
3746 :
3747 : // For near-horizontal windows (i.e., no more than 5 deg from horizontal) assume
3748 : // there is no air flow thru gap
3749 :
3750 0 : if (std::abs(surf.SinTilt) < 0.0872) {
3751 0 : VGap = 0.0;
3752 0 : hcv = 2.0 * hGapStill;
3753 0 : QConvGap = 0.0;
3754 0 : TGapNew = TAve;
3755 0 : TGapOutlet = TAve;
3756 0 : return;
3757 : }
3758 :
3759 0 : GapHeight = surf.Height;
3760 :
3761 0 : auto const *matShadingDevice = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(MatNumSh));
3762 0 : assert(matShadingDevice != nullptr);
3763 :
3764 0 : GapDepth = matShadingDevice->toGlassDist;
3765 0 : AGap = GapDepth * surf.Width;
3766 0 : ATopGap = matShadingDevice->topOpeningMult * AGap;
3767 0 : ABotGap = matShadingDevice->bottomOpeningMult * AGap;
3768 0 : ALeftGap = matShadingDevice->leftOpeningMult * GapHeight * GapDepth;
3769 0 : ARightGap = matShadingDevice->rightOpeningMult * GapHeight * GapDepth;
3770 : // For blinds, airFlowPermeability depends on slat angle which is a property of the surface, not the material
3771 0 : if (matShadingDevice->group == Material::Group::Blind) {
3772 0 : AHolesGap = s_surf->surfShades(SurfNum).blind.airFlowPermeability * GapHeight * surf.Width;
3773 : } else {
3774 0 : AHolesGap = matShadingDevice->airFlowPermeability * GapHeight * surf.Width;
3775 : }
3776 :
3777 0 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapOld - Constant::Kelvin);
3778 0 : ViscAir = wm->AirProps[4] + wm->AirProps[5] * (TGapOld - Constant::Kelvin);
3779 : // The factor 12 in the next line is based on the solution of steady laminar flow between fixed
3780 : // parallel plates given in Sec. 6.9.1 of Fundamentals of Fluid Mechanics, Munson/Young/Okishi, Third Edition
3781 : // Update, John Wiley & Sons, 1998; ISO 15099 has 8 for this factor, which is for flow through a tube.
3782 0 : BVGap = 12.0 * ViscAir * GapHeight / pow_2(GapDepth);
3783 : // Adding 0.000001 and 0.000002 in the following gives ATopLRH = ABotLRH =
3784 : // 0.25*(ALeftGap + ARightGap + AHolesGap) when ABotGap = ATopGap = 0.0 (shade/blind sealed at
3785 : // bottom and top but possibly open at left side, right side and/or in-shade/blind)
3786 0 : ATopLRH = 0.5 * ((ATopGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
3787 0 : ABotLRH = 0.5 * ((ABotGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
3788 0 : if (TGapOld > TGapInlet) {
3789 0 : AEqInlet = ABotGap + ATopLRH;
3790 0 : AEqOutlet = ATopGap + ABotLRH;
3791 : } else {
3792 0 : AEqOutlet = ABotGap + ATopLRH;
3793 0 : AEqInlet = ATopGap + ABotLRH;
3794 : }
3795 : // Adding 0.000001 in the following gives very large value of Zinlet for AEqInlet = 0 and
3796 : // very large value of Zoutlet for AEqInlet = 0; this gives VGap close to zero, as required
3797 : // when there is no inlet and/or outlet for air. This then reduces to the
3798 : // case of a completely sealed shade, in which hcv = 2*hGapStill and QConvGap = 0.
3799 0 : Zinlet = pow_2(AGap / (0.6 * AEqInlet + 0.000001) - 1.0);
3800 0 : Zoutlet = pow_2(AGap / (0.6 * AEqOutlet + 0.000001) - 1.0);
3801 0 : AVGap = 0.5 * RhoAir * (1 + Zinlet + Zoutlet);
3802 0 : RhoTRef = wm->AirProps[0] * Constant::Kelvin;
3803 0 : CVGap = RhoTRef * 9.81 * GapHeight * s_surf->Surface(SurfNum).SinTilt * (TGapOld - TGapInlet) / (TGapOld * TGapInlet);
3804 :
3805 : // Solution of quadratic equation in VGap
3806 0 : VGap = (std::sqrt(pow_2(BVGap) + std::abs(4.0 * AVGap * CVGap)) - BVGap) / (2.0 * AVGap);
3807 0 : hcv = 2.0 * hGapStill + 4.0 * VGap;
3808 0 : GapHeightChar = RhoAir * 1008.0 * GapDepth * VGap / (2.0 * hcv);
3809 : // The following avoids divide by zero and exponential underflow
3810 0 : if (GapHeightChar == 0.0) {
3811 0 : TGapOutlet = TAve;
3812 0 : } else if ((GapHeight / GapHeightChar) > 15.0) {
3813 0 : TGapOutlet = TAve;
3814 : } else {
3815 0 : TGapOutlet = TAve - (TAve - TGapInlet) * std::exp(-GapHeight / GapHeightChar);
3816 : }
3817 0 : TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet);
3818 :
3819 : // Convective heat flow from gap to room air for interior shade or blind
3820 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3821 0 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapNew - Constant::Kelvin);
3822 0 : QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet);
3823 : // Exclude convection to gap due to divider, if present; divider convection handled
3824 : // separately in CalcWinFrameAndDividerTemps
3825 0 : QConvGap *= 0.5 * (1.0 + s_surf->Surface(SurfNum).Area / (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum)));
3826 : }
3827 : }
3828 :
3829 : //****************************************************************************
3830 :
3831 0 : void BetweenGlassShadeNaturalFlow(EnergyPlusData &state,
3832 : int const SurfNum, // Surface number
3833 : int const iter, // Iteration number for glass heat balance calculation
3834 : Real64 &VGap, // Gas velocity in gaps (m/s)
3835 : Array1A<Real64> TGapNew, // Current-iteration average gas temp in gaps (K)
3836 : Array1A<Real64> hcv // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
3837 : )
3838 : {
3839 :
3840 : // SUBROUTINE INFORMATION:
3841 : // AUTHOR F. Winkelmann
3842 : // DATE WRITTEN December 2002
3843 : // MODIFIED na
3844 : // RE-ENGINEERED na
3845 :
3846 : // PURPOSE OF THIS SUBROUTINE:
3847 : // Called by SolveForWindowTemperatures for windows that have a
3848 : // between-glass shade or blind in place.
3849 : // Solves for gas flow in the two gaps on either side of shade/blind.
3850 : // Finds average temperature of gas in the two gaps, and the coefficient
3851 : // for convective heat transfer from glass to gap gas and shade/blind to gap gas
3852 : // for the two gaps. The two gaps are assumed to have the same depth so that the
3853 : // gas velocity due to natural convection is the same in the two gaps.
3854 : // The Between-glass shade/blind is between the two glass layers of double glazing
3855 : // or between the two inner glass layers of triple glazing. The quadruple glazing
3856 : // case is not considered.
3857 :
3858 : // METHODOLOGY EMPLOYED:
3859 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
3860 : // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
3861 :
3862 : // Argument array dimensioning
3863 0 : TGapNew.dim(2);
3864 0 : hcv.dim(2);
3865 :
3866 : int ConstrNumSh; // Shaded construction number
3867 : int MatNumSh; // Material number of shade/blind layer
3868 : // In the following, "gaps" refer to the gaps on either side of the shade/blind
3869 0 : Array1D<Real64> TGlassFace(2); // Temperature of glass surfaces facing gaps (K)
3870 0 : Array1D<Real64> TShadeFace(2); // Temperature of shade surfaces facing gaps (K)
3871 0 : Array1D<Real64> hGapStill(2); // Still-air conduction/convection coeffs for the gaps (W/m2-K)
3872 0 : Array1D<Real64> TGapOld(2); // Previous-iteration average gas temp in gaps (K)
3873 : Real64 GapHeight; // Vertical length of glass-shade/blind gap (m)
3874 : Real64 GapDepth; // Distance from shade/blind to glass; assumed same for both gaps (m)
3875 0 : Array1D<Real64> RhoGas(2); // Density of gap gas at a temperature of TGapOld (kg/m3)
3876 : Real64 RhoTRef; // Density of gap gas at reference temp = KelvinConvK (kg/m3)
3877 0 : Array1D<Real64> ViscGas(2); // Viscosity of gap gas at a temperature of TGapOld (kg/m3)
3878 : Real64 RhoGasZero; // Gas density at KelvinConvK
3879 : Real64 ViscGasZero; // Gas viscosity at KelvinConvK (not used)
3880 : Real64 AGap; // Cross sectional area of gaps (m2); for vertical window, this
3881 : // is in horizontal plane normal to window.
3882 : Real64 ATopGap; // Area of the top and bottom openings of shade/blind (m2)
3883 : Real64 ABotGap;
3884 : Real64 ALeftGap; // Area of the left and right openings of shade/blind (m2)
3885 : Real64 ARightGap;
3886 : Real64 AHolesGap; // Area of the holes in the shade/blind (assumed homogeneously
3887 : // distributed) (m2)
3888 : Real64 ATopLRH; // Intermediate variables
3889 : Real64 ABotLRH;
3890 : Real64 AEqInlet; // Equivalent inlet and outlet opening areas (m2)
3891 : Real64 AEqOutlet;
3892 : Real64 Zinlet; // Inlet and outlet pressure loss factors
3893 : Real64 Zoutlet;
3894 : Real64 AVGap; // Coeff. of VGap**2 term in pressure balance equation
3895 : Real64 BVGap; // Coeff. of VGap term in pressure balance equation
3896 : Real64 CVGap; // VGap-independent term in pressure balance equation
3897 0 : Array1D<Real64> GapHeightChar(2); // Characteristic height of the gap gas temperature profile (m)
3898 0 : Array1D<Real64> EpsChar(2); // EXP(-GapHeight/GapHeightChar(IGap))
3899 0 : Array1D<Real64> TAve(2); // Average of TGlass and TShade for the gaps (K)
3900 : Real64 con; // Gap gas conductivity and derivative
3901 : Real64 gr; // Gap gas Grashof number
3902 : Real64 pr; // Gap gas Prandtl number
3903 : Real64 nu; // Gap gas Nusselt number
3904 : WinShadingType ShadeFlag; // Shading flag
3905 : int IGapInc; // Gap increment (0 or 1)
3906 :
3907 0 : auto &wm = state.dataWindowManager;
3908 0 : auto &s_mat = state.dataMaterial;
3909 0 : auto &s_surf = state.dataSurface;
3910 :
3911 0 : auto &surf = s_surf->Surface(SurfNum);
3912 :
3913 0 : ConstrNumSh = surf.activeShadedConstruction;
3914 0 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
3915 :
3916 0 : if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double glazing
3917 0 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(3);
3918 0 : IGapInc = 0;
3919 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3920 0 : TGlassFace(IGap) = wm->thetas[IGap];
3921 0 : TShadeFace(IGap) = wm->thetas[IGap + 3];
3922 : }
3923 : } else { // Triple glazing
3924 0 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(5);
3925 0 : IGapInc = 1;
3926 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3927 0 : TGlassFace(IGap) = wm->thetas[IGap + 2];
3928 0 : TShadeFace(IGap) = wm->thetas[IGap + 5];
3929 : }
3930 : }
3931 :
3932 0 : auto const *matShadingDevice = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(MatNumSh));
3933 :
3934 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3935 0 : TAve(IGap) = 0.5 * (TGlassFace(IGap) + TShadeFace(IGap));
3936 0 : if (iter == 0) {
3937 0 : TGapOld(IGap) = TAve(IGap);
3938 : } else {
3939 0 : TGapOld(IGap) = TGapNew(IGap);
3940 : }
3941 : // Conductance of gaps on either side of shade/blind assuming gaps are sealed
3942 0 : WindowGasConductance(state, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, con, pr, gr);
3943 0 : NusseltNumber(state, SurfNum, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, gr, pr, nu);
3944 0 : hGapStill(IGap) = con / wm->gaps[IGap + IGapInc - 1].width * nu;
3945 : }
3946 :
3947 : // For near-horizontal windows (i.e., no more than 5 deg from horizontal) assume
3948 : // there is no air flow thru gap
3949 :
3950 0 : if (std::abs(s_surf->Surface(SurfNum).SinTilt) < 0.0872) {
3951 0 : VGap = 0.0;
3952 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3953 0 : hcv(IGap) = 2.0 * hGapStill(IGap);
3954 0 : TGapNew(IGap) = TAve(IGap);
3955 : }
3956 0 : return;
3957 : }
3958 :
3959 0 : GapHeight = s_surf->Surface(SurfNum).Height;
3960 0 : GapDepth = wm->gaps[IGapInc].width;
3961 0 : AGap = GapDepth * s_surf->Surface(SurfNum).Width;
3962 :
3963 0 : ATopGap = matShadingDevice->topOpeningMult * AGap;
3964 0 : ABotGap = matShadingDevice->bottomOpeningMult * AGap;
3965 0 : ALeftGap = matShadingDevice->leftOpeningMult * GapHeight * GapDepth;
3966 0 : ARightGap = matShadingDevice->rightOpeningMult * GapHeight * GapDepth;
3967 : // For blinds, airFlowPermeability depends on slat angle which is a property of the surface, not the material
3968 0 : if (matShadingDevice->group == Material::Group::Blind) {
3969 0 : AHolesGap = s_surf->surfShades(SurfNum).blind.airFlowPermeability * GapHeight * surf.Width;
3970 : } else {
3971 0 : AHolesGap = matShadingDevice->airFlowPermeability * GapHeight * surf.Width;
3972 : }
3973 :
3974 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3975 0 : WindowGasPropertiesAtTemp(state, TGapOld(IGap), IGap + IGapInc, RhoGas(IGap), ViscGas(IGap));
3976 : }
3977 :
3978 0 : BVGap = 12.0 * (ViscGas(1) + ViscGas(2)) * GapHeight / pow_2(GapDepth);
3979 : // Adding 0.000001 and 0.000002 in the following gives ATopLRH = ABotLRH =
3980 : // 0.25*(ALeftGap + ARightGap + AHolesGap) when ABotGap = ATopGap = 0.0 (shade/blind sealed at
3981 : // bottom and top but possibly open at left side, right side and/or in shade/blind)
3982 0 : ATopLRH = 0.5 * ((ATopGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
3983 0 : ABotLRH = 0.5 * ((ABotGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
3984 0 : AEqInlet = ABotGap + ATopLRH;
3985 0 : AEqOutlet = ATopGap + ABotLRH;
3986 :
3987 : // Adding 0.000001 in the following gives very large value of Zinlet for AEqInlet = 0 and
3988 : // very large value of Zoutlet for AEqInlet = 0; this gives VGap close to zero, as required
3989 : // when there is no inlet and/or outlet for air. This then reduces to the
3990 : // case of a completely sealed shade, in which hcv = 2*hGapStill and QConvGap = 0.
3991 0 : Zinlet = pow_2(AGap / (0.6 * AEqInlet + 0.000001) - 1.0);
3992 0 : Zoutlet = pow_2(AGap / (0.6 * AEqOutlet + 0.000001) - 1.0);
3993 0 : AVGap = 0.5 * (RhoGas(1) + RhoGas(2)) * (1.0 + Zinlet + Zoutlet);
3994 0 : WindowGasPropertiesAtTemp(state, Constant::Kelvin, 1 + IGapInc, RhoGasZero, ViscGasZero);
3995 0 : RhoTRef = RhoGasZero * Constant::Kelvin;
3996 0 : CVGap = RhoTRef * 9.81 * GapHeight * s_surf->Surface(SurfNum).SinTilt * (TGapOld(1) - TGapOld(2)) / (TGapOld(1) * TGapOld(2));
3997 :
3998 : // Solution of quadratic equation in VGap
3999 :
4000 0 : VGap = (std::sqrt(pow_2(BVGap) + std::abs(4 * AVGap * CVGap)) - BVGap) / (2 * AVGap);
4001 :
4002 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
4003 0 : hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
4004 0 : GapHeightChar(IGap) = RhoGas(IGap) * 1008.0 * GapDepth * VGap / (2.0 * hcv(IGap));
4005 : // The following avoids divide by zero and exponential underflow
4006 0 : if (GapHeightChar(IGap) == 0.0) {
4007 0 : EpsChar(IGap) = 0.0;
4008 0 : } else if ((GapHeight / GapHeightChar(IGap)) > 15.0) {
4009 0 : EpsChar(IGap) = 0.0;
4010 : } else {
4011 0 : EpsChar(IGap) = std::exp(-GapHeight / GapHeightChar(IGap));
4012 : }
4013 : }
4014 :
4015 0 : TGapNew(1) =
4016 0 : TAve(1) - (TAve(1) - TAve(2)) * (GapHeightChar(1) / GapHeight) * (1 - EpsChar(1)) * (1 - EpsChar(2)) / (1 - EpsChar(1) * EpsChar(2));
4017 :
4018 0 : TGapNew(2) =
4019 0 : TAve(2) - (TAve(2) - TAve(1)) * (GapHeightChar(2) / GapHeight) * (1 - EpsChar(1)) * (1 - EpsChar(2)) / (1 - EpsChar(1) * EpsChar(2));
4020 0 : }
4021 :
4022 : //****************************************************************************
4023 :
4024 0 : void BetweenGlassForcedFlow(EnergyPlusData &state,
4025 : int const SurfNum, // Surface number
4026 : int const iter, // Iteration number for glass heat balance calculation
4027 : Real64 &VGap, // Air velocity in airflow gap (m/s)
4028 : Real64 &TGapNew, // Current-iteration average air temp in airflow gap (K)
4029 : Real64 &TGapOutlet, // Temperature of air leaving glass-shade/blind gap at top for upward
4030 : Real64 &hcv, // Convection coefficient from gap glass faces to gap air (W/m2-K)
4031 : Real64 &QConvGap // Convective heat gain from air flow gap (W)
4032 : )
4033 : {
4034 :
4035 : // SUBROUTINE INFORMATION:
4036 : // AUTHOR F. Winkelmann
4037 : // DATE WRITTEN February 2003
4038 : // MODIFIED na
4039 : // RE-ENGINEERED na
4040 :
4041 : // PURPOSE OF THIS SUBROUTINE:
4042 : // Called by SolveForWindowTemperatures for "airflow windows",i.e., windows
4043 : // with forced airflow in one of the gaps between layers of glass. Based on
4044 : // the velocity of airflow through gap, finds effective temperature of gap air,
4045 : // convective heat transfer coefficient from glass to gap air,
4046 : // the gap outlet temperature, and the outlet convective heat flow.
4047 :
4048 : // Called only for double and triple glazing. For triple glazing the airflow
4049 : // is assumed to be between the inner two layers of glass (glass layers 2 and 3).
4050 :
4051 : // METHODOLOGY EMPLOYED:
4052 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
4053 : // Detailed Calculations"
4054 :
4055 : // Locals
4056 : // SUBROUTINE ARGUMENT DEFINITIONS:
4057 : // air flow or bottom for downward air flow (K)
4058 :
4059 : int ConstrNum; // Construction number of surface
4060 : int NGlass; // Number of glass layers in construction
4061 : int GapNum; // Number of airflow gap
4062 : Real64 TGapInlet; // Temperature of air entering glass-shade/blind gap at bottom for upward
4063 : // air flow or top for downward air flow (K)
4064 : Real64 TGlassFace1; // Temperature of left-hand glass surface facing airflow gap (K)
4065 : Real64 TGlassFace2; // Temperature of right-hand glass surface facing airflow gap (K)
4066 : Real64 hGapStill; // Still-air gap conduction/convection coeff (W/m2-K)
4067 : Real64 TGapOld; // Previous-iteration average air temp in airflow gap (K)
4068 : Real64 GapHeight; // Vertical length of airflow gap (m)
4069 : Real64 GapDepth; // Thickness of airflow gap (m)
4070 : Real64 RhoAir; // Density of airflow gap air at a temperature of TGapOld (kg/m3)
4071 : Real64 AGap; // Cross sectional area of airflow gap (m2); for vertical window, this
4072 : // is in horizontal plane normal to window.
4073 : Real64 GapHeightChar; // Characteristic height of the airflow gap air temperature profile (m)
4074 : Real64 TAve; // Average of TGlassFace1 and TGlassFace2 (K)
4075 : // REAL(r64) :: AirProps(8) ! Air properties
4076 : Real64 con; // Gap conductivity and derivative
4077 : Real64 gr; // Gap air Grashof number
4078 : Real64 pr; // Gap air Prandtl number
4079 : Real64 nu; // Gap air Nusselt number
4080 :
4081 : // Air properties
4082 : // Dens dDens/dT Con dCon/dT Vis dVis/dT Prandtl dPrandtl/dT
4083 : // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72, 1.8d-3 /
4084 :
4085 0 : auto &s_mat = state.dataMaterial;
4086 0 : auto &s_surf = state.dataSurface;
4087 0 : auto const &wm = state.dataWindowManager;
4088 :
4089 0 : auto const &surf = s_surf->Surface(SurfNum);
4090 :
4091 0 : ConstrNum = surf.Construction;
4092 0 : NGlass = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
4093 0 : TGlassFace1 = wm->thetas[2 * NGlass - 3];
4094 0 : TGlassFace2 = wm->thetas[2 * NGlass - 2];
4095 0 : GapNum = NGlass - 1;
4096 0 : TAve = 0.5 * (TGlassFace1 + TGlassFace2);
4097 :
4098 0 : if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
4099 0 : TGapInlet = wm->tin; // Source is inside air
4100 : } else {
4101 0 : TGapInlet = wm->tout; // Source is outside air
4102 : }
4103 :
4104 0 : if (iter == 0) {
4105 0 : TGapOld = 0.5 * (TAve + TGapInlet);
4106 : } else {
4107 0 : TGapOld = TGapNew;
4108 : }
4109 :
4110 : // Conductance of gap assuming it is sealed
4111 0 : WindowGasConductance(state, TGlassFace1, TGlassFace2, GapNum, con, pr, gr);
4112 0 : NusseltNumber(state, SurfNum, TGlassFace1, TGlassFace2, GapNum, gr, pr, nu);
4113 0 : hGapStill = con / wm->gaps[GapNum - 1].width * nu;
4114 0 : GapHeight = surf.Height;
4115 0 : GapDepth = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(2 * NGlass - 2))->Thickness;
4116 0 : AGap = GapDepth * surf.Width;
4117 0 : VGap = s_surf->SurfWinAirflowThisTS(SurfNum) / GapDepth;
4118 0 : hcv = 2.0 * hGapStill + 4.0 * VGap;
4119 0 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapOld - Constant::Kelvin);
4120 0 : GapHeightChar = RhoAir * 1008.0 * GapDepth * VGap / (2.0 * hcv);
4121 : // The following avoids divide by zero and exponential underflow
4122 0 : if (GapHeightChar == 0.0) {
4123 0 : TGapOutlet = TAve;
4124 0 : } else if ((GapHeight / GapHeightChar) > 15.0) {
4125 0 : TGapOutlet = TAve;
4126 : } else {
4127 0 : TGapOutlet = TAve - (TAve - TGapInlet) * std::exp(-GapHeight / GapHeightChar);
4128 : }
4129 0 : TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet);
4130 : // Convective heat flow from gap [W]
4131 0 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapNew - Constant::Kelvin);
4132 0 : QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet);
4133 0 : } // BetweenGlassForcedFlow()
4134 :
4135 : //****************************************************************************
4136 :
4137 0 : void BetweenGlassShadeForcedFlow(EnergyPlusData &state,
4138 : int const SurfNum, // Surface number
4139 : int const iter, // Iteration number for glass heat balance calculation
4140 : Real64 &VGap, // Air velocity in each gap (m/s)
4141 : Array1A<Real64> TGapNew, // Current-iteration average gas temp in gaps (K)
4142 : Real64 &TGapOutletAve, // Average of TGapOutlet(1) and TGapOutlet(2) (K)
4143 : Array1A<Real64> hcv, // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
4144 : Real64 &QConvTot // Sum of convective heat flow from gaps (W)
4145 : )
4146 : {
4147 :
4148 : // SUBROUTINE INFORMATION:
4149 : // AUTHOR F. Winkelmann
4150 : // DATE WRITTEN February 2003
4151 : // MODIFIED na
4152 : // RE-ENGINEERED na
4153 :
4154 : // PURPOSE OF THIS SUBROUTINE:
4155 : // Called by SolveForWindowTemperatures for airflow windows with a
4156 : // between-glass shade or blind over which fan-forced air flows.
4157 : // Based on the air flow velocity (which is assumed to be the same in the
4158 : // gaps on either side of the shade/blind), finds, for each gap: the average
4159 : // air temperature, the shade/blind or glass surface to air convective heat
4160 : // transfer coefficient, the gap outlet temperature, and the outlet convective heat flow.
4161 :
4162 : // Called only for double and triple glazing. For triple glazing the airflow
4163 : // is assumed to be between the inner two layers of glass (glass layers 2 and 3),
4164 : // between which the shade/blind is located.
4165 :
4166 : // METHODOLOGY EMPLOYED:
4167 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
4168 : // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
4169 :
4170 : // Argument array dimensioning
4171 0 : TGapNew.dim(2);
4172 0 : hcv.dim(2);
4173 :
4174 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4175 : int ConstrNumSh; // Shaded construction number
4176 : // In the following, "gaps" refer to the gaps on either side of the shade/blind
4177 0 : Array1D<Real64> TGlassFace(2); // Temperature of glass surfaces facing gaps (K)
4178 0 : Array1D<Real64> TShadeFace(2); // Temperature of shade surfaces facing gaps (K)
4179 0 : Array1D<Real64> hGapStill(2); // Still-air conduction/convection coeffs for the gaps (W/m2-K)
4180 0 : Array1D<Real64> TGapOld(2); // Previous-iteration average gas temp in gaps (K)
4181 : Real64 GapHeight; // Vertical length of glass-shade/blind gap (m)
4182 : Real64 GapDepth; // Distance from shade/blind to glass; assumed same for both gaps (m)
4183 0 : Array1D<Real64> RhoAir(2); // Density of gap air (kg/m3)
4184 : Real64 AGap; // Cross sectional area of each gap (m2); for vertical window, this
4185 : // is in horizontal plane normal to window.
4186 : Real64 TGapInlet; // Gap inlet air temperature (K)
4187 0 : Array1D<Real64> TGapOutlet(2); // Gap outlet air temperature (K)
4188 0 : Array1D<Real64> QConvGap(2); // Convective heat flow from each gap (W)
4189 0 : Array1D<Real64> GapHeightChar(2); // Characteristic height of the gap air temperature profile (m)
4190 0 : Array1D<Real64> TAve(2); // Average of TGlass and TShade for the gaps (K)
4191 : Real64 con; // Gap air conductivity and derivative
4192 : Real64 gr; // Gap air Grashof number
4193 : Real64 pr; // Gap air Prandtl number
4194 : Real64 nu; // Gap air Nusselt number
4195 : WinShadingType ShadeFlag; // Shading flag
4196 : int IGapInc; // Gap increment; =0, double glass, =1, triple glass
4197 : // REAL(r64) :: AirProps(8) ! Air properties
4198 :
4199 0 : auto &s_surf = state.dataSurface;
4200 0 : auto const &wm = state.dataWindowManager;
4201 :
4202 : // Air properties
4203 : // Dens dDens/dT Con dCon/dT Vis dVis/dT Prandtl dPrandtl/dT
4204 : // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72, 1.8d-3 /
4205 :
4206 0 : ConstrNumSh = s_surf->Surface(SurfNum).activeShadedConstruction;
4207 0 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
4208 :
4209 0 : if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double glazing
4210 0 : IGapInc = 0;
4211 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
4212 0 : TGlassFace(IGap) = wm->thetas[IGap];
4213 0 : TShadeFace(IGap) = wm->thetas[IGap + 3];
4214 : }
4215 : } else { // Triple glazing
4216 0 : IGapInc = 1;
4217 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
4218 0 : TGlassFace(IGap) = wm->thetas[IGap + 2];
4219 0 : TShadeFace(IGap) = wm->thetas[IGap + 5];
4220 : }
4221 : }
4222 :
4223 0 : if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
4224 0 : TGapInlet = wm->tin;
4225 : } else {
4226 0 : TGapInlet = wm->tout;
4227 : }
4228 :
4229 0 : GapHeight = s_surf->Surface(SurfNum).Height;
4230 0 : GapDepth = wm->gaps[IGapInc].width;
4231 0 : AGap = GapDepth * s_surf->Surface(SurfNum).Width;
4232 : // Factor of 2 below assumes gaps on either side of shade/blind have same depth
4233 0 : VGap = s_surf->SurfWinAirflowThisTS(SurfNum) / (2.0 * GapDepth);
4234 :
4235 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
4236 0 : TAve(IGap) = 0.5 * (TGlassFace(IGap) + TShadeFace(IGap));
4237 0 : if (iter == 0) {
4238 0 : TGapOld(IGap) = TAve(IGap);
4239 : } else {
4240 0 : TGapOld(IGap) = TGapNew(IGap);
4241 : }
4242 : // Conductance of gaps on either side of shade/blind assuming gaps are sealed
4243 0 : WindowGasConductance(state, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, con, pr, gr);
4244 0 : NusseltNumber(state, SurfNum, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, gr, pr, nu);
4245 0 : hGapStill(IGap) = con / wm->gaps[IGap + IGapInc - 1].width * nu;
4246 : // Shade/blind or glass surface to air convection coefficient
4247 0 : hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
4248 0 : RhoAir(IGap) = wm->AirProps[0] + wm->AirProps[1] * (TGapOld(IGap) - Constant::Kelvin);
4249 0 : hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
4250 0 : GapHeightChar(IGap) = RhoAir(IGap) * 1008.0 * GapDepth * VGap / (2.0 * hcv(IGap));
4251 : // The following avoids divide by zero and exponential underflow
4252 0 : if (GapHeightChar(IGap) == 0.0) {
4253 0 : TGapOutlet(IGap) = TAve(IGap);
4254 0 : } else if ((GapHeight / GapHeightChar(IGap)) > 15.0) {
4255 0 : TGapOutlet(IGap) = TAve(IGap);
4256 : } else {
4257 0 : TGapOutlet(IGap) = TAve(IGap) - (TAve(IGap) - TGapInlet) * std::exp(-GapHeight / GapHeightChar(IGap));
4258 : }
4259 0 : TGapNew(IGap) = TAve(IGap) - (GapHeightChar(IGap) / GapHeight) * (TGapOutlet(IGap) - TGapInlet);
4260 : // Convective heat flow from gap [W]
4261 0 : RhoAir(IGap) = wm->AirProps[0] + wm->AirProps[1] * (TGapNew(IGap) - Constant::Kelvin);
4262 0 : QConvGap(IGap) = RhoAir(IGap) * AGap * VGap * 1008.0 * (TGapOutlet(IGap) - TGapInlet);
4263 : }
4264 :
4265 0 : QConvTot = QConvGap(1) + QConvGap(2);
4266 0 : TGapOutletAve = 0.5 * (TGapOutlet(1) + TGapOutlet(2));
4267 0 : } // BetweenGlassShadeForcedFlow()
4268 :
4269 : //****************************************************************************
4270 :
4271 204621 : void LUdecomposition(EnergyPlusData &state,
4272 : Array2<Real64> &ajac, // As input: matrix to be decomposed;
4273 : int const n, // Dimension of matrix
4274 : Array1D_int &indx, // Vector of row permutations
4275 : int &d // +1 if even number of row interchange is even, -1
4276 : )
4277 : {
4278 :
4279 : // SUBROUTINE INFORMATION:
4280 : // AUTHOR F. Winkelmann, adapted from Numerical Recipes
4281 : // DATE WRITTEN February 2000
4282 :
4283 : // PURPOSE OF THIS SUBROUTINE:
4284 : // Performs LU decomposition of a matrix.
4285 :
4286 : // SUBROUTINE ARGUMENT DEFINITIONS:
4287 : // as output: decomposed matrix
4288 : // if odd
4289 :
4290 : int imax; // Temporary variable
4291 : // as output: decomposed matrix
4292 :
4293 204621 : assert(n <= 10); // vv sizing
4294 204621 : std::array<Real64, 10> vv = {0.0}; // Stores the implicit scaling of each row
4295 :
4296 204621 : d = 1;
4297 803903 : for (int i = 1; i <= n; ++i) {
4298 599282 : Real64 aamax = 0.0;
4299 2558006 : for (int j = 1; j <= n; ++j) {
4300 1958724 : if (std::abs(ajac(j, i)) > aamax) {
4301 999990 : aamax = std::abs(ajac(j, i));
4302 : }
4303 : }
4304 599282 : if (aamax == 0.0) {
4305 0 : ShowFatalError(state, "Singular matrix in LUdecomposition, window calculations");
4306 : }
4307 599282 : vv[i - 1] = 1.0 / aamax;
4308 : }
4309 803903 : for (int j = 1; j <= n; ++j) {
4310 1279003 : for (int i = 1; i <= j - 1; ++i) {
4311 679721 : Real64 sum = ajac(j, i);
4312 1059801 : for (int k = 1; k <= i - 1; ++k) {
4313 380080 : sum -= ajac(k, i) * ajac(j, k);
4314 : }
4315 679721 : ajac(j, i) = sum;
4316 : }
4317 599282 : Real64 aamax = 0.0;
4318 1878285 : for (int i = j; i <= n; ++i) {
4319 1279003 : Real64 sum = ajac(j, i);
4320 2338804 : for (int k = 1; k <= j - 1; ++k) {
4321 1059801 : sum -= ajac(k, i) * ajac(j, k);
4322 : }
4323 1279003 : ajac(j, i) = sum;
4324 1279003 : Real64 dum = vv[i - 1] * std::abs(sum);
4325 1279003 : if (dum >= aamax) {
4326 599282 : imax = i;
4327 599282 : aamax = dum;
4328 : }
4329 : }
4330 599282 : if (j != imax) {
4331 0 : for (int k = 1; k <= n; ++k) {
4332 0 : Real64 dum = ajac(k, imax);
4333 0 : ajac(k, imax) = ajac(k, j);
4334 0 : ajac(k, j) = dum;
4335 : }
4336 0 : d = -d;
4337 0 : vv[imax - 1] = vv[j - 1];
4338 : }
4339 599282 : indx(j) = imax;
4340 599282 : if (ajac(j, j) == 0.0) {
4341 0 : ajac(j, j) = Constant::rTinyValue;
4342 : }
4343 599282 : if (j != n) {
4344 394661 : Real64 dum = 1.0 / ajac(j, j);
4345 1074382 : for (int i = j + 1; i <= n; ++i) {
4346 679721 : ajac(j, i) *= dum;
4347 : }
4348 : }
4349 : }
4350 204621 : } // LUdecomposition()
4351 :
4352 : //**************************************************************************
4353 :
4354 368607 : void LUsolution([[maybe_unused]] EnergyPlusData &state,
4355 : Array2<Real64> const &a, // Matrix and vector in a.x = b;
4356 : int const n, // Dimension of a and b
4357 : Array1D_int const &indx, // Vector of row permutations
4358 : Array1D<Real64> &b // Matrix and vector in a.x = b;
4359 : )
4360 : {
4361 :
4362 : // SUBROUTINE INFORMATION:
4363 : // AUTHOR F. Winkelmann, adapted from Numerical Recipes
4364 : // DATE WRITTEN February 2000
4365 : // MODIFIED na
4366 : // RE-ENGINEERED na
4367 :
4368 : // PURPOSE OF THIS SUBROUTINE:
4369 : // Solves set of linear equations a.x = b
4370 :
4371 : // Locals
4372 : // SUBROUTINE ARGUMENT DEFINITIONS:
4373 : // b is also output as the solution, x
4374 : // b is also output as the solution, x
4375 :
4376 : Real64 sum; // Summation variable
4377 :
4378 368607 : int ii = 0;
4379 1623833 : for (int i = 1; i <= n; ++i) {
4380 1255226 : int ll = indx(i);
4381 1255226 : sum = b(ll);
4382 1255226 : b(ll) = b(i);
4383 1255226 : if (ii != 0) {
4384 1456962 : for (int j = ii; j <= i - 1; ++j) {
4385 898333 : sum -= a(j, i) * b(j);
4386 : }
4387 696597 : } else if (sum != 0.0) {
4388 368607 : ii = i;
4389 : }
4390 1255226 : b(i) = sum;
4391 : }
4392 1623833 : for (int i = n; i >= 1; --i) {
4393 1255226 : sum = b(i);
4394 2918863 : for (int j = i + 1; j <= n; ++j) {
4395 1663637 : sum -= a(j, i) * b(j);
4396 : }
4397 1255226 : b(i) = sum / a(i, i);
4398 : }
4399 368607 : } // LUsolution()
4400 :
4401 : //******************************************************************************
4402 :
4403 40358 : void WindowGasConductance(EnergyPlusData &state,
4404 : Real64 const tleft, // Temperature of gap surface closest to outside (K)
4405 : Real64 const tright, // Temperature of gap surface closest to zone (K)
4406 : int const IGap, // Gap number
4407 : Real64 &con, // Gap gas conductance (W/m2-K)
4408 : Real64 &pr, // Gap gas Prandtl number
4409 : Real64 &gr // Gap gas Grashof number
4410 : )
4411 : {
4412 :
4413 : // SUBROUTINE INFORMATION:
4414 : // AUTHOR Adapted by Fred Winkelmann from Window5 subroutine gasses
4415 : // DATE WRITTEN September 2001
4416 : // MODIFIED na
4417 : // RE-ENGINEERED na
4418 :
4419 : // PURPOSE OF THIS SUBROUTINE:
4420 : // Find the coefficient of convective/conductive heat transfer in the gas-filled gap
4421 : // between isothermal solid layers. The gap may be filled with a single gas or a gas mixture.
4422 :
4423 : // METHODOLOGY EMPLOYED:
4424 : // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
4425 : // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
4426 : // The equation numbers below correspond to those in the standard.
4427 :
4428 : // REFERENCES:
4429 : // Window5 source code; ISO 15099
4430 :
4431 40358 : constexpr Real64 pres(1.0e5); // Gap gas pressure (Pa)
4432 40358 : constexpr Real64 gaslaw(8314.51); // Molar gas constant (J/kMol-K)
4433 40358 : Real64 const two_sqrt_2(2.0 * std::sqrt(2.0));
4434 :
4435 : int NMix; // Number of gases in a mixture
4436 : Real64 molmix; // Molecular weight of mixture
4437 :
4438 40358 : auto &wm = state.dataWindowManager;
4439 :
4440 : Real64 kpmix; // Monotonic thermal conductivity of mixture
4441 : Real64 kdpmix;
4442 : Real64 kmix; // For accumulating conductance of gas mixture
4443 : Real64 mumix; // For accumulating viscosity of gas mixture
4444 40358 : Real64 visc(0.0); // Dynamic viscosity of mixture at tmean (g/m-s)
4445 40358 : Real64 cp(0.0); // Specific heat of mixture at tmean (J/m3-K)
4446 40358 : Real64 dens(0.0); // Density of mixture at tmean (kg/m3)
4447 : Real64 cpmixm; // Gives cp when divided by molmix
4448 : Real64 phimup; // Numerator factor
4449 : Real64 downer; // Denominator factor
4450 : Real64 psiup; // Numerator factor
4451 : Real64 psiterm; // Factor
4452 : Real64 phikup; // Numerator factor
4453 : Real64 rhomix; // Density of gas mixture (kg/m3)
4454 :
4455 40358 : std::array<Real64, 10> mukpdwn = {0.0}; // Denominator term
4456 40358 : std::array<Real64, 10> kpdown = {0.0}; // Denominator terms
4457 40358 : std::array<Real64, 10> kdpdown = {0.0};
4458 : // Conductivity term accounting for additional energy moved by the diffusional transport of internal energy in polyatomic gases.
4459 40358 : std::array<Real64, 10> kdblprm = {0.0};
4460 40358 : std::array<Real64, 10> frct = {0.0}; // Fraction of each gas in a mixture
4461 40358 : std::array<Real64, 10> kprime = {0.0}; // Monotonic thermal conductivity
4462 :
4463 40358 : std::array<Real64, 10> fvis = {0.0}; // Viscosity of each gas in a mixture (g/m-s)
4464 40358 : std::array<Real64, 10> fcon = {0.0}; // Conductance of each gas in a mixture (W/m2-K)
4465 40358 : std::array<Real64, 10> fdens = {0.0}; // Density of each gas in a mixture (kg/m3)
4466 40358 : std::array<Real64, 10> fcp = {0.0}; // Specific heat of each gas in a mixture (J/m3-K)
4467 :
4468 : // Autodesk:Logic Either assert NMix>0 or handle NMix<=0 in logic so that con and locals guar. initialized before use
4469 40358 : NMix = wm->gaps[IGap - 1].numGases;
4470 :
4471 80716 : for (int IMix = 0; IMix < NMix; ++IMix) {
4472 40358 : frct[IMix] = wm->gaps[IGap - 1].gasFracts[IMix];
4473 : }
4474 :
4475 40358 : Real64 const tmean(0.5 * (tleft + tright)); // Average gap gas temperature (K)
4476 40358 : Real64 const tmean_2(pow_2(tmean));
4477 :
4478 40358 : auto const &wmgas0 = wm->gaps[IGap - 1].gases[0];
4479 40358 : fcon[0] = wmgas0.con.c0 + wmgas0.con.c1 * tmean + wmgas0.con.c2 * tmean_2;
4480 40358 : fvis[0] = wmgas0.vis.c0 + wmgas0.vis.c1 * tmean + wmgas0.vis.c2 * tmean_2;
4481 40358 : fcp[0] = wmgas0.cp.c0 + wmgas0.cp.c1 * tmean + wmgas0.cp.c2 * tmean_2;
4482 40358 : fdens[0] = pres * wmgas0.wght / (gaslaw * tmean); // Density using ideal gas law:
4483 : // rho=(presure*molecweight)/(gasconst*tmean)
4484 :
4485 40358 : if (NMix == 1) { // Single gas
4486 40358 : con = fcon[0];
4487 40358 : visc = fvis[0];
4488 40358 : cp = fcp[0];
4489 40358 : dens = fdens[0];
4490 0 : } else if (NMix > 1) { // Multiple gases; calculate mixture properties
4491 0 : molmix = frct[0] * wmgas0.wght; // initialize eq. 56
4492 0 : cpmixm = molmix * fcp[0]; // initialize eq. 58
4493 0 : kprime[0] = 3.75 * (gaslaw / wmgas0.wght) * fvis[0]; // eq. 67
4494 0 : kdblprm[0] = fcon[0] - kprime[0]; // eq. 67
4495 :
4496 : // Initialize summations for eqns 60-66
4497 0 : mumix = 0.0;
4498 0 : kpmix = 0.0;
4499 0 : kdpmix = 0.0;
4500 0 : mukpdwn[0] = 1.0;
4501 0 : kpdown[0] = 1.0;
4502 0 : kdpdown[0] = 1.0;
4503 :
4504 : // Calculate properties of mixture constituents
4505 0 : for (int i = 2; i <= NMix; ++i) {
4506 0 : auto const &wmgas = wm->gaps[IGap - 1].gases[i - 1];
4507 :
4508 0 : fcon[i - 1] = wmgas.con.c0 + wmgas.con.c1 * tmean + wmgas.con.c2 * tmean_2;
4509 0 : fvis[i - 1] = wmgas.vis.c0 + wmgas.vis.c1 * tmean + wmgas.vis.c2 * tmean_2;
4510 0 : fcp[i - 1] = wmgas.cp.c0 + wmgas.cp.c1 * tmean + wmgas.cp.c2 * tmean_2;
4511 0 : molmix += frct[i - 1] * wmgas.wght; // eq. 56
4512 0 : cpmixm += frct[i - 1] * fcp[i - 1] * wmgas.wght; // eq. 58-59
4513 0 : kprime[i - 1] = 3.75 * gaslaw / wmgas.wght * fvis[i - 1]; // eq. 67
4514 0 : kdblprm[i - 1] = fcon[i - 1] - kprime[i - 1]; // eq. 68
4515 0 : mukpdwn[i - 1] = 1.0; // initialize denominator of eq. 60
4516 0 : kpdown[i - 1] = 1.0; // initialize denominator of eq. 63
4517 0 : kdpdown[i - 1] = 1.0; // initialize denominator of eq. 65
4518 : }
4519 :
4520 0 : for (int i = 1; i <= NMix; ++i) {
4521 0 : auto const &wmgasI = wm->gaps[IGap - 1].gases[i - 1];
4522 :
4523 0 : for (int j = 1; j <= NMix; ++j) {
4524 0 : auto const &wmgasJ = wm->gaps[IGap - 1].gases[j - 1];
4525 :
4526 : // numerator of equation 61
4527 0 : phimup = pow_2(1.0 + std::sqrt(fvis[i - 1] / fvis[j - 1]) * root_4(wmgasJ.wght / wmgasI.wght));
4528 : // denominator of eq. 61, 64 and 66
4529 0 : downer = two_sqrt_2 * std::sqrt(1 + (wmgasI.wght / wmgasJ.wght));
4530 : // calculate the denominator of eq. 60
4531 0 : if (i != j) {
4532 0 : mukpdwn[i - 1] += phimup / downer * frct[j - 1] / frct[i - 1];
4533 : }
4534 : // numerator of eq. 64; psiterm is the multiplied term in brackets
4535 0 : psiup = pow_2(1.0 + std::sqrt(kprime[i - 1] / kprime[j - 1]) * root_4(wmgasI.wght / wmgasJ.wght));
4536 0 : psiterm = 1.0 + 2.41 * (wmgasI.wght - wmgasJ.wght) * (wmgasI.wght - 0.142 * wmgasJ.wght) / pow_2(wmgasI.wght + wmgasJ.wght);
4537 : // using the common denominator, downer, calculate the denominator for eq. 63
4538 0 : if (i != j) {
4539 0 : kpdown[i - 1] += psiup * (psiterm / downer) * (frct[j - 1] / frct[i - 1]);
4540 : }
4541 : // calculate the numerator of eq. 66
4542 0 : phikup = pow_2(1.0 + std::sqrt(kprime[i - 1] / kprime[j - 1]) * root_4(wmgasI.wght / wmgasJ.wght));
4543 : // using the common denominator, downer, calculate the denominator for eq. 65
4544 0 : if (i != j) {
4545 0 : kdpdown[i - 1] += (phikup / downer) * (frct[j - 1] / frct[i - 1]);
4546 : }
4547 : }
4548 0 : mumix += fvis[i - 1] / mukpdwn[i - 1]; // eq. 60
4549 0 : kpmix += kprime[i - 1] / kpdown[i - 1]; // eq. 63
4550 0 : kdpmix += kdblprm[i - 1] / kdpdown[i - 1]; // eq. 65
4551 : }
4552 :
4553 : // Calculate the density of the mixture assuming an ideal gas
4554 0 : rhomix = pres * molmix / (gaslaw * tmean); // eq. 57
4555 0 : kmix = kpmix + kdpmix; // eq. 68-a
4556 :
4557 : // Final mixture properties
4558 0 : visc = mumix;
4559 0 : con = kmix;
4560 0 : dens = rhomix;
4561 0 : cp = cpmixm / molmix;
4562 :
4563 : } else {
4564 0 : assert(false);
4565 : } // End of check if single or multiple gases in gap
4566 :
4567 40358 : pr = cp * visc / con;
4568 40358 : gr = 9.807 * pow_3(wm->gaps[IGap - 1].width) * std::abs(tleft - tright) * pow_2(dens) / (tmean * pow_2(visc));
4569 40358 : } // WindowGasConductance()
4570 :
4571 : //******************************************************************************
4572 :
4573 0 : void WindowGasPropertiesAtTemp(EnergyPlusData const &state,
4574 : Real64 const tmean, // Temperature of gas in gap (K)
4575 : int const IGap, // Gap number
4576 : Real64 &dens, // Gap gas density at tmean (kg/m3)
4577 : Real64 &visc // Gap gas dynamic viscosity at tmean (g/m-s)
4578 : )
4579 : {
4580 :
4581 : // SUBROUTINE INFORMATION:
4582 : // AUTHOR F. Winkelmann
4583 : // DATE WRITTEN December 2002
4584 : // MODIFIED na
4585 : // RE-ENGINEERED na
4586 :
4587 : // PURPOSE OF THIS SUBROUTINE:
4588 : // Finds the density and viscosity of the gas in a gap at a particular temperature.
4589 : // The gap may be filled with a single gas or a gas mixture.
4590 : // Based on Subroutine WindowGasConductance.
4591 :
4592 : // METHODOLOGY EMPLOYED:
4593 : // See Subr. WindowGasConductance
4594 :
4595 : // REFERENCES:
4596 : // See Subr. WindowGasConductance
4597 :
4598 0 : Real64 constexpr pres(1.0e5); // Gap gas pressure (Pa)
4599 0 : Real64 constexpr gaslaw(8314.51); // Molar gas constant (J/kMol-K)
4600 0 : Real64 const two_sqrt_2(2.0 * std::sqrt(2.0));
4601 :
4602 : int NMix; // Number of gases in a mixture
4603 : Real64 molmix; // Molecular weight of mixture
4604 0 : Array1D<Real64> mukpdwn(10); // Denominator term
4605 : Real64 mumix; // For accumulating viscosity of gas mixture
4606 : Real64 phimup; // Numerator factor
4607 : Real64 downer; // Denominator factor
4608 : Real64 rhomix; // Density of gas mixture (kg/m3)
4609 0 : Array1D<Real64> frct(10); // Fraction of each gas in a mixture
4610 0 : Array1D<Real64> fvis(10); // Viscosity of each gas in a mixture (g/m-s)
4611 0 : Array1D<Real64> fdens(10); // Density of each gas in a mixture (kg/m3)
4612 :
4613 0 : auto const &wm = state.dataWindowManager;
4614 :
4615 0 : NMix = wm->gaps[IGap - 1].numGases;
4616 :
4617 0 : for (int IMix = 1; IMix <= NMix; ++IMix) {
4618 0 : frct(IMix) = wm->gaps[IGap - 1].gasFracts[IMix - 1];
4619 : }
4620 :
4621 0 : Real64 const tmean_2(pow_2(tmean));
4622 0 : auto const &wmgas0 = wm->gaps[IGap - 1].gases[0];
4623 0 : fvis(1) = wmgas0.vis.c0 + wmgas0.vis.c1 * tmean + wmgas0.vis.c2 * tmean_2;
4624 0 : fdens(1) = pres * wmgas0.wght / (gaslaw * tmean); // Density using ideal gas law:
4625 : // rho=(presure*molecweight)/(gasconst*tmean)
4626 0 : if (NMix == 1) { // Single gas
4627 0 : visc = fvis(1);
4628 0 : dens = fdens(1);
4629 : } else { // Multiple gases; calculate mixture properties
4630 0 : molmix = frct(1) * wmgas0.wght; // initialize eq. 56
4631 :
4632 : // Initialize summations for eqns 60-66
4633 0 : mumix = 0.0;
4634 0 : mukpdwn(1) = 1.0;
4635 :
4636 : // Calculate properties of mixture constituents
4637 0 : for (int i = 2; i <= NMix; ++i) {
4638 0 : auto const &wmgas = wm->gaps[IGap - 1].gases[i - 1];
4639 0 : fvis(i) = wmgas.vis.c0 + wmgas.vis.c1 * tmean + wmgas.vis.c2 * tmean_2;
4640 0 : fdens(i) = pres * wmgas.wght / (gaslaw * tmean);
4641 0 : molmix += frct(i) * wmgas.wght; // eq. 56
4642 0 : mukpdwn(i) = 1.0; // initialize denominator of eq. 60
4643 : }
4644 :
4645 0 : for (int i = 1; i <= NMix; ++i) {
4646 0 : auto const &wmgasI = wm->gaps[IGap - 1].gases[i - 1];
4647 0 : for (int j = 1; j <= NMix; ++j) {
4648 0 : auto const &wmgasJ = wm->gaps[IGap - 1].gases[j - 1];
4649 : // numerator of equation 61
4650 0 : phimup = pow_2(1.0 + std::sqrt(fvis(i) / fvis(j)) * root_4(wmgasJ.wght / wmgasI.wght));
4651 : // denominator of eq. 61, 64 and 66
4652 0 : downer = two_sqrt_2 * std::sqrt(1 + (wmgasI.wght / wmgasJ.wght));
4653 : // calculate the denominator of eq. 60
4654 0 : if (i != j) {
4655 0 : mukpdwn(i) += phimup / downer * frct(j) / frct(i);
4656 : }
4657 : }
4658 0 : mumix += fvis(i) / mukpdwn(i); // eq. 60
4659 : }
4660 :
4661 : // Calculate the density of the mixture assuming an ideal gas
4662 0 : rhomix = pres * molmix / (gaslaw * tmean); // eq. 57
4663 :
4664 : // Final mixture properties
4665 0 : visc = mumix;
4666 0 : dens = rhomix;
4667 :
4668 : } // End of check if single or multiple gases in gap
4669 0 : } // WindowGasPropertiesAtTemp()
4670 :
4671 : //********************************************************************************
4672 :
4673 85895 : void StartingWindowTemps(EnergyPlusData &state,
4674 : int const SurfNum, // Surface number
4675 : Array1A<Real64> AbsRadShade // Short-wave radiation absorbed by shade/blind faces
4676 : )
4677 : {
4678 :
4679 : // SUBROUTINE INFORMATION:
4680 : // AUTHOR F. Winkelmann
4681 : // DATE WRITTEN January 2000
4682 : // MODIFIED March 2003, FW: add rough calc of increase above ambient of
4683 : // initial shade/blind temperature when shade/blind deployed
4684 : // after having been off.
4685 : // Jan 2004, FW: take into account whether storm window was added
4686 : // or removed in the current time step.
4687 : // RE-ENGINEERED na
4688 :
4689 : // PURPOSE OF THIS SUBROUTINE:
4690 : // Initializes face temperature distribution prior to iteration
4691 :
4692 : // Argument array dimensioning
4693 85895 : AbsRadShade.dim(2);
4694 :
4695 85895 : constexpr Real64 hrad(5.3); // Typical radiative conductance (W/m2-K)
4696 85895 : constexpr Real64 resgap(0.21); // Typical gap resistance (m2-K/W)
4697 :
4698 : WinShadingType ShadeFlag; // Shading flag
4699 85895 : Array1D<Real64> rguess(11); // Combined radiative/convective resistance (m2-K/W) of
4700 : // inside or outside air film, or gap
4701 : Real64 restot; // Total window resistance including outside
4702 : // and inside air films (m2-K/W)
4703 : Real64 temdiff; // Inside/outside air temperature difference (K)
4704 : Real64 ressum; // Resistance sum (m2-K/W)
4705 : int StormWinFlagPrevDay; // Previous time step value (day) of storm window flag
4706 : int StormWinFlagThisDay; // Current time step value (day) of storm window flag
4707 : // current time step value, nglface, if storm window was
4708 : // added or removed during the current time step).
4709 :
4710 85895 : auto &s_surf = state.dataSurface;
4711 85895 : auto const &wm = state.dataWindowManager;
4712 :
4713 85895 : StormWinFlagPrevDay = s_surf->SurfWinStormWinFlagPrevDay(SurfNum);
4714 85895 : StormWinFlagThisDay = s_surf->SurfWinStormWinFlag(SurfNum);
4715 :
4716 85895 : if (state.dataGlobal->BeginEnvrnFlag || (StormWinFlagThisDay != StormWinFlagPrevDay)) {
4717 :
4718 : // Guess values of glass face temperatures based on a simple resistance-network solution
4719 : // that (1) ignores short- and long-wave radiation (from lights and zone equipment) absorbed
4720 : // by the glass faces, and (2) assumes zero glass resistance. Absorbed solar is also ignored
4721 : // since the tests on BeginEnvrnFlag and storm window transition can be true only at midnight.
4722 : // Interaction with shade or blind, if one of these is present, is ignored. See below for
4723 : // separate calculation of shade/blind temperature.
4724 :
4725 122 : rguess(1) = 1.0 / (wm->hcout + hrad);
4726 122 : rguess(wm->nglface + 1) = 1.0 / (wm->hcin + hrad);
4727 :
4728 281 : for (int i = 2; i <= wm->nglface; i += 2) {
4729 159 : rguess(i) = 1.0 / wm->scon[i / 2 - 1];
4730 159 : if (i < wm->nglface) {
4731 37 : rguess(i + 1) = resgap;
4732 : }
4733 : }
4734 :
4735 122 : restot = 0.0;
4736 562 : for (int i = 1; i <= wm->nglface + 1; ++i) {
4737 440 : restot += rguess(i);
4738 : }
4739 :
4740 122 : temdiff = wm->tin - wm->tout;
4741 122 : if (std::abs(temdiff) < 0.5) {
4742 21 : temdiff = 2.0;
4743 : }
4744 :
4745 122 : ressum = 0.0;
4746 440 : for (int i = 1; i <= wm->nglface; ++i) {
4747 318 : ressum += rguess(i);
4748 318 : wm->thetas[i - 1] = (ressum / restot) * temdiff + wm->tout;
4749 : }
4750 :
4751 : } else {
4752 : // Use previous time step values
4753 305639 : for (int i = 1; i <= wm->nglface; ++i) {
4754 219866 : wm->thetas[i - 1] = s_surf->SurfaceWindow(SurfNum).thetaFace[i];
4755 : }
4756 : }
4757 :
4758 : // Initialize face temperatures of shade or blind, if present
4759 :
4760 85895 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
4761 85895 : if (ANY_INTERIOR_SHADE_BLIND(s_surf->SurfWinExtIntShadePrevTS(SurfNum)) ||
4762 85895 : s_surf->SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtShade ||
4763 257685 : s_surf->SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtBlind ||
4764 85895 : ANY_BETWEENGLASS_SHADE_BLIND(s_surf->SurfWinExtIntShadePrevTS(SurfNum))) {
4765 : // Shade or blind is on during the previous TS; use previous-TS values of shade/blind face temps.
4766 : // Note that if shade or blind is NOT on in the current TS the following two
4767 : // temperature values, although calculated here, are not used. The shade/blind face numbers
4768 : // during the previous time step depend on whether a storm window glass layer was added to
4769 : // or removed from the window during the current time step.
4770 0 : int nglfacePrevDay = wm->nglface;
4771 0 : if (StormWinFlagPrevDay == 0 && StormWinFlagThisDay == 1) {
4772 0 : nglfacePrevDay = wm->nglface - 2;
4773 : }
4774 0 : if (StormWinFlagPrevDay == 1 && StormWinFlagThisDay == 0) {
4775 0 : nglfacePrevDay = wm->nglface + 2;
4776 : }
4777 0 : wm->thetas[wm->nglface] = s_surf->SurfaceWindow(SurfNum).thetaFace[nglfacePrevDay + 1];
4778 0 : wm->thetas[wm->nglface + 1] = s_surf->SurfaceWindow(SurfNum).thetaFace[nglfacePrevDay + 2];
4779 : } else {
4780 : // No shade or blind previous time step; guess starting values of shade/blind
4781 : // taking into account short- and long-wave radiation (from solar, lights and zone equipment)
4782 : // absorbed by shade/blind faces. Face temps are assumed to be the same and
4783 : // equal to shade/blind temp. For interior shade/blind, air temp on either side is
4784 : // assumed to be the same and equal to tin; for exterior blind it is assumed to be
4785 : // equal to tout. For between-glass shade/blind it is assumed to be equal to the
4786 : // average temperature of the adjacent glass faces.
4787 :
4788 85895 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
4789 0 : wm->thetas[wm->nglface] = wm->tin + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (wm->hcin + hrad));
4790 0 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4791 85895 : } else if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind) {
4792 0 : wm->thetas[wm->nglface] = wm->tout + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (wm->hcout + hrad));
4793 0 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4794 85895 : } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
4795 : // Between-glass shade/blind allowed only for double and triple glazing.
4796 : // The factor 16.0 below is based on a combined convective/radiative heat transfer
4797 : // coefficient on either side of the shade/blind of 8.0 W/m2-K -- about 1.4 Btu/h-ft2-F.
4798 0 : if (wm->nglface == 4) { // double glazing
4799 0 : wm->thetas[wm->nglface] = 0.5 * (wm->thetas[1] + wm->thetas[2]) + (AbsRadShade(1) + AbsRadShade(2)) / 16.0;
4800 0 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4801 : } else { // triple glazing
4802 0 : wm->thetas[wm->nglface] = 0.5 * (wm->thetas[3] + wm->thetas[4]) + (AbsRadShade(1) + AbsRadShade(2)) / 16.0;
4803 0 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4804 : }
4805 : }
4806 : }
4807 85895 : } // StartingWindowTemps()
4808 :
4809 : //****************************************************************************
4810 :
4811 40358 : void NusseltNumber(EnergyPlusData &state,
4812 : int const SurfNum, // Surface number
4813 : Real64 const tso, // Temperature of gap surface closest to outside (K)
4814 : Real64 const tsi, // Temperature of gap surface closest to zone (K)
4815 : int const IGap, // Gap number
4816 : Real64 const gr, // Gap gas Grashof number
4817 : Real64 const pr, // Gap gas Prandtl number
4818 : Real64 &gnu // Gap gas Nusselt number
4819 : )
4820 : {
4821 :
4822 : // SUBROUTINE INFORMATION:
4823 : // AUTHOR Adapted by Fred Winkelmann from Window5 subroutine nusselt
4824 : // DATE WRITTEN September 2001
4825 : // MODIFIED na
4826 : // RE-ENGINEERED na
4827 :
4828 : // PURPOSE OF THIS SUBROUTINE:
4829 : // Finds the Nusselt number for gas-filled gaps between isothermal solid layers.
4830 : // The gap may be filled with a single gas or a gas mixture.
4831 :
4832 : // METHODOLOGY EMPLOYED:
4833 : // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
4834 : // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
4835 : // The equation numbers below correspond to those in the standard.
4836 :
4837 : // REFERENCES:
4838 : // Window5 source code; ISO 15099
4839 :
4840 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4841 : Real64 asp; // Aspect ratio: window height to gap width
4842 : Real64 ra; // Rayleigh number
4843 : Real64 gnu901; // Nusselt number temporary variables for
4844 : Real64 gnu902;
4845 : Real64 gnu90;
4846 : Real64 gnu601;
4847 : Real64 gnu602; // different tilt and Ra ranges
4848 : Real64 gnu60;
4849 : Real64 gnu601a;
4850 : Real64 gnua;
4851 : Real64 gnub;
4852 : Real64 cra; // Temporary variables
4853 : Real64 a;
4854 : Real64 b;
4855 : Real64 g;
4856 : Real64 ang;
4857 :
4858 40358 : auto const &wm = state.dataWindowManager;
4859 :
4860 40358 : if (SurfNum > 0) {
4861 40270 : auto const &s_surf = state.dataSurface;
4862 40270 : asp = s_surf->Surface(SurfNum).Height / wm->gaps[IGap - 1].width;
4863 : } else { // SurfNum = 0 when NusseltNumber is called from CalcNominalWindowCond, which applies to a
4864 : // particular construction. So window height is not known and we assume 5 ft (1.524 m)
4865 88 : asp = 1.524 / wm->gaps[IGap - 1].width;
4866 : }
4867 :
4868 40358 : wm->tiltr = wm->tilt * Constant::DegToRad;
4869 40358 : ra = gr * pr;
4870 : //! fw if (ra > 2.0e6): error that outside range of Rayleigh number?
4871 :
4872 40358 : if (ra <= 1.0e4) {
4873 40357 : gnu901 = 1.0 + 1.7596678e-10 * std::pow(ra, 2.2984755); // eq. 51
4874 : }
4875 40358 : if (ra > 1.0e4 && ra <= 5.0e4) {
4876 1 : gnu901 = 0.028154 * std::pow(ra, 0.4134); // eq. 50
4877 : }
4878 40358 : if (ra > 5.0e4) {
4879 0 : gnu901 = 0.0673838 * std::pow(ra, 1.0 / 3.0); // eq. 49
4880 : }
4881 :
4882 40358 : gnu902 = 0.242 * std::pow(ra / asp, 0.272); // eq. 52
4883 40358 : gnu90 = max(gnu901, gnu902);
4884 :
4885 40358 : if (tso > tsi) { // window heated from above
4886 18283 : gnu = 1.0 + (gnu90 - 1.0) * std::sin(wm->tiltr); // eq. 53
4887 : } else { // window heated from below
4888 22075 : if (wm->tilt >= 60.0) {
4889 22069 : if (ra >= 0.001) {
4890 22069 : g = 0.5 * std::pow(1.0 + std::pow(ra / 3160.0, 20.6), -0.1); // eq. 47
4891 : } else {
4892 0 : g = 0.5;
4893 : }
4894 22069 : gnu601a = 1.0 + pow_7(0.0936 * std::pow(ra, 0.314) / (1.0 + g)); // eq. 45
4895 22069 : gnu601 = std::pow(gnu601a, 0.142857);
4896 :
4897 : // For any aspect ratio
4898 22069 : gnu602 = (0.104 + 0.175 / asp) * std::pow(ra, 0.283); // eq. 46
4899 22069 : gnu60 = max(gnu601, gnu602);
4900 :
4901 : // linear interpolation for layers inclined at angles between 60 and 90 deg
4902 22069 : gnu = ((90.0 - wm->tilt) * gnu60 + (wm->tilt - 60.0) * gnu90) / 30.0;
4903 : }
4904 22075 : if (wm->tilt < 60.0) { // eq. 42
4905 6 : cra = ra * std::cos(wm->tiltr);
4906 6 : a = 1.0 - 1708.0 / cra;
4907 6 : b = std::pow(cra / 5830.0, 0.33333) - 1.0;
4908 6 : gnua = (std::abs(a) + a) / 2.0;
4909 6 : gnub = (std::abs(b) + b) / 2.0;
4910 6 : ang = 1708.0 * std::pow(std::sin(1.8 * wm->tiltr), 1.6);
4911 6 : gnu = 1.0 + 1.44 * gnua * (1.0 - ang / cra) + gnub;
4912 : }
4913 : }
4914 40358 : } // NusseltNumber()
4915 :
4916 : //*******************************************************************************************************
4917 :
4918 22932 : void TransAndReflAtPhi(Real64 const cs, // Cosine of incidence angle
4919 : Real64 const tf0, // Transmittance at zero incidence angle
4920 : Real64 const rf0, // Front reflectance at zero incidence angle
4921 : Real64 const rb0, // Back reflectance at zero incidence angle
4922 : Real64 &tfp, // Transmittance at cs
4923 : Real64 &rfp, // Front reflectance at cs
4924 : Real64 &rbp, // Back reflectance at cs
4925 : bool const SimpleGlazingSystem, // .TRUE. if simple block model being used
4926 : Real64 const SimpleGlazingSHGC, // SHGC value to use in alternate model for simple glazing system
4927 : Real64 const SimpleGlazingU // U-factor value to use in alternate model for simple glazing system
4928 : )
4929 : {
4930 :
4931 : // SUBROUTINE INFORMATION:
4932 : // AUTHOR F. Winkelmann
4933 : // DATE WRITTEN January 2000
4934 : // MODIFIED 5 June 2003, FCW: modify to correspond to WINDOW 4 and WINDOW 5.
4935 : // Original routine was based on the method in E.U. Finlayson et al,
4936 : // "WINDOW 4.0: Documentation of Calculation Procedures," LBL-33943,
4937 : // July 1993, which is not used in either WINDOW 4 or WINDOW 5.
4938 : // The current routine is based on ASHRAE Handbook of Fundamentals,
4939 : // 2001, pp. 30.20-23, "Optical Properties of Single Glazing Layers."
4940 : // Original routine underpredicted transmittance at angles of
4941 : // incidence > 60 degrees.
4942 : // June 2009. Brent Griffith. add simple window correlation
4943 : // newer model from LBNL windows group 5/15/2009
4944 : // RE-ENGINEERED na
4945 :
4946 : // PURPOSE OF THIS SUBROUTINE:
4947 : // For a single glazing layer, calculate transmittance and reflectance at an arbitrary
4948 : // angle of incidence given transmittance and reflectance at zero incidence angle.
4949 :
4950 : // REFERENCES:
4951 : // ASHRAE Handbook of Fundamentals, 2001, pp. 30.20-23,
4952 : // "Optical Properties of Single Glazing Layers."
4953 :
4954 : Real64 tfp1; // Transmittance at cs for each polarization
4955 : Real64 tfp2;
4956 : Real64 rfp1; // Front reflectance at cs for each polarization
4957 : Real64 rfp2;
4958 : Real64 rbp1; // Back reflectance at cs for each polarization
4959 : Real64 rbp2;
4960 : Real64 betaf; // Intermediate variables
4961 : Real64 betab;
4962 : Real64 r0f;
4963 : Real64 r0b;
4964 : Real64 abf;
4965 : Real64 abb;
4966 : Real64 ngf; // Front and back index of refraction
4967 : Real64 ngb;
4968 : Real64 cgf; // Intermediate variables
4969 : Real64 cgb;
4970 : Real64 rpf1; // Front and back air/glass interface reflectivity
4971 : Real64 rpb1;
4972 : Real64 tpf1;
4973 : Real64 tpb1;
4974 : // and transmittivity for first polarization
4975 : Real64 rpf2; // Front and back air/glass interface reflectivity
4976 : Real64 rpb2;
4977 : Real64 tpf2;
4978 : Real64 tpb2;
4979 : // and transmittivity for second polarization
4980 : Real64 tcl; // Transmittance and reflectance for clear glass
4981 : Real64 rcl;
4982 : Real64 tbnz; // Transmittance and reflectance for bronze glass
4983 : Real64 rbnz;
4984 : Real64 expmabfdivcgf;
4985 : Real64 expm2abfdivcgf;
4986 : Real64 expmabbdivcgb;
4987 :
4988 : Real64 testval; // temporary value for calculations
4989 : Real64 tmp1; // temporary value for calculations
4990 : Real64 tmp2; // temporary value for calculations
4991 : Real64 tmp3; // temporary value for calculations
4992 : Real64 tmp4; // temporary value for calculations
4993 : Real64 tmp5; // temporary value for calculations
4994 : Real64 tmp6; // temporary value for calculations
4995 : Real64 tmp7; // temporary value for calculations
4996 : Real64 tmp8; // temporary value for calculations
4997 : Real64 tmp9; // temporary value for calculations
4998 :
4999 22932 : if (SimpleGlazingSystem) { // use alternate angular dependence model for block model of simple glazing input
5000 :
5001 491 : Real64 const cs_2(pow_2(cs));
5002 491 : Real64 const cs_3(pow_3(cs));
5003 491 : Real64 const cs_4(pow_4(cs));
5004 491 : Real64 TransCurveA = 0.00 + 3.36 * cs - 3.85 * cs_2 + 1.49 * cs_3 + 0.01 * cs_4;
5005 491 : Real64 TransCurveB = 0.00 + 2.83 * cs - 2.42 * cs_2 + 0.04 * cs_3 + 0.55 * cs_4;
5006 491 : Real64 TransCurveC = 0.00 + 2.45 * cs - 1.58 * cs_2 - 0.64 * cs_3 + 0.77 * cs_4;
5007 491 : Real64 TransCurveD = 0.00 + 2.85 * cs - 2.58 * cs_2 + 0.40 * cs_3 + 0.35 * cs_4;
5008 491 : Real64 TransCurveE = 0.00 + 1.51 * cs + 2.49 * cs_2 - 5.87 * cs_3 + 2.88 * cs_4;
5009 491 : Real64 TransCurveF = 0.00 + 1.21 * cs + 3.14 * cs_2 - 6.37 * cs_3 + 3.03 * cs_4;
5010 491 : Real64 TransCurveG = 0.00 + 1.09 * cs + 3.54 * cs_2 - 6.84 * cs_3 + 3.23 * cs_4;
5011 491 : Real64 TransCurveH = 0.00 + 0.98 * cs + 3.83 * cs_2 - 7.13 * cs_3 + 3.33 * cs_4;
5012 491 : Real64 TransCurveI = 0.00 + 0.79 * cs + 3.93 * cs_2 - 6.86 * cs_3 + 3.15 * cs_4;
5013 491 : Real64 TransCurveJ = 0.00 + 0.08 * cs + 6.02 * cs_2 - 8.84 * cs_3 + 3.74 * cs_4;
5014 491 : Real64 TransCurveFGHI = (TransCurveF + TransCurveG + TransCurveH + TransCurveI) / 4.0;
5015 491 : Real64 TransCurveFH = (TransCurveF + TransCurveH) / 2.0;
5016 491 : Real64 TransCurveBDCD = (TransCurveB + TransCurveD + TransCurveC + TransCurveD) / 4.0;
5017 :
5018 491 : Real64 ReflectCurveA = 1.00 - 0.70 * cs + 2.57 * cs_2 - 3.20 * cs_3 + 1.33 * cs_4 - TransCurveA;
5019 491 : Real64 ReflectCurveB = 1.00 - 1.87 * cs + 6.50 * cs_2 - 7.86 * cs_3 + 3.23 * cs_4 - TransCurveB;
5020 491 : Real64 ReflectCurveC = 1.00 - 2.52 * cs + 8.40 * cs_2 - 9.86 * cs_3 + 3.99 * cs_4 - TransCurveC;
5021 491 : Real64 ReflectCurveD = 1.00 - 1.85 * cs + 6.40 * cs_2 - 7.64 * cs_3 + 3.11 * cs_4 - TransCurveD;
5022 491 : Real64 ReflectCurveE = 1.00 - 1.57 * cs + 5.60 * cs_2 - 6.82 * cs_3 + 2.80 * cs_4 - TransCurveE;
5023 491 : Real64 ReflectCurveF = 1.00 - 3.15 * cs + 10.98 * cs_2 - 13.14 * cs_3 + 5.32 * cs_4 - TransCurveF;
5024 491 : Real64 ReflectCurveG = 1.00 - 3.25 * cs + 11.32 * cs_2 - 13.54 * cs_3 + 5.49 * cs_4 - TransCurveG;
5025 491 : Real64 ReflectCurveH = 1.00 - 3.39 * cs + 11.70 * cs_2 - 13.94 * cs_3 + 5.64 * cs_4 - TransCurveH;
5026 491 : Real64 ReflectCurveI = 1.00 - 4.06 * cs + 13.55 * cs_2 - 15.74 * cs_3 + 6.27 * cs_4 - TransCurveI;
5027 491 : Real64 ReflectCurveJ = 1.00 - 4.35 * cs + 14.27 * cs_2 - 16.32 * cs_3 + 6.39 * cs_4 - TransCurveJ;
5028 :
5029 491 : Real64 ReflectCurveFGHI = (ReflectCurveF + ReflectCurveG + ReflectCurveH + ReflectCurveI) / 4.0;
5030 491 : Real64 ReflectCurveFH = (ReflectCurveF + ReflectCurveH) / 2.0;
5031 491 : Real64 ReflectCurveBDCD = (ReflectCurveB + ReflectCurveD + ReflectCurveC + ReflectCurveD) / 4.0;
5032 :
5033 491 : Real64 TransTmp(0.0);
5034 491 : Real64 ReflectTmp(0.0);
5035 :
5036 491 : if (SimpleGlazingU < 1.4195) { // cell 1, 2, or 3
5037 80 : if (SimpleGlazingSHGC > 0.45) {
5038 : // cell # 1
5039 : // Curve E
5040 40 : TransTmp = TransCurveE;
5041 40 : ReflectTmp = ReflectCurveE;
5042 :
5043 40 : } else if ((0.35 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
5044 : // cell # 2
5045 : // 2 way interpolation between Curve E and Curve J
5046 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.35, 0.45, TransCurveJ, TransCurveE);
5047 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.35, 0.45, ReflectCurveJ, ReflectCurveE);
5048 :
5049 40 : } else if (SimpleGlazingSHGC < 0.35) {
5050 : // cell # 3
5051 : // Curve J
5052 40 : TransTmp = TransCurveJ;
5053 40 : ReflectTmp = ReflectCurveJ;
5054 : }
5055 :
5056 411 : } else if ((1.4195 <= SimpleGlazingU) && (SimpleGlazingU <= 1.7034)) { // cell 4, 5 , 6, 7, 8, 9, or 10
5057 0 : if (SimpleGlazingSHGC > 0.55) {
5058 : // cell # 4
5059 : // Curve E
5060 0 : TransTmp = TransCurveE;
5061 0 : ReflectTmp = ReflectCurveE;
5062 :
5063 0 : } else if ((0.5 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
5064 : // cell # 5
5065 : // 4 way interpolation between Curve E , Curve E, Curve E and Curve FGHI
5066 :
5067 0 : TransTmp = InterpolateBetweenFourValues(
5068 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.50, 0.55, TransCurveE, TransCurveE, TransCurveFGHI, TransCurveE);
5069 0 : ReflectTmp = InterpolateBetweenFourValues(
5070 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.50, 0.55, ReflectCurveE, ReflectCurveE, ReflectCurveFGHI, ReflectCurveE);
5071 :
5072 0 : } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.5)) {
5073 : // cell # 6
5074 : // 2 way interpolation between Curve E and Curve FGHI
5075 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveE, TransCurveFGHI);
5076 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveE, ReflectCurveFGHI);
5077 :
5078 0 : } else if ((0.35 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
5079 : // cell # 7
5080 : // 4 way interpolation between Curve E , Curve FGHI, Curve J and Curve FGHI
5081 0 : TransTmp = InterpolateBetweenFourValues(
5082 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.35, 0.45, TransCurveJ, TransCurveE, TransCurveFGHI, TransCurveFGHI);
5083 0 : ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
5084 : SimpleGlazingSHGC,
5085 : 1.4195,
5086 : 1.7034,
5087 : 0.35,
5088 : 0.45,
5089 : ReflectCurveJ,
5090 : ReflectCurveE,
5091 : ReflectCurveFGHI,
5092 : ReflectCurveFGHI);
5093 :
5094 0 : } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.35)) {
5095 : // cell # 8
5096 : // 2 way interpolation between Curve J and Curve FGHI
5097 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveJ, TransCurveFGHI);
5098 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveJ, ReflectCurveFGHI);
5099 :
5100 0 : } else if ((0.25 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
5101 : // cell # 9
5102 : // 4 way interpolation between Curve J, Curve FGHI, Curve J and Curve FH
5103 0 : TransTmp = InterpolateBetweenFourValues(
5104 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.25, 0.3, TransCurveJ, TransCurveJ, TransCurveFH, TransCurveFGHI);
5105 0 : ReflectTmp = InterpolateBetweenFourValues(
5106 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.25, 0.3, ReflectCurveJ, ReflectCurveJ, ReflectCurveFH, ReflectCurveFGHI);
5107 :
5108 0 : } else if (SimpleGlazingSHGC <= 0.25) {
5109 : // cell # 10
5110 : // 2 way interpolation between Curve J and Curve FH
5111 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveJ, TransCurveFH);
5112 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveJ, ReflectCurveFH);
5113 : }
5114 411 : } else if ((1.7034 < SimpleGlazingU) && (SimpleGlazingU < 3.4068)) { // cell 11, 12, 13, 14, or 15
5115 331 : if (SimpleGlazingSHGC > 0.55) {
5116 : // cell # 11
5117 : // Curve E
5118 0 : TransTmp = TransCurveE;
5119 0 : ReflectTmp = ReflectCurveE;
5120 :
5121 331 : } else if ((0.5 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
5122 : // cell # 12
5123 : // 2 way interpolation between Curve E and Curve FGHI
5124 80 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.5, 0.55, TransCurveFGHI, TransCurveE);
5125 80 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.5, 0.55, ReflectCurveFGHI, ReflectCurveE);
5126 :
5127 251 : } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC < 0.5)) {
5128 : // cell # 13
5129 : // Curve FGHI
5130 251 : TransTmp = TransCurveFGHI;
5131 251 : ReflectTmp = ReflectCurveFGHI;
5132 :
5133 0 : } else if ((0.25 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
5134 : // cell # 14
5135 : // 2 way interpolation between Curve FGHI and Curve FH
5136 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.25, 0.30, TransCurveFH, TransCurveFGHI);
5137 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.25, 0.30, ReflectCurveFH, ReflectCurveFGHI);
5138 :
5139 0 : } else if (SimpleGlazingSHGC < 0.25) {
5140 : // cell # 15
5141 : // Curve FH
5142 0 : TransTmp = TransCurveFH;
5143 0 : ReflectTmp = ReflectCurveFH;
5144 : }
5145 :
5146 80 : } else if ((3.4068 <= SimpleGlazingU) && (SimpleGlazingU <= 4.5424)) { // cell 16, 17, 18, 19, 20, 21, 22, or 23
5147 0 : if (SimpleGlazingSHGC > 0.65) {
5148 : // cell # 16
5149 : // 2 way interpolation between Curve E and Curve A
5150 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveE, TransCurveA);
5151 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveE, ReflectCurveA);
5152 :
5153 0 : } else if ((0.6 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.65)) {
5154 : // cell # 17
5155 : // 4 way interpolation between Curve E , Curve E, Curve A, and Curve BDCD
5156 0 : TransTmp = InterpolateBetweenFourValues(
5157 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.6, 0.65, TransCurveE, TransCurveE, TransCurveBDCD, TransCurveA);
5158 0 : ReflectTmp = InterpolateBetweenFourValues(
5159 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.6, 0.65, ReflectCurveE, ReflectCurveE, ReflectCurveBDCD, ReflectCurveA);
5160 :
5161 0 : } else if ((0.55 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.6)) {
5162 : // cell # 18
5163 : // 2 way interpolation between Curve E and Curve BDCD
5164 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveE, TransCurveBDCD);
5165 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveE, ReflectCurveBDCD);
5166 :
5167 0 : } else if ((0.5 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
5168 : // cell # 19
5169 : // 4 way interpolation between Curve E , Curve FGHI, Curve BDCD and Curve BDCD
5170 0 : TransTmp = InterpolateBetweenFourValues(
5171 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.5, 0.55, TransCurveFGHI, TransCurveE, TransCurveBDCD, TransCurveBDCD);
5172 0 : ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
5173 : SimpleGlazingSHGC,
5174 : 3.4068,
5175 : 4.5424,
5176 : 0.5,
5177 : 0.55,
5178 : ReflectCurveFGHI,
5179 : ReflectCurveE,
5180 : ReflectCurveBDCD,
5181 : ReflectCurveBDCD);
5182 :
5183 0 : } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.5)) {
5184 : // cell # 20
5185 : // 2 way interpolation between Curve FGHI and Curve BDCD
5186 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveFGHI, TransCurveBDCD);
5187 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveFGHI, ReflectCurveBDCD);
5188 :
5189 0 : } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
5190 : // cell # 21
5191 : // 4 way interpolation between Curve FGHI, Curve FGHI, Curve BDCD, and Curve D
5192 0 : TransTmp = InterpolateBetweenFourValues(
5193 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.3, 0.45, TransCurveFGHI, TransCurveFGHI, TransCurveD, TransCurveBDCD);
5194 0 : ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
5195 : SimpleGlazingSHGC,
5196 : 3.4068,
5197 : 4.5424,
5198 : 0.3,
5199 : 0.45,
5200 : ReflectCurveFGHI,
5201 : ReflectCurveFGHI,
5202 : ReflectCurveD,
5203 : ReflectCurveBDCD);
5204 :
5205 0 : } else if ((0.25 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
5206 : // cell # 22
5207 : // 4 way interpolation between Curve FGHI, Curve FH, Curve D, and Curve D
5208 0 : TransTmp = InterpolateBetweenFourValues(
5209 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.25, 0.3, TransCurveFH, TransCurveFGHI, TransCurveD, TransCurveD);
5210 0 : ReflectTmp = InterpolateBetweenFourValues(
5211 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.25, 0.3, ReflectCurveFH, ReflectCurveFGHI, ReflectCurveD, ReflectCurveD);
5212 :
5213 0 : } else if (SimpleGlazingSHGC <= 0.25) {
5214 : // cell # 23
5215 : // 2 way interpolation between Curve FH and Curve D
5216 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveFH, TransCurveD);
5217 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveFH, ReflectCurveD);
5218 : }
5219 80 : } else if (SimpleGlazingU > 4.5424) { // cell 24, 25, 26, 27, or 28
5220 80 : if (SimpleGlazingSHGC > 0.65) {
5221 : // cell # 24
5222 : // Curve A
5223 40 : TransTmp = TransCurveA;
5224 40 : ReflectTmp = ReflectCurveA;
5225 40 : } else if ((0.6 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.65)) {
5226 : // cell # 25
5227 : // 2 way interpolation between Curve A and Curve BDCD
5228 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.6, 0.65, TransCurveBDCD, TransCurveA);
5229 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.6, 0.65, ReflectCurveBDCD, ReflectCurveA);
5230 :
5231 40 : } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC < 0.6)) {
5232 : // cell # 26
5233 : // Curve BDCD
5234 0 : TransTmp = TransCurveBDCD;
5235 0 : ReflectTmp = ReflectCurveBDCD;
5236 :
5237 40 : } else if ((0.3 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
5238 : // cell # 27
5239 : // 2 way interpolation between Curve BDCD and Curve D
5240 40 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.3, 0.45, TransCurveD, TransCurveBDCD);
5241 40 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.3, 0.45, ReflectCurveD, ReflectCurveBDCD);
5242 :
5243 0 : } else if (SimpleGlazingSHGC < 0.3) {
5244 : // cell # 28
5245 : // Curve D
5246 0 : TransTmp = TransCurveD;
5247 0 : ReflectTmp = ReflectCurveD;
5248 :
5249 : } else {
5250 0 : assert(false);
5251 : }
5252 : } else {
5253 0 : assert(false);
5254 : }
5255 :
5256 491 : if (cs == 1.0) { // at 0 deg incident, TransTmp and ReflectTmp should be 1.0
5257 49 : TransTmp = 1.0;
5258 49 : ReflectTmp = 0.0;
5259 : }
5260 :
5261 : // now apply normalization factors to zero incidence angle properties
5262 491 : tfp = tf0 * TransTmp;
5263 491 : tfp = max(min(1.0, tfp), 0.0);
5264 :
5265 491 : rfp = rf0 * (1. - ReflectTmp) + ReflectTmp;
5266 491 : rfp = max(min(0.9999 - tfp, rfp), 0.0);
5267 :
5268 491 : rbp = rfp;
5269 :
5270 22441 : } else if (tf0 <= 0.0) {
5271 : // This is an opaque window. For all angles, set transmittance to 0; set reflectance to that at zero incidence angle.
5272 0 : tfp = 0.0;
5273 0 : rfp = rf0;
5274 0 : rbp = rb0;
5275 : } else {
5276 :
5277 22441 : betaf = pow_2(tf0) - pow_2(rf0) + 2.0 * rf0 + 1.0;
5278 22441 : betab = pow_2(tf0) - pow_2(rb0) + 2.0 * rb0 + 1.0;
5279 22441 : r0f = (betaf - std::sqrt(pow_2(betaf) - 4.0 * (2.0 - rf0) * rf0)) / (2.0 * (2.0 - rf0));
5280 22441 : r0b = (betab - std::sqrt(pow_2(betab) - 4.0 * (2.0 - rb0) * rb0)) / (2.0 * (2.0 - rb0));
5281 :
5282 22441 : tmp1 = std::abs(r0f - r0b);
5283 22441 : if (tmp1 != 0.0) {
5284 12680 : testval = std::abs(r0f - r0b) / (r0f + r0b);
5285 : } else {
5286 9761 : testval = 0.0;
5287 : }
5288 :
5289 22441 : if (testval < 0.001) { // CR8830, CR8942, implications of relaxation of glazing properties CR8413
5290 : // UNCOATED GLASS
5291 9761 : tmp1 = r0f * tf0;
5292 9761 : if (tmp1 != 0.0) {
5293 9761 : abf = std::log(tmp1 / (rf0 - r0f));
5294 : } else {
5295 0 : abf = 0.0;
5296 : }
5297 9761 : tmp2 = r0b * tf0;
5298 9761 : if (tmp2 != 0.0) {
5299 9761 : abb = std::log(tmp2 / (rb0 - r0b));
5300 : } else {
5301 0 : abb = 0.0;
5302 : }
5303 9761 : ngf = (1.0 + std::sqrt(r0f)) / (1.0 - std::sqrt(r0f));
5304 9761 : ngb = (1.0 + std::sqrt(r0b)) / (1.0 - std::sqrt(r0b));
5305 9761 : cgf = std::sqrt(1.0 - (1.0 - cs * cs) / pow_2(ngf));
5306 9761 : cgb = std::sqrt(1.0 - (1.0 - cs * cs) / pow_2(ngb));
5307 9761 : tmp3 = ngf * cs - cgf;
5308 9761 : if (tmp3 != 0.0) {
5309 9761 : rpf1 = pow_2(tmp3 / (ngf * cs + cgf));
5310 : } else {
5311 0 : rpf1 = 0.0;
5312 : }
5313 9761 : tmp4 = ngf * cgf - cs;
5314 9761 : if (tmp4 != 0.0) {
5315 9761 : rpf2 = pow_2(tmp4 / (ngf * cgf + cs));
5316 : } else {
5317 0 : rpf2 = 0.0;
5318 : }
5319 9761 : tpf1 = 1 - rpf1;
5320 9761 : tpf2 = 1 - rpf2;
5321 9761 : tmp5 = ngb * cs - cgb;
5322 9761 : if (tmp5 != 0.0) {
5323 9761 : rpb1 = pow_2(tmp5 / (ngb * cs + cgb));
5324 : } else {
5325 0 : rpb1 = 0.0;
5326 : }
5327 9761 : tmp6 = ngb * cgb - cs;
5328 9761 : if (tmp6 != 0.0) {
5329 9761 : rpb2 = pow_2(tmp6 / (ngb * cgb + cs));
5330 : } else {
5331 0 : rpb2 = 0.0;
5332 : }
5333 9761 : tpb1 = 1 - rpf1;
5334 9761 : tpb2 = 1 - rpf2;
5335 9761 : tmp7 = -abf;
5336 9761 : if (cgf != 0.0) {
5337 9761 : expmabfdivcgf = std::exp(tmp7 / cgf);
5338 : } else {
5339 0 : expmabfdivcgf = 0.0;
5340 : }
5341 9761 : tmp8 = -2.0 * abf;
5342 9761 : if (cgf != 0.0) {
5343 9761 : expm2abfdivcgf = std::exp(tmp8 / cgf);
5344 : } else {
5345 0 : expm2abfdivcgf = 0.0;
5346 : }
5347 9761 : if (tpf1 != 0.0) {
5348 9761 : tfp1 = pow_2(tpf1) * expmabfdivcgf / (1.0 - pow_2(rpf1) * expm2abfdivcgf);
5349 : } else {
5350 0 : tfp1 = 0.0;
5351 : }
5352 9761 : rfp1 = rpf1 * (1.0 + tfp1 * expmabfdivcgf);
5353 9761 : if (tpf2 != 0.0) {
5354 8805 : tfp2 = pow_2(tpf2) * expmabfdivcgf / (1.0 - pow_2(rpf2) * expm2abfdivcgf);
5355 : } else {
5356 956 : tfp2 = 0.0;
5357 : }
5358 9761 : rfp2 = rpf2 * (1.0 + tfp2 * expmabfdivcgf);
5359 9761 : tfp = 0.5 * (tfp1 + tfp2);
5360 9761 : rfp = 0.5 * (rfp1 + rfp2);
5361 9761 : tmp9 = -abb;
5362 9761 : if (tmp9 != 0.0) {
5363 9761 : expmabbdivcgb = std::exp(tmp9 / cgb);
5364 : } else {
5365 0 : expmabbdivcgb = 0.0;
5366 : }
5367 9761 : rbp1 = rpb1 * (1.0 + tfp1 * expmabbdivcgb);
5368 9761 : rbp2 = rpb2 * (1.0 + tfp2 * expmabbdivcgb);
5369 9761 : rbp = 0.5 * (rbp1 + rbp2);
5370 : } else {
5371 : // COATED GLASS
5372 12680 : if (tf0 > 0.645) {
5373 : // Use clear glass angular distribution.
5374 : // Normalized clear glass transmittance and reflectance distribution
5375 12500 : if (cs > 0.999) { // Angle of incidence = 0 deg
5376 1250 : tcl = 1.0;
5377 1250 : rcl = 0.0;
5378 11250 : } else if (cs < 0.001) { // Angle of incidence = 90 deg
5379 1250 : tcl = 0.0;
5380 1250 : rcl = 1.0;
5381 : } else {
5382 10000 : tcl = -0.0015 + (3.355 + (-3.840 + (1.460 + 0.0288 * cs) * cs) * cs) * cs;
5383 10000 : rcl = 0.999 + (-0.563 + (2.043 + (-2.532 + 1.054 * cs) * cs) * cs) * cs - tcl;
5384 : }
5385 12500 : tfp = tf0 * tcl;
5386 12500 : rfp = rf0 * (1.0 - rcl) + rcl;
5387 12500 : rbp = rb0 * (1.0 - rcl) + rcl;
5388 : } else {
5389 : // Use bronze glass angular distribution.
5390 : // Normalized bronze tinted glass transmittance and reflectance distribution
5391 180 : if (cs > 0.999) { // Angle of incidence = 0 deg
5392 18 : tbnz = 1.0;
5393 18 : rbnz = 0.0;
5394 162 : } else if (cs < 0.001) { // Angle of incidence = 90 deg
5395 18 : tbnz = 0.0;
5396 18 : rbnz = 1.0;
5397 : } else {
5398 144 : tbnz = -0.002 + (2.813 + (-2.341 + (-0.05725 + 0.599 * cs) * cs) * cs) * cs;
5399 144 : rbnz = 0.997 + (-1.868 + (6.513 + (-7.862 + 3.225 * cs) * cs) * cs) * cs - tbnz;
5400 : }
5401 180 : tfp = tf0 * tbnz;
5402 180 : rfp = rf0 * (1.0 - rbnz) + rbnz;
5403 180 : rbp = rb0 * (1.0 - rbnz) + rbnz;
5404 : }
5405 : }
5406 : }
5407 :
5408 : // total absorptance cannot be negative
5409 22932 : assert(1.0 - rfp - tfp >= -1e6);
5410 22932 : assert(1.0 - rbp - tfp >= -1e6);
5411 22932 : } // TransAndReflAtPhi()
5412 :
5413 240 : Real64 InterpolateBetweenTwoValues(Real64 const X, Real64 const X0, Real64 const X1, Real64 const F0, Real64 const F1)
5414 : {
5415 :
5416 : // FUNCTION INFORMATION:
5417 : // AUTHOR Brent Griffith
5418 : // DATE WRITTEN June 2009
5419 : // MODIFIED na
5420 : // RE-ENGINEERED na
5421 :
5422 : // PURPOSE OF THIS FUNCTION:
5423 : // Interpolate between two results
5424 :
5425 : // METHODOLOGY EMPLOYED:
5426 : // linear interpolation
5427 :
5428 : Real64 InterpResult;
5429 :
5430 240 : InterpResult = F0 + ((X - X0) / (X1 - X0)) * (F1 - F0);
5431 240 : return InterpResult;
5432 : } // InterpolateBetweenTwoValues()
5433 :
5434 0 : Real64 InterpolateBetweenFourValues(Real64 const X,
5435 : Real64 const Y,
5436 : Real64 const X1,
5437 : Real64 const X2,
5438 : Real64 const Y1,
5439 : Real64 const Y2,
5440 : Real64 const Fx1y1,
5441 : Real64 const Fx1y2,
5442 : Real64 const Fx2y1,
5443 : Real64 const Fx2y2)
5444 : {
5445 :
5446 : // FUNCTION INFORMATION:
5447 : // AUTHOR Brent Griffith
5448 : // DATE WRITTEN June 2009
5449 : // MODIFIED na
5450 : // RE-ENGINEERED na
5451 :
5452 : // PURPOSE OF THIS FUNCTION:
5453 : // Interpolate between four results.
5454 :
5455 : // METHODOLOGY EMPLOYED:
5456 : // bilinear interpolation (approximate)
5457 :
5458 : // REFERENCES:
5459 : // http://en.wikipedia.org/wiki/Bilinear_interpolation
5460 :
5461 : // Return value
5462 : Real64 InterpResult;
5463 :
5464 0 : InterpResult = (Fx1y1 / ((X2 - X1) * (Y2 - Y1))) * (X2 - X) * (Y2 - Y) + (Fx2y1 / ((X2 - X1) * (Y2 - Y1))) * (X - X1) * (Y2 - Y) +
5465 0 : (Fx1y2 / ((X2 - X1) * (Y2 - Y1))) * (X2 - X) * (Y - Y1) + (Fx2y2 / ((X2 - X1) * (Y2 - Y1))) * (X - X1) * (Y - Y1);
5466 0 : return InterpResult;
5467 : } // InterpolateBetweenFourValues()
5468 :
5469 : //**************************************************************************
5470 546 : void W5LsqFit(std::array<Real64, numPhis> const &ivars, // Independent variables
5471 : std::array<Real64, numPhis> const &dvars, // Dependent variables
5472 : std::array<Real64, maxPolyCoef> &coeffs // Polynomial coefficients from fit
5473 : )
5474 : {
5475 :
5476 : // SUBROUTINE INFORMATION:
5477 : // AUTHOR George Walton
5478 : // DATE WRITTEN April 1976
5479 : // MODIFIED November 1999 F.Winkelmann
5480 : // RE-ENGINEERED na
5481 :
5482 : // PURPOSE OF THIS SUBROUTINE:
5483 : // Does least squares fit for coefficients of a polynomial
5484 : // that gives a window property, such as transmittance, as a function of
5485 : // the cosine of the angle of incidence. The polynomial is of the
5486 : // form C1*X + C2*X**2 + C3*X**3 + ... +CN*X**N, where N <= 6.
5487 : // Adapted from BLAST subroutine LSQFIT.
5488 :
5489 : std::array<std::array<Real64, maxPolyCoef>, maxPolyCoef> A; // Least squares derivative matrix
5490 : std::array<Real64, maxPolyCoef> B; // Least squares derivative vector
5491 : std::array<std::array<Real64, 16>, maxPolyCoef> D; // Powers of independent variable
5492 :
5493 : // Set up least squares matrix
5494 6006 : for (int M = 0; M < numPhis; ++M) {
5495 5460 : D[0][M] = ivars[M];
5496 : }
5497 :
5498 3276 : for (int i = 1; i < maxPolyCoef; ++i) {
5499 30030 : for (int M = 0; M < numPhis; ++M) {
5500 27300 : D[i][M] = D[i - 1][M] * ivars[M];
5501 : }
5502 : }
5503 :
5504 3822 : for (int i = 0; i < maxPolyCoef; ++i) {
5505 3276 : Real64 SUM = 0.0;
5506 36036 : for (int M = 0; M < numPhis; ++M) {
5507 32760 : SUM += dvars[M] * D[i][M];
5508 : }
5509 3276 : B[i] = SUM;
5510 22932 : for (int j = 0; j < maxPolyCoef; ++j) {
5511 19656 : Real64 SUM2 = 0.0;
5512 216216 : for (int M = 0; M < numPhis; ++M) {
5513 196560 : SUM2 += D[i][M] * D[j][M];
5514 : }
5515 19656 : A[j][i] = SUM2;
5516 19656 : A[i][j] = SUM2;
5517 : }
5518 : }
5519 :
5520 : // Solve the simultaneous equations using Gauss elimination
5521 546 : int order1 = maxPolyCoef - 1;
5522 3276 : for (int K = 0; K < order1; ++K) {
5523 2730 : int KP1 = K + 1;
5524 10920 : for (int i = KP1; i < maxPolyCoef; ++i) {
5525 8190 : Real64 ACON = A[K][i] / A[K][K];
5526 8190 : B[i] -= B[K] * ACON;
5527 46410 : for (int j = K; j < maxPolyCoef; ++j) {
5528 38220 : A[j][i] -= A[j][K] * ACON;
5529 : }
5530 : }
5531 : }
5532 :
5533 : // Perform back substitution
5534 546 : coeffs[maxPolyCoef - 1] = B[maxPolyCoef - 1] / A[maxPolyCoef - 1][maxPolyCoef - 1];
5535 546 : int LP1 = maxPolyCoef - 1;
5536 546 : int L = maxPolyCoef - 2;
5537 :
5538 3276 : while (L >= 0) {
5539 2730 : Real64 SUM = 0.0;
5540 10920 : for (int j = LP1; j < maxPolyCoef; ++j) {
5541 8190 : SUM += A[j][L] * coeffs[j];
5542 : }
5543 2730 : coeffs[L] = (B[L] - SUM) / A[L][L];
5544 2730 : LP1 = L;
5545 2730 : --L;
5546 : }
5547 546 : } // W5LsqFit()
5548 :
5549 : //********************************************************************************
5550 :
5551 0 : void W5LsqFit2(Array1A<Real64> const IndepVar, // Independent variables
5552 : Array1A<Real64> const DepVar, // Dependent variables
5553 : int const N, // Order of polynomial
5554 : int const N1, // First and last data points used
5555 : int const N2,
5556 : Array1A<Real64> CoeffsCurve // Polynomial coefficients from fit
5557 : )
5558 : {
5559 :
5560 : // SUBROUTINE INFORMATION:
5561 : // AUTHOR George Walton
5562 : // DATE WRITTEN April 1976
5563 : // MODIFIED November 1999 F.Winkelmann
5564 : // May 2001 F. Winkelmann, to do 19 indep. variables
5565 : // RE-ENGINEERED na
5566 :
5567 : // PURPOSE OF THIS SUBROUTINE:
5568 : // Does least squares fit for coefficients of a polynomial
5569 : // that gives a window property, such as transmittance, as a function of
5570 : // the cosine of the angle of incidence. The polynomial is of the
5571 : // form C1*X + C2*X**2 + C3*X**3 + ... +CN*X**N, where N <= 6.
5572 : // Adapted from BLAST subroutine LSQFIT.
5573 :
5574 : // Argument array dimensioning
5575 0 : IndepVar.dim(19);
5576 0 : DepVar.dim(19);
5577 0 : CoeffsCurve.dim(6);
5578 :
5579 0 : Array2D<Real64> A(6, 6); // Least squares derivative matrix
5580 0 : Array1D<Real64> B(6); // Least squares derivative vector
5581 0 : Array2D<Real64> D(6, 16); // Powers of independent variable
5582 : Real64 ACON; // Intermediate variables
5583 : Real64 SUM;
5584 : int LP1;
5585 : int NM1;
5586 :
5587 : // Set up least squares matrix
5588 0 : for (int M = N1; M <= N2; ++M) {
5589 0 : D(1, M) = IndepVar(M);
5590 : }
5591 :
5592 0 : for (int i = 2; i <= N; ++i) {
5593 0 : for (int M = N1; M <= N2; ++M) {
5594 0 : D(i, M) = D(i - 1, M) * IndepVar(M);
5595 : }
5596 : }
5597 :
5598 0 : for (int i = 1; i <= N; ++i) {
5599 0 : SUM = 0.0;
5600 0 : for (int M = N1; M <= N2; ++M) {
5601 0 : SUM += DepVar(M) * D(i, M);
5602 : }
5603 0 : B(i) = SUM;
5604 0 : for (int j = 1; j <= N; ++j) {
5605 0 : SUM = 0.0;
5606 0 : for (int M = N1; M <= N2; ++M) {
5607 0 : SUM += D(i, M) * D(j, M);
5608 : }
5609 0 : A(j, i) = SUM;
5610 0 : A(i, j) = SUM;
5611 : }
5612 : }
5613 :
5614 : // Solve the simultaneous equations using Gauss elimination
5615 0 : NM1 = N - 1;
5616 0 : for (int K = 1; K <= NM1; ++K) {
5617 0 : int KP1 = K + 1;
5618 0 : for (int i = KP1; i <= N; ++i) {
5619 0 : ACON = A(K, i) / A(K, K);
5620 0 : B(i) -= B(K) * ACON;
5621 0 : for (int j = K; j <= N; ++j) {
5622 0 : A(j, i) -= A(j, K) * ACON;
5623 : }
5624 : }
5625 : }
5626 :
5627 : // Perform back substitution
5628 0 : CoeffsCurve(N) = B(N) / A(N, N);
5629 0 : LP1 = N;
5630 0 : int L = N - 1;
5631 :
5632 0 : while (L > 0) {
5633 0 : SUM = 0.0;
5634 0 : for (int j = LP1; j <= N; ++j) {
5635 0 : SUM += A(j, L) * CoeffsCurve(j);
5636 : }
5637 0 : CoeffsCurve(L) = (B(L) - SUM) / A(L, L);
5638 0 : LP1 = L;
5639 0 : --L;
5640 : }
5641 0 : } // W5LsqFit2()
5642 :
5643 : //***********************************************************************
5644 :
5645 1982 : Real64 DiffuseAverage(std::array<Real64, numPhis> const &props) // Property value at angles of incidence
5646 : {
5647 :
5648 : // FUNCTION INFORMATION:
5649 : // AUTHOR Fred Winkelmann
5650 : // DATE WRITTEN November 1999
5651 : // MODIFIED na
5652 : // RE-ENGINEERED na
5653 :
5654 : // PURPOSE OF THIS FUNCTION:
5655 : // Calculate value of property, such as transmittance, for hemispherical
5656 : // diffuse radiation from property values at angles of incidence from
5657 : // 0 to 90 degrees in 10 degree increments.
5658 :
5659 : // METHODOLOGY EMPLOYED:
5660 : // By Simpson's rule, evaluates the integral from 0 to 90 deg of
5661 : // 2*PropertyValue(phi)*cos(phi)*sin(phi)*dphi (which is same as
5662 : // PropertyValue(phi)*sin(2*phi)*dphi)
5663 :
5664 : // Locals
5665 : // SUBROUTINE ARGUMENT DEFINITIONS:
5666 : // 0,10,20,...,80,90 degrees
5667 :
5668 1982 : constexpr Real64 dPhiR = dPhiDeg * Constant::DegToRad; // Half of 10-deg incidence angle increment (radians)
5669 :
5670 1982 : Real64 avg = 0.0;
5671 19820 : for (int iPhi = 0; iPhi < numPhis - 1; ++iPhi) {
5672 17838 : avg += 0.5 * dPhiR * (props[iPhi] * std::sin(2.0 * iPhi * dPhiR) + props[iPhi + 1] * std::sin(2.0 * (iPhi + 1) * dPhiR));
5673 : }
5674 :
5675 1982 : return (avg < 0.0) ? 0.0 : avg;
5676 : } // DiffuseAverage()
5677 :
5678 : //*************************************************************************************
5679 :
5680 9 : void CalcWinFrameAndDividerTemps(EnergyPlusData &state,
5681 : int const SurfNum, // Surface number
5682 : Real64 const tout, // Outside air temperature (K)
5683 : Real64 const tin, // Inside air temperature (K)
5684 : Real64 const HOutConv, // Outside convective air film conductance (W/m2-K)
5685 : Real64 const HInConv, // Inside convective air film conductance (W/m2-K)
5686 : Real64 const Outir, // Exterior IR irradiance from sky and ground
5687 : int const ConstrNum // Construction number of window
5688 : )
5689 : {
5690 :
5691 : // SUBROUTINE INFORMATION:
5692 : // AUTHOR F. Winkelmann
5693 : // DATE WRITTEN May 2000
5694 : // MODIFIED Aug 2000, FCW: Add effect of frame and divider projections
5695 : // Jun 2001, FCW: Add frame/divider contribution to WinHeatGain
5696 : // Aug 2003, FCW: Fix calculation of divider outside temp: frame
5697 : // inside temp was being used instead of divider inside temp
5698 : // RE-ENGINEERED na
5699 :
5700 : // PURPOSE OF THIS SUBROUTINE:
5701 : // Calculates window frame divider face temperatures from a linearized
5702 : // heat balance on the inside and outside faces
5703 :
5704 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5705 : Real64 HInRad; // Inside radiative conductance (W/m2-K)
5706 : Real64 HOutRad; // Outside radiative conductance (W/m2-K)
5707 : int FrDivNum; // Frame/divider number
5708 : Real64 TInRad; // Inside radiative temperature (K)
5709 : Real64 TInRadFr; // Effective inside radiative temperature for frame (K)
5710 : Real64 TInRadDiv; // Effective inside radiative temperature for divider (K)
5711 : Real64 TOutRad; // Outside radiative temperature (K)
5712 : Real64 TOutRadFr; // Effective outside radiative temperature for frame (K)
5713 : Real64 TOutRadDiv; // Effective outside radiative temperature for divider (K)
5714 : WinShadingType ShadeFlag; // Window shading flag
5715 : Real64 FrameCon; // Frame conductance (W/m2-K)
5716 :
5717 : Real64 Afac; // Intermediate calculation variables
5718 : Real64 Bfac;
5719 : Real64 Dfac;
5720 : Real64 Efac;
5721 : DataSurfaces::FrameDividerType DivType; // Divider type
5722 : Real64 DivCon; // Divider conductance (W/m2-K)
5723 : Real64 DivEmisIn; // Inside divider emissivity
5724 : Real64 DivEmisOut; // Outside divider emissivity
5725 :
5726 : Real64 ProjCorrFrOut; // Outside correction factor for absorbed radiation
5727 : // for frame with outside projection
5728 : Real64 ProjCorrFrIn; // Inside correction factor for absorbed radiation
5729 : // for frame with inside projection
5730 : Real64 HOutConvFr; // Effective outside convective coeff for frame
5731 : // with outside projection (W/m2-K)
5732 : Real64 HOutConvDiv; // Effective outside convective coeff for divider
5733 : // with outside projection (W/m2-K)
5734 : Real64 HInConvFr; // Effective inside convective coeff for frame
5735 : // with inside projection (W/m2-K)
5736 : Real64 HInConvDiv; // Effective inside convective coeff for divider
5737 : // with inside projection (W/m2-K)
5738 : Real64 EmisGlassOut; // Outside surface emissivity of window glazing
5739 : Real64 EmisGlassIn; // Inside surface emissivity of window glazing
5740 : int TotGlassLayers; // Total number of glass layers
5741 : int TotLayers; // Total number of layers in unshaded construction
5742 : // Real64 DivTempOut; // Outside surface divider temperature (K)
5743 : Real64 FrameHeatGain; // Heat gain to zone from frame (W)
5744 : // Real64 FrameHeatTransfer; // Heat transfer through frame (W)
5745 : // Real64 ProjCorrWinHeatGain; // Inside projection correction to IR from divider to zone
5746 : // for window heat gain calculation
5747 : Real64 DividerHeatGain; // Heat gain to zone from divider (W)
5748 : // Real64 DividerHeatTransfer; // Heat transfer through divider (W)
5749 :
5750 9 : auto &s_mat = state.dataMaterial;
5751 9 : auto &s_surf = state.dataSurface;
5752 :
5753 9 : auto const &surfWin = s_surf->SurfaceWindow(SurfNum);
5754 :
5755 9 : TInRad = root_4(s_surf->SurfWinIRfromParentZone(SurfNum) / Constant::StefanBoltzmann);
5756 9 : TOutRad = root_4(Outir / Constant::StefanBoltzmann);
5757 9 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
5758 9 : FrDivNum = s_surf->Surface(SurfNum).FrameDivider;
5759 9 : auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
5760 9 : TotLayers = thisConstruct.TotLayers;
5761 9 : TotGlassLayers = thisConstruct.TotSolidLayers;
5762 9 : EmisGlassOut = s_mat->materials(thisConstruct.LayerPoint(1))->AbsorpThermalFront;
5763 9 : EmisGlassIn = s_mat->materials(thisConstruct.LayerPoint(TotLayers))->AbsorpThermalBack;
5764 9 : FrameHeatGain = 0.0;
5765 9 : DividerHeatGain = 0.0;
5766 9 : s_surf->SurfWinFrameHeatGain(SurfNum) = 0.0;
5767 9 : s_surf->SurfWinFrameHeatLoss(SurfNum) = 0.0;
5768 9 : s_surf->SurfWinDividerHeatGain(SurfNum) = 0.0;
5769 9 : s_surf->SurfWinDividerHeatLoss(SurfNum) = 0.0;
5770 :
5771 9 : if (s_surf->SurfWinFrameArea(SurfNum) > 0.0) {
5772 : // Window has a frame. Note that if a shade, screen or blind is present it covers only the glazed part of the
5773 : // window and is assumed not to shadow long- or short-wave radiation incident on the frame elements.
5774 9 : ProjCorrFrOut = s_surf->SurfWinProjCorrFrOut(SurfNum);
5775 9 : ProjCorrFrIn = s_surf->SurfWinProjCorrFrIn(SurfNum);
5776 9 : TOutRadFr = TOutRad * root_4((1.0 + 0.5 * ProjCorrFrOut) / (1.0 + ProjCorrFrOut));
5777 9 : TInRadFr = TInRad * root_4((1.0 + 0.5 * ProjCorrFrIn) / (1.0 + ProjCorrFrIn));
5778 9 : FrameCon = s_surf->SurfWinFrameConductance(SurfNum);
5779 9 : HInRad = 0.5 * s_surf->SurfWinFrameEmis(SurfNum) * Constant::StefanBoltzmann *
5780 9 : pow_3(TInRadFr + s_surf->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin);
5781 9 : HInConvFr = HInConv;
5782 9 : HOutRad = 0.5 * s_surf->SurfWinFrameEmis(SurfNum) * Constant::StefanBoltzmann *
5783 9 : pow_3(TOutRadFr + s_surf->SurfWinFrameTempSurfOut(SurfNum) + Constant::Kelvin);
5784 9 : HOutConvFr = HOutConv;
5785 9 : auto const &frdiv = s_surf->FrameDivider(FrDivNum);
5786 9 : if (frdiv.FrameProjectionOut > 0.0) {
5787 0 : HOutRad *= (1.0 + ProjCorrFrOut);
5788 0 : HOutConvFr = HOutConv * (1.0 + ProjCorrFrOut);
5789 : // Add long-wave from outside window surface absorbed by frame outside projection
5790 0 : s_surf->SurfWinFrameQRadOutAbs(SurfNum) += 0.5 * s_surf->SurfWinProjCorrFrOut(SurfNum) * frdiv.FrameEmis * EmisGlassOut *
5791 0 : Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[1]);
5792 : }
5793 9 : if (frdiv.FrameProjectionIn > 0.0) {
5794 0 : HInRad *= (1.0 + ProjCorrFrIn);
5795 0 : HInConvFr = HInConv * (1.0 + ProjCorrFrIn);
5796 : // Add long-wave from inside window surface absorbed by frame inside projection
5797 0 : s_surf->SurfWinFrameQRadInAbs(SurfNum) += 0.5 * s_surf->SurfWinProjCorrFrIn(SurfNum) * frdiv.FrameEmis * EmisGlassIn *
5798 0 : Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[2 * TotGlassLayers]);
5799 : }
5800 9 : Afac = (HOutRad * TOutRadFr + HOutConvFr * tout + s_surf->SurfWinFrameQRadOutAbs(SurfNum)) / (HOutRad + FrameCon + HOutConvFr);
5801 9 : Bfac = FrameCon / (HOutRad + FrameCon + HOutConvFr);
5802 9 : Dfac = (HInRad * TInRadFr + HInConvFr * tin + s_surf->SurfWinFrameQRadInAbs(SurfNum)) / (HInRad + FrameCon + HInConvFr);
5803 9 : Efac = FrameCon / (HInRad + FrameCon + HInConvFr);
5804 9 : s_surf->SurfWinFrameTempIn(SurfNum) = (Dfac + Efac * Afac) / (1.0 - Efac * Bfac) - Constant::Kelvin;
5805 9 : s_surf->SurfWinFrameTempSurfOut(SurfNum) = Afac + Bfac * (s_surf->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin) - Constant::Kelvin;
5806 : // Heat gain to zone from frame
5807 :
5808 : // FrameHeatTransfer = s_surf->SurfWinFrameArea(SurfNum) * FrameCon *
5809 : // (s_surf->SurfWinFrameTempSurfOut(SurfNum) - s_surf->SurfWinFrameTempIn(SurfNum));
5810 9 : FrameHeatGain = s_surf->SurfWinFrameArea(SurfNum) * (1.0 + s_surf->SurfWinProjCorrFrIn(SurfNum)) *
5811 9 : (HInConvFr * (s_surf->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin - tin));
5812 :
5813 9 : if (FrameHeatGain > 0.0) {
5814 0 : s_surf->SurfWinFrameHeatGain(SurfNum) = FrameHeatGain;
5815 : } else {
5816 9 : s_surf->SurfWinFrameHeatLoss(SurfNum) = std::abs(FrameHeatGain);
5817 : }
5818 :
5819 9 : s_surf->SurfWinHeatGain(SurfNum) += FrameHeatGain;
5820 9 : s_surf->SurfWinGainFrameDividerToZoneRep(SurfNum) = FrameHeatGain;
5821 : } // End of check if window has a frame
5822 :
5823 9 : if (s_surf->SurfWinDividerArea(SurfNum) > 0.0 && s_surf->SurfWinStormWinFlag(SurfNum) < 1) {
5824 : // Window has divider. Note that if the window has a storm window layer in place (StormWinFlag = 1)
5825 : // the divider heat transfer calculation is not done.
5826 :
5827 9 : DivType = s_surf->SurfWinDividerType(SurfNum);
5828 9 : DivCon = s_surf->SurfWinDividerConductance(SurfNum);
5829 :
5830 9 : if (DivType == DataSurfaces::FrameDividerType::DividedLite) { // Divided lite
5831 9 : DivEmisIn = s_surf->SurfWinDividerEmis(SurfNum);
5832 9 : DivEmisOut = DivEmisIn;
5833 : } else { // Suspended (between-glass) divider
5834 0 : DivEmisOut = s_mat->materials(thisConstruct.LayerPoint(1))->AbsorpThermalFront;
5835 0 : DivEmisIn = s_mat->materials(thisConstruct.LayerPoint(thisConstruct.TotLayers))->AbsorpThermalBack;
5836 : }
5837 :
5838 9 : TOutRadDiv = TOutRad * root_4((1.0 + s_surf->SurfWinProjCorrDivOut(SurfNum)) / (1.0 + 2.0 * s_surf->SurfWinProjCorrDivOut(SurfNum)));
5839 9 : TInRadDiv = TInRad * root_4((1.0 + s_surf->SurfWinProjCorrDivIn(SurfNum)) / (1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum)));
5840 9 : HInRad = 0.5 * DivEmisIn * Constant::StefanBoltzmann * pow_3(TInRadDiv + s_surf->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin);
5841 9 : HOutRad =
5842 9 : 0.5 * DivEmisOut * Constant::StefanBoltzmann * pow_3(TOutRadDiv + s_surf->SurfWinDividerTempSurfOut(SurfNum) + Constant::Kelvin);
5843 9 : HOutConvDiv = HOutConv;
5844 9 : auto const &frdiv = s_surf->FrameDivider(FrDivNum);
5845 9 : if (frdiv.DividerProjectionOut > 0.0) {
5846 0 : HOutRad *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivOut(SurfNum));
5847 0 : if (s_surf->SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade) {
5848 0 : HOutConvDiv = s_surf->SurfWinConvCoeffWithShade(SurfNum);
5849 : }
5850 0 : HOutConvDiv *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivOut(SurfNum));
5851 : // Add long-wave from outside window surface absorbed by divider outside projection
5852 0 : s_surf->SurfWinDividerQRadOutAbs(SurfNum) += s_surf->SurfWinProjCorrDivOut(SurfNum) * frdiv.DividerEmis * EmisGlassOut *
5853 0 : Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[1]);
5854 : }
5855 :
5856 9 : HInConvDiv = HInConv;
5857 :
5858 9 : if (frdiv.DividerProjectionIn > 0.0) {
5859 0 : HInRad *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum));
5860 0 : if (s_surf->SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade) {
5861 0 : HInConvDiv = s_surf->SurfWinConvCoeffWithShade(SurfNum);
5862 : }
5863 0 : HInConvDiv *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum));
5864 : // Add long-wave from inside window surface absorbed by divider inside projection
5865 0 : s_surf->SurfWinDividerQRadInAbs(SurfNum) += s_surf->SurfWinProjCorrDivIn(SurfNum) * frdiv.DividerEmis * EmisGlassIn *
5866 0 : Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[2 * TotGlassLayers]);
5867 : }
5868 9 : Afac = (HOutRad * TOutRadDiv + HOutConvDiv * tout + s_surf->SurfWinDividerQRadOutAbs(SurfNum)) / (HOutRad + DivCon + HOutConvDiv);
5869 9 : Bfac = DivCon / (HOutRad + DivCon + HOutConvDiv);
5870 9 : Dfac = (HInRad * TInRadDiv + HInConvDiv * tin + s_surf->SurfWinDividerQRadInAbs(SurfNum)) / (HInRad + DivCon + HInConvDiv);
5871 9 : Efac = DivCon / (HInRad + DivCon + HInConvDiv);
5872 9 : s_surf->SurfWinDividerTempIn(SurfNum) = (Dfac + Efac * Afac) / (1 - Efac * Bfac) - Constant::Kelvin;
5873 9 : s_surf->SurfWinDividerTempSurfOut(SurfNum) = Afac + Bfac * (s_surf->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin) - Constant::Kelvin;
5874 : // Contribution of divider to window heat gain
5875 : // ProjCorrWinHeatGain = 1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum);
5876 :
5877 9 : DividerHeatGain = s_surf->SurfWinDividerArea(SurfNum) * (1.0 + s_surf->SurfWinProjCorrDivIn(SurfNum)) *
5878 9 : (HInConvDiv * (s_surf->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin - tin));
5879 : // DividerHeatTransfer = s_surf->SurfWinDividerArea(SurfNum) * DivCon *
5880 : // (s_surf->SurfWinDividerTempSurfOut(SurfNum) - s_surf->SurfWinDividerTempIn(SurfNum));
5881 :
5882 9 : if (DividerHeatGain > 0.0) {
5883 0 : s_surf->SurfWinDividerHeatGain(SurfNum) = DividerHeatGain;
5884 : } else {
5885 9 : s_surf->SurfWinDividerHeatLoss(SurfNum) = std::abs(DividerHeatGain);
5886 : }
5887 9 : s_surf->SurfWinHeatGain(SurfNum) += DividerHeatGain;
5888 9 : s_surf->SurfWinGainFrameDividerToZoneRep(SurfNum) += DividerHeatGain;
5889 : // If interior shade is present it is assumed that both the convective and IR radiative gain
5890 : // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative
5891 : // interaction between divider and shade is ignored due to the difficulty of calculating this interaction
5892 : // at the same time that the interaction between glass and shade is calculated.
5893 9 : if (ANY_INTERIOR_SHADE_BLIND(s_surf->SurfWinShadingFlag(SurfNum))) {
5894 0 : s_surf->SurfWinDividerHeatGain(SurfNum) = DividerHeatGain;
5895 : }
5896 : // DivTempOut = s_surf->SurfWinDividerTempSurfOut(SurfNum) + Constant::Kelvin;
5897 : } // End of check if window has dividers
5898 9 : } // CalcWinFrameAndDividerTemps()
5899 :
5900 : //************************************************************************************
5901 :
5902 66 : void CalcNominalWindowCond(EnergyPlusData &state,
5903 : int const ConstrNum, // Construction number
5904 : int const WinterSummerFlag, // 1=winter, 2=summer
5905 : Real64 &NominalConductance, // Nominal center-of-glass conductance, including air films
5906 : Real64 &SHGC, // Nominal center-of-glass solar heat gain coefficient for
5907 : Real64 &TSolNorm, // Overall beam solar transmittance at normal incidence
5908 : Real64 &TVisNorm, // Overall beam visible transmittance at normal incidence
5909 : int &errFlag // Error flag
5910 : )
5911 : {
5912 :
5913 : // SUBROUTINE INFORMATION:
5914 : // AUTHOR F. Winkelmann
5915 : // DATE WRITTEN September 2000
5916 : // MODIFIED Oct 2000, FW: add solar heat gain coefficient
5917 : // June 2001, FW: account for blinds; change summer outside air
5918 : // temp from 35.0C to 31.7C to correspond to ASHRAE value
5919 : // Feb 2003, FW: add comments that this routine is not called for
5920 : // between-glass shade/blind constructions.
5921 : // May 2006, RR: account for screens
5922 : // Oct 2007, LKL: change temps to match Window 5 values
5923 : // Feb 2009, BG: Changes for CR7682 (SHGC)
5924 : // RE-ENGINEERED na
5925 :
5926 : // PURPOSE OF THIS SUBROUTINE:
5927 : // Calculates nominal center-of-glass U-value and solar heat gain coefficient
5928 : // (SHGC) of a window construction for ASHRAE winter and summer conditions.
5929 : // This function is just for reporting
5930 : // Winter:
5931 : // Inside air temperature = 21.C (69.80F)
5932 : // Outside air temperature = -18C (-.4F)
5933 : // Windspeed = 5.5 m/s (12.3 mph)
5934 : // No solar radiation
5935 : // Replaced Winter:
5936 : // Inside air temperature = 21.1C (70F)
5937 : // Outside air temperature = -17.8C (0F)
5938 : // Windspeed = 6.71 m/s (15 mph)
5939 : // No solar radiation
5940 : // Summer:
5941 : // Inside air temperature = 24C (75.2F)
5942 : // Outside air temperature = 32C (89.6F)
5943 : // Windspeed = 2.8 m/s (6.2 mph)
5944 : // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
5945 : // Replaced Summer:
5946 : // Inside air temperature = 24C (75.2F) ! BG changed again Feb. 2009 by 0.1 (per Window5 team)
5947 : // Outside air temperature = 31.7C (89F)
5948 : // Windspeed = 3.35 m/s (7.5 mph)
5949 : // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
5950 : // The window's inside surround is assumed to be a black body at the inside air temp.
5951 : // The window's outside surround is assumed t be a black body at the outside air temp.
5952 : // Note that in this routine we use a value of 26 W/m2 for the outside convective
5953 : // air film conductance for 5.5 m/s (12.3 mph) wind speed.
5954 : // This is the value used in Window 5 and is also the value for which the center-of-glass
5955 : // conductances in the EnergyPlus window construction reference data set were calculated.
5956 : // However, in the time step loop we will have different values of outside film
5957 : // conductance depending on that time step's wind speed, wind direction, surface-to-air temp difference,
5958 : // etc.(see subroutine InitExteriorConvectionCoeff).
5959 : // This routine will return an error and exit for window constructions with between-glass shade or blind
5960 : // until a method is worked out to determine the nominal conductance and SHGC in this case.
5961 : // If an interior or exterior shade or blind is present in the construction,
5962 : // the conductance calculation does not include the effect of the shade or blind.
5963 : // This is because in this case the conductance depends on the natural convective
5964 : // air flow in the shade/glass, screen/glass or blind/glass channel, which in turn is highly dependent
5965 : // on window height and other parameters that are not part of the construction definition.
5966 : // Therefore, the reported conductance value will be too high for windows with a tightly fitting
5967 : // shade, screen or blind with a relatively high thermal resistance.
5968 : // For SHGC calculation, all solar absorbed by interior blind or shade is assumed
5969 : // to go into zone air. (This is not true in general; the fraction of this absorbed solar that
5970 : // is conducted back out is accounted for in the time-step glazing calculation.)
5971 : // For CR 7682, the SHGC calculations were changed to model the absorbed solar arriving at the middle of the layer
5972 : // rather than at the outer face of the layer. The resistances changed by one half the glazing layer, or 0.5/scon(n).
5973 : // (CR 7682 also changed WindowTempsForNominalCond to include absorbed solar, a bigger change)
5974 :
5975 : // Locals
5976 : // SUBROUTINE ARGUMENT DEFINITIONS:
5977 : // normal incidence beam solar radiation
5978 :
5979 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5980 : int TotLay; // Total number of layers in a construction
5981 : // (sum of solid layers and gap layers)
5982 : int TotGlassLay; // Total number of glass layers in a construction
5983 : int LayPtr; // Material number for a layer
5984 :
5985 : Real64 BeamSolarInc; // Incident beam radiation at zero angle of incidence (W/m2)
5986 : // Real64 hOutRad; // Radiative conductance of outside and inside airfilm [W/m2-K]
5987 : // Real64 hInRad;
5988 : // Real64 rOut; // Combined radiative and conductive outside and inside film
5989 : // Real64 rIn;
5990 : // resistance [m2-K/W]
5991 : Array1D<Real64> hgap(
5992 66 : maxGlassLayers); // Conductive gap conductance [W/m2-K]
5993 : // Array1D<Real64> hGapTot(5); // Combined radiative and conductive gap conductance [W/m2-K]
5994 : // Real64 Rbare; // Nominal center-of-glass resistance without air films [m2-K/W]
5995 : WinShadingType ShadeFlag; // Shading flag
5996 : Real64 ShadeRes; // Thermal resistance of shade
5997 : int MatOutside; // Material number of outside layer of construction
5998 : int MatInside; // Material number of inside layer of construction
5999 : int MatShade; // Material number of shade layer
6000 66 : Array1D<Real64> AbsBeamNorm(maxGlassLayers); // Beam absorptance at normal incidence for each glass layer
6001 : Real64 AbsBeamShadeNorm; // Shade solar absorptance at normal incidence
6002 : int ConstrNumBare; // Construction without shading device
6003 : int BlNum; // Blind number
6004 : Real64 SlatAng; // Slat angle (rad)
6005 : int LayPtrSh; // Layer pointer of blind
6006 : Real64 TBmBm; // Bare glass normal incidence beam-beam transmittance
6007 : Real64 TBmBmVis;
6008 : Real64 TBlBmBm; // Normal incidence blind beam-beam transmittance
6009 : Real64 TScBmBm; // Screen incident beam-beam transmittance
6010 : Real64 TScBmBmVis;
6011 : Real64 TBmBmBl; // TBmBm * TBlBmBm, TBmBmVis * TBlBmBm
6012 : Real64 TBmBmBlVis;
6013 : Real64 RGlDiffBack; // Bare glass back sol/vis reflectance
6014 : Real64 RGlDiffBackVis;
6015 : Real64 RGlDiffFront; // Bare glass front sol/vis reflectance
6016 : Real64 RGlDiffFrontVis;
6017 : Real64 RhoBlFront; // Blind normal front beam-diffuse sol/vis reflectance
6018 : Real64 RhoBlFrontVis;
6019 : Real64 RhoBlBack; // Blind normal back beam-diffuse sol/vis reflectance
6020 : Real64 RhoBlBackVis;
6021 : Real64 RScBack; // Screen back beam-diffuse sol/vis reflectance (same as front)
6022 : Real64 RScBackVis;
6023 : Real64 AbsBlFront; // Blind normal front beam solar absorptance
6024 : Real64 AbsBlBack; // Blind normal back beam solar absorptance
6025 : Real64 RhoBlDiffFront; // Blind front diffuse-diffuse sol/vis reflectance
6026 : Real64 RhoBlDiffFrontVis;
6027 : Real64 AbsBlDiffFront; // Blind front diffuse solar absorptance
6028 : Real64 AbsBlDiffBack; // Blind back diffuse solar absorptance
6029 : Real64 RGlFront; // Bare glass normal front beam sol/vis reflectance
6030 : Real64 RGlFrontVis;
6031 : Real64 RhoBlDiffBack; // Blind back diffuse-diffuse sol/vis reflectance
6032 : Real64 RhoBlDiffBackVis;
6033 : Real64 RScDifBack; // Screen back diffuse-diffuse sol/vis reflectance (doesn't change with sun angle)
6034 : Real64 RScDifBackVis;
6035 : Real64 TBlBmDif; // Blind front normal beam-diffuse sol/vis transmittance
6036 : Real64 TBlBmDifVis;
6037 : Real64 TBlDifDif; // Blind front diffuse-diffuse sol/vis transmittance
6038 : Real64 TBlDifDifVis;
6039 : Real64 TScBmDif; // Screen front beam-diffuse sol/vis transmittance
6040 : Real64 TScBmDifVis;
6041 : Real64 TDif; // Bare glass diffuse sol/vis transmittance
6042 : Real64 TDifVis;
6043 : Real64 AGlDiffBack; // Back diffuse solar absorptance of a glass layer
6044 :
6045 66 : auto &s_mat = state.dataMaterial;
6046 66 : auto &s_surf = state.dataSurface;
6047 66 : auto &wm = state.dataWindowManager;
6048 : // Autodesk:Uninit Initialize variables used uninitialized
6049 : // Rbare = 0.0; // Autodesk:Uninit Force default initialization
6050 :
6051 66 : NominalConductance = 0.0;
6052 66 : errFlag = 0;
6053 66 : TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
6054 66 : TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
6055 66 : wm->ngllayer = TotGlassLay; // Autodesk:Uninit This routine needs to check/enforce 1<=ngllayer<=4
6056 : // EPTeam - believe that is done on input.
6057 66 : wm->nglface = 2 * wm->ngllayer;
6058 66 : wm->tilt = 90.0; // Assume vertical window
6059 :
6060 66 : if (WinterSummerFlag == 1) { // Winter
6061 : // LKL Oct 2007: According to Window5, Winter environmental conditions are:
6062 41 : wm->tin = 294.15; // Inside air temperature (69.8F, 21.C)
6063 41 : wm->tout = 255.15; // Outside air temperature (-.4F, -18C)
6064 41 : wm->hcout = 26.0; // Outside convective film conductance for 5.5 m/s (12.3 mph) wind speed
6065 : // (the value used in Window 5)
6066 : // tin = 294.26 ! Inside air temperature (70F, 21.1C)
6067 : // tout = 255.35 ! Outside air temperature (0F, -17.8C)
6068 : // hcout = 25.47 ! Outside convective film conductance for 6.71 m/s (15 mph) wind speed
6069 : // ! (the value used in Window 4)
6070 41 : BeamSolarInc = 0.0;
6071 : } else { // Summer
6072 : // LKL Oct 2007: According to Window5, Summer environmental conditions are:
6073 : // tin = 297.05d0 ! Inside air temperature (75.2F, 24C)
6074 : // BG Feb. 2009: According to Window5 Expert Christian Kohler, it is exactly 24C or 297.15
6075 25 : wm->tin = 297.15;
6076 25 : wm->tout = 305.15; // Outside air temperature (89.6F, 32C)
6077 25 : wm->hcout = 15.0; // Outside convective film conductance for 2.8 m/s (6.2 mph) wind speed
6078 : // (the value used in Window 5)
6079 : // tin = 297.05 ! Inside air temperature (75F, 23.9C)
6080 : // !tout = 308.15 ! Outside air temperature (95F, 35.0C)
6081 : // ! Changed 6/20/01 by FCW to make consistent with Window 4 and 5.
6082 : // tout = 304.82 ! Outside air temperature (89F, 31.7C)
6083 : // hcout = 18.86 ! Outside convective film conductance for 3.35 m/s (7.5 mph) wind speed
6084 : // ! (average of Window 4 0 m/s and 6.71 m/s values)
6085 25 : BeamSolarInc = 783.0;
6086 : }
6087 :
6088 : // IR incident on inside of glazing (inside surround assumed to be
6089 : // a black body at inside air temperature)
6090 66 : wm->Rmir = Constant::StefanBoltzmann * pow_4(wm->tin);
6091 :
6092 : // IR incident on outside of glazing
6093 : // (outside surround is assumed to be a black body at outside air temperature)
6094 66 : wm->Outir = Constant::StefanBoltzmann * pow_4(wm->tout);
6095 :
6096 : // Determine whether construction has an exterior or interior shade or blind
6097 66 : ShadeFlag = WinShadingType::NoShade;
6098 66 : ShadeRes = 0.0;
6099 66 : MatOutside = state.dataConstruction->Construct(ConstrNum).LayerPoint(1);
6100 66 : MatInside = state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLay);
6101 66 : if (s_mat->materials(MatOutside)->group == Material::Group::Shade) { // Exterior shade present
6102 0 : MatShade = MatOutside;
6103 0 : ShadeFlag = WinShadingType::ExtShade;
6104 : // Set glazing outside convection coefficient to Window 4 still-air value
6105 0 : wm->hcout = 12.25;
6106 66 : } else if (s_mat->materials(MatOutside)->group == Material::Group::Screen) { // Exterior screen present
6107 0 : MatShade = MatOutside;
6108 0 : ShadeFlag = WinShadingType::ExtScreen;
6109 0 : wm->hcout = 12.25;
6110 66 : } else if (s_mat->materials(MatOutside)->group == Material::Group::Blind) { // Exterior blind present
6111 0 : MatShade = MatOutside;
6112 0 : ShadeFlag = WinShadingType::ExtBlind;
6113 0 : BlNum = MatOutside;
6114 0 : wm->hcout = 12.25;
6115 66 : } else if (s_mat->materials(MatInside)->group == Material::Group::Shade) { // Interior shade present
6116 0 : MatShade = MatInside;
6117 0 : ShadeFlag = WinShadingType::IntShade;
6118 66 : } else if (s_mat->materials(MatInside)->group == Material::Group::Blind) { // Interior blind present
6119 2 : MatShade = MatInside;
6120 2 : BlNum = MatShade;
6121 2 : ShadeFlag = WinShadingType::IntBlind;
6122 64 : } else if (TotGlassLay == 2) {
6123 17 : if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(3))->group == Material::Group::Shade) {
6124 0 : ShadeFlag = WinShadingType::BGShade;
6125 : }
6126 17 : if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(3))->group == Material::Group::Blind) {
6127 0 : ShadeFlag = WinShadingType::BGBlind;
6128 : }
6129 47 : } else if (TotGlassLay == 3) {
6130 0 : if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(5))->group == Material::Group::Shade) {
6131 0 : ShadeFlag = WinShadingType::BGShade;
6132 : }
6133 0 : if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(5))->group == Material::Group::Blind) {
6134 0 : ShadeFlag = WinShadingType::BGBlind;
6135 : }
6136 : }
6137 :
6138 66 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
6139 0 : errFlag = 2;
6140 0 : return;
6141 : }
6142 :
6143 66 : TSolNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef);
6144 66 : TVisNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransVisBeamCoef);
6145 66 : AbsBeamShadeNorm = 0.0;
6146 66 : if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) { // Exterior or interior shade on
6147 0 : AbsBeamShadeNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamShadeCoef);
6148 : // Exterior blind or screen or interior blind on
6149 66 : } else if (ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) {
6150 : // Find unshaded construction that goes with this construction w/blind or screen
6151 2 : ConstrNumBare = 0;
6152 24 : for (int ConstrNum1 = 1; ConstrNum1 <= state.dataHeatBal->TotConstructs; ++ConstrNum1) {
6153 24 : if (ConstrNum1 != ConstrNum && state.dataConstruction->Construct(ConstrNum1).TypeIsWindow &&
6154 50 : state.dataConstruction->Construct(ConstrNum1).TotGlassLayers == state.dataConstruction->Construct(ConstrNum1).TotSolidLayers &&
6155 2 : state.dataConstruction->Construct(ConstrNum1).TotGlassLayers == state.dataConstruction->Construct(ConstrNum).TotGlassLayers) {
6156 : // We have an unshaded window construction with the same number of glass layers as ConstrNum;
6157 : // see if the glass and gas layers match
6158 2 : ConstrNumBare = ConstrNum1;
6159 4 : for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum1).TotLayers; ++Lay) {
6160 2 : LayPtr = state.dataConstruction->Construct(ConstrNum1).LayerPoint(Lay);
6161 2 : if (ShadeFlag == WinShadingType::IntBlind) { // The shaded construction has an interior blind
6162 2 : LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
6163 : } else { // The shaded construction has an exterior blind or screen
6164 0 : LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay + 1);
6165 : }
6166 2 : if (LayPtrSh != LayPtr) {
6167 0 : ConstrNumBare = 0;
6168 : }
6169 : }
6170 2 : if (ConstrNumBare != 0) {
6171 2 : break;
6172 : }
6173 : }
6174 : }
6175 2 : if (ConstrNumBare == 0) {
6176 : // No matching bare construction found for this construction with blind or screen
6177 0 : errFlag = 1;
6178 0 : return;
6179 : }
6180 :
6181 2 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6182 2 : TBmBm = POLYF(1.0, constructBare.TransSolBeamCoef);
6183 2 : TBmBmVis = POLYF(1.0, constructBare.TransVisBeamCoef);
6184 :
6185 2 : if (ShadeFlag == WinShadingType::ExtScreen) {
6186 : // Don't need to call subroutine, use normal incident properties (SUBROUTINE CalcNominalWindowCond)
6187 : // Last call to CalcScreenTransmittance(ISurf) was done at direct normal angle (0,0) in CalcWindowScreenProperties
6188 0 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(s_mat->materials(MatShade));
6189 0 : assert(matScreen != nullptr);
6190 0 : auto const &btar = matScreen->btars[0][0];
6191 0 : TScBmBm = btar.BmTrans;
6192 0 : TScBmBmVis = btar.BmTransVis;
6193 0 : TScBmDif = btar.DfTrans;
6194 0 : TScBmDifVis = btar.DfTransVis;
6195 0 : TDif = constructBare.TransDiff;
6196 0 : TDifVis = constructBare.TransDiffVis;
6197 0 : RScBack = matScreen->ShadeRef;
6198 0 : RScBackVis = matScreen->ShadeRefVis;
6199 0 : RScDifBack = matScreen->DfRef;
6200 0 : RScDifBackVis = matScreen->DfRefVis;
6201 0 : RGlFront = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6202 0 : RGlFrontVis = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6203 0 : RGlDiffFront = constructBare.ReflectSolDiffFront;
6204 0 : RGlDiffFrontVis = constructBare.ReflectVisDiffFront;
6205 0 : TSolNorm = TScBmBm * (TBmBm + TDif * RGlFront * RScBack / (1 - RGlDiffFront * RScDifBack)) +
6206 0 : TScBmDif * TDif / (1 - RGlDiffFront * RScDifBack);
6207 0 : TVisNorm = TScBmBmVis * (TBmBmVis + TDifVis * RGlFrontVis * RScBackVis / (1 - RGlDiffFrontVis * RScDifBackVis)) +
6208 0 : TScBmDifVis * TDifVis / (1 - RGlDiffFrontVis * RScDifBackVis);
6209 :
6210 : } else { // Blind
6211 2 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
6212 2 : assert(matBlind != nullptr);
6213 :
6214 2 : SlatAng = matBlind->SlatAngle * Constant::DegToRad;
6215 2 : Real64 ProfAng = 0.0;
6216 :
6217 : int slatIdxLo, slatIdxHi;
6218 : Real64 slatInterpFac;
6219 2 : Material::GetSlatIndicesInterpFac(SlatAng, slatIdxLo, slatIdxHi, slatInterpFac);
6220 2 : Material::BlindTraAbsRef<Material::MaxProfAngs + 1> blindTAR;
6221 : // This interpolates all blind properties. No need to interpolate them one-by-one
6222 2 : blindTAR.interpSlatAng(matBlind->TARs[slatIdxLo], matBlind->TARs[slatIdxHi], slatInterpFac);
6223 :
6224 : int profIdxLo, profIdxHi;
6225 2 : Material::GetProfIndices(ProfAng, profIdxLo, profIdxHi);
6226 :
6227 2 : assert(profIdxLo == (Material::MaxProfAngs / 2) + 1); // Should be true for ProfAng == 0.0
6228 :
6229 2 : TBlBmBm = matBlind->BeamBeamTrans(0.0, SlatAng);
6230 2 : TBmBmBl = TBmBm * TBlBmBm;
6231 2 : TBmBmBlVis = TBmBmVis * TBlBmBm;
6232 2 : TBlBmDif = blindTAR.Sol.Ft.Bm[profIdxLo].DfTra;
6233 2 : TBlBmDifVis = blindTAR.Vis.Ft.Bm[profIdxLo].DfTra;
6234 2 : TDif = constructBare.TransDiff;
6235 2 : TDifVis = constructBare.TransDiffVis;
6236 2 : if (ShadeFlag == WinShadingType::IntBlind) {
6237 2 : RGlDiffBack = constructBare.ReflectSolDiffBack;
6238 2 : RGlDiffBackVis = constructBare.ReflectVisDiffBack;
6239 2 : RhoBlFront = blindTAR.Sol.Ft.Bm[profIdxLo].DfRef;
6240 2 : RhoBlFrontVis = blindTAR.Vis.Ft.Bm[profIdxLo].DfRef;
6241 2 : AbsBlFront = blindTAR.Sol.Ft.Bm[profIdxLo].Abs;
6242 2 : RhoBlDiffFront = blindTAR.Sol.Ft.Df.Ref;
6243 2 : RhoBlDiffFrontVis = blindTAR.Vis.Ft.Df.Ref;
6244 2 : AbsBlDiffFront = blindTAR.Sol.Ft.Df.Abs;
6245 2 : AbsBeamShadeNorm = TBmBm * (AbsBlFront + RhoBlFront * RGlDiffBack * AbsBlDiffFront / (1.0 - RhoBlDiffFront * RGlDiffBack));
6246 2 : TBlDifDif = blindTAR.Sol.Ft.Df.Tra;
6247 2 : TBlDifDifVis = blindTAR.Vis.Ft.Df.Tra;
6248 2 : TSolNorm = TBmBm * (TBlBmBm + TBlBmDif + TBlDifDif * RhoBlFront * RGlDiffBack / (1.0 - RhoBlDiffFront * RGlDiffBack));
6249 : // use of TBlBmBm here is correct, visible and IR transmittance are the same (reference deleted CR6925 on 3/20/2006)
6250 2 : TVisNorm = TBmBmVis *
6251 2 : (TBlBmBm + TBlBmDifVis + TBlDifDifVis * RhoBlFrontVis * RGlDiffBackVis / (1.0 - RhoBlDiffFrontVis * RGlDiffBackVis));
6252 :
6253 0 : } else if (ShadeFlag == WinShadingType::ExtBlind) {
6254 0 : RGlFront = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6255 0 : RGlFrontVis = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6256 0 : AbsBlFront = blindTAR.Sol.Ft.Bm[profIdxLo].Abs;
6257 0 : AbsBlBack = blindTAR.Sol.Bk.Bm[profIdxLo].Abs;
6258 0 : AbsBlDiffBack = blindTAR.Sol.Bk.Df.Abs;
6259 0 : RGlDiffFront = constructBare.ReflectSolDiffFront;
6260 0 : RGlDiffFrontVis = constructBare.ReflectVisDiffFront;
6261 :
6262 0 : RhoBlDiffBack = blindTAR.Sol.Bk.Df.Ref;
6263 0 : RhoBlDiffBackVis = blindTAR.Vis.Bk.Df.Ref;
6264 0 : RhoBlBack = blindTAR.Sol.Bk.Bm[profIdxLo].DfRef;
6265 0 : RhoBlBackVis = blindTAR.Vis.Bk.Bm[profIdxLo].DfRef;
6266 :
6267 0 : AbsBeamShadeNorm =
6268 0 : AbsBlFront + AbsBlBack * RGlFront * TBlBmBm +
6269 0 : (AbsBlDiffBack * RGlDiffFront / (1.0 - RhoBlDiffBack * RGlDiffFront)) * (RGlFront * TBlBmBm * RhoBlBack + TBlBmDif);
6270 0 : RGlDiffFront = constructBare.ReflectSolDiffFront;
6271 0 : TSolNorm = TBlBmBm * (TBmBm + TDif * RGlFront * RhoBlBack / (1 - RGlDiffFront * RhoBlDiffBack)) +
6272 0 : TBlBmDif * TDif / (1.0 - RGlDiffFront * RhoBlDiffBack);
6273 0 : TVisNorm = TBlBmBm * (TBmBmVis + TDifVis * RGlFrontVis * RhoBlBackVis / (1 - RGlDiffFrontVis * RhoBlDiffBackVis)) +
6274 0 : TBlBmDifVis * TDifVis / (1.0 - RGlDiffFrontVis * RhoBlDiffBackVis);
6275 : } // (ExtBlind)
6276 : } // (Screen or Blind)
6277 : } // (Shade, Blind, or Screen)
6278 :
6279 : // Fill the layer properties needed for the thermal calculation.
6280 :
6281 : // The layer and face numbering are as follows (for the triple glazing case):
6282 : // Glass layers are 1,2 and 3, where 1 is the outside (outside environment facing)
6283 : // layer and 3 is the inside (room-facing) layer;
6284 : // Faces (also called surfaces) are 1,2,3,4,5 and 6, where face 1 is the
6285 : // outside (front) face of glass layer 1, face 2 is the inside (back)
6286 : // face of glass layer 1, face 3 is the outer face of glass layer 2, face 4 is the
6287 : // inner face of glass layer 2, etc.
6288 : // Gap layers are 1 and 2, where gap layer 1 is between glass layers 1 and 2
6289 : // and gap layer 2 is between glass layers 2 and 3.
6290 :
6291 66 : int IGlass = 0;
6292 66 : int IGap = 0;
6293 :
6294 172 : for (int Lay = 1; Lay <= TotLay; ++Lay) {
6295 106 : LayPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
6296 106 : auto const *mat = s_mat->materials(LayPtr);
6297 :
6298 106 : if ((mat->group == Material::Group::Glass) || (mat->group == Material::Group::GlassSimple)) {
6299 83 : auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
6300 83 : assert(matGlass != nullptr);
6301 :
6302 83 : ++IGlass;
6303 83 : wm->thick[IGlass - 1] = matGlass->Thickness;
6304 83 : wm->scon[IGlass - 1] = matGlass->Conductivity / matGlass->Thickness;
6305 83 : wm->emis[2 * IGlass - 2] = matGlass->AbsorpThermalFront;
6306 83 : wm->emis[2 * IGlass - 1] = matGlass->AbsorpThermalBack;
6307 83 : wm->tir[2 * IGlass - 2] = matGlass->TransThermal;
6308 83 : wm->tir[2 * IGlass - 1] = matGlass->TransThermal;
6309 83 : AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef(IGlass));
6310 83 : if (ShadeFlag == WinShadingType::IntBlind) { // Interior blind on
6311 2 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6312 2 : AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
6313 2 : AGlDiffBack = constructBare.AbsDiffBack(IGlass);
6314 2 : AbsBeamNorm(IGlass) += TBmBm * AGlDiffBack * RhoBlFront / (1.0 - RhoBlFront * RGlDiffBack);
6315 81 : } else if (ShadeFlag == WinShadingType::ExtBlind) { // Exterior blind on
6316 0 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6317 0 : AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
6318 0 : AbsBeamNorm(IGlass) = TBlBmBm * AbsBeamNorm(IGlass) + (TBlBmBm * RGlFront * RhoBlBack + TBlBmDif) *
6319 0 : constructBare.AbsDiff(IGlass) / (1.0 - RGlDiffFront * RhoBlDiffBack);
6320 81 : } else if (ShadeFlag == WinShadingType::ExtScreen) { // Exterior screen on
6321 0 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6322 0 : AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
6323 0 : AbsBeamNorm(IGlass) = TScBmBm * AbsBeamNorm(IGlass) + (TScBmBm * RGlFront * RScBack + TScBmDif) * constructBare.AbsDiff(IGlass) /
6324 0 : (1.0 - RGlDiffFront * RScDifBack);
6325 : }
6326 83 : wm->AbsRadGlassFace[2 * IGlass - 2] = 0.5 * BeamSolarInc * AbsBeamNorm(IGlass);
6327 83 : wm->AbsRadGlassFace[2 * IGlass - 1] = 0.5 * BeamSolarInc * AbsBeamNorm(IGlass);
6328 : }
6329 106 : if (mat->group == Material::Group::Gas || mat->group == Material::Group::GasMixture ||
6330 91 : mat->group == Material::Group::ComplexWindowGap) { // Gap layer
6331 19 : ++IGap;
6332 :
6333 19 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
6334 19 : assert(matGas != nullptr);
6335 19 : wm->gaps[IGap - 1].width = matGas->Thickness;
6336 19 : wm->gaps[IGap - 1].numGases = matGas->numGases;
6337 38 : for (int IMix = 0; IMix < wm->gaps[IGap - 1].numGases; ++IMix) {
6338 19 : wm->gaps[IGap - 1].gases[IMix] = matGas->gases[IMix];
6339 19 : wm->gaps[IGap - 1].gasFracts[IMix] = matGas->gasFracts[IMix];
6340 : }
6341 : }
6342 : } // for (Lay)
6343 :
6344 : // Factors used in glass temperature solution
6345 66 : if (wm->ngllayer >= 2) {
6346 17 : wm->A23P = -wm->emis[2] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
6347 17 : wm->A32P = wm->emis[1] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
6348 17 : wm->A23 = wm->emis[1] * Constant::StefanBoltzmann * wm->A23P;
6349 : }
6350 :
6351 66 : if (wm->ngllayer >= 3) {
6352 0 : wm->A45P = -wm->emis[4] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
6353 0 : wm->A54P = wm->emis[3] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
6354 0 : wm->A45 = wm->emis[3] * Constant::StefanBoltzmann * wm->A45P;
6355 : }
6356 :
6357 66 : if (wm->ngllayer == 4) {
6358 0 : wm->A67P = -wm->emis[6] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
6359 0 : wm->A76P = wm->emis[5] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
6360 0 : wm->A67 = wm->emis[5] * Constant::StefanBoltzmann * wm->A67P;
6361 : }
6362 :
6363 66 : wm->thetas = {0.0};
6364 :
6365 66 : WindowTempsForNominalCond(state, ConstrNum, hgap, 1.0);
6366 :
6367 66 : if (!ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
6368 64 : AbsBeamShadeNorm = 0.0;
6369 : }
6370 :
6371 : // Get center-of-glass conductance and solar heat gain coefficient
6372 : // including inside and outside air films
6373 66 : auto const *mat = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1));
6374 29 : Real64 inputU = (mat->group == Material::Group::Glass || mat->group == Material::Group::GlassSimple)
6375 95 : ? dynamic_cast<Material::MaterialGlass const *>(mat)->SimpleWindowUfactor
6376 66 : : 0.0;
6377 :
6378 : // Calculate the NominalConductance glazing only (before adjusted)
6379 66 : EvalNominalWindowCond(state, AbsBeamShadeNorm, AbsBeamNorm, hgap, NominalConductance, SHGC, TSolNorm);
6380 :
6381 66 : if (WinterSummerFlag == 1) {
6382 41 : state.dataHeatBal->NominalUBeforeAdjusted(ConstrNum) = NominalConductance;
6383 41 : if (inputU > 0) { // only compute adjustment ratio when there is valid user input U
6384 15 : Real64 wettedAreaAdjRatio = 1; // Adjustment ratio for the wetted area
6385 15 : Real64 hcoutRated = wm->hcout;
6386 : // Adjustment ratio applies to convective film coefficients when input U value is above the limit of the simple glazing nominal U
6387 : // Representing the nominal highly conductive frame effects. Solved iteratively.
6388 15 : Real64 adjLower = 1.0;
6389 15 : Real64 adjUpper = 2.0;
6390 15 : int MaxIter = 100;
6391 39 : while (std::abs(inputU - NominalConductance) > 0.01 && MaxIter > 0) {
6392 24 : wettedAreaAdjRatio = (adjLower + adjUpper) / 2;
6393 24 : WindowTempsForNominalCond(
6394 : state, ConstrNum, hgap, wettedAreaAdjRatio); // reeval hcout at each iteration, hcin is not linear to wetted area
6395 24 : wm->hcout = hcoutRated * wettedAreaAdjRatio; // reeval hcout
6396 24 : EvalNominalWindowCond(state, AbsBeamShadeNorm, AbsBeamNorm, hgap, NominalConductance, SHGC, TSolNorm);
6397 24 : if (NominalConductance < inputU) {
6398 8 : adjLower = wettedAreaAdjRatio;
6399 : } else {
6400 16 : adjUpper = wettedAreaAdjRatio;
6401 : }
6402 24 : MaxIter -= 1;
6403 : }
6404 15 : state.dataHeatBal->CoeffAdjRatio(ConstrNum) = wettedAreaAdjRatio;
6405 : }
6406 : }
6407 :
6408 : // EPTeam - again -- believe that is enforced in input //Autodesk But this routine is not self-protecting: Add as an assert
6409 :
6410 : // init the surface convective and radiative adjustment ratio
6411 220 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
6412 308 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
6413 154 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
6414 154 : int const firstSurfWin = thisSpace.WindowSurfaceFirst;
6415 154 : int const lastSurfWin = thisSpace.WindowSurfaceLast;
6416 367 : for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) {
6417 213 : if (s_surf->Surface(SurfNum).ExtBoundCond == ExternalEnvironment) {
6418 213 : int ConstrNum2 = s_surf->Surface(SurfNum).Construction;
6419 213 : state.dataHeatBalSurf->SurfWinCoeffAdjRatio(SurfNum) = state.dataHeatBal->CoeffAdjRatio(ConstrNum2);
6420 : }
6421 : }
6422 154 : }
6423 : }
6424 :
6425 : // Need to add variables writing here since this routine will override previously calculated values from WinCalc-Engine
6426 66 : if (wm->inExtWindowModel->isExternalLibraryModel()) {
6427 0 : TSolNorm = GetSolarTransDirectHemispherical(state, ConstrNum);
6428 0 : TVisNorm = GetVisibleTransDirectHemispherical(state, ConstrNum);
6429 : }
6430 66 : } // CalcNominalWindowCond()
6431 :
6432 90 : void EvalNominalWindowCond(EnergyPlusData &state,
6433 : Real64 const AbsBeamShadeNorm, // Shade solar absorptance at normal incidence
6434 : Array1D<Real64> const AbsBeamNorm, // Beam absorptance at normal incidence for each glass layer
6435 : Array1D<Real64> const hgap, // Conductive gap conductance [W/m2-K]
6436 : Real64 &NominalConductance, // Nominal center-of-glass conductance, including air films
6437 : Real64 &SHGC, // Nominal center-of-glass solar heat gain coefficient for
6438 : Real64 const TSolNorm // Overall beam solar transmittance at normal incidence
6439 : )
6440 : {
6441 90 : Array1D<Real64> hGapTot(5); // Combined radiative and conductive gap conductance [W/m2-K]
6442 :
6443 90 : auto const &wm = state.dataWindowManager;
6444 90 : Real64 hOutRad = wm->emis[0] * Constant::StefanBoltzmann * 0.5 * pow_3(wm->tout + wm->thetas[0]);
6445 90 : Real64 rOut = 1.0 / (hOutRad + wm->hcout);
6446 90 : Real64 hInRad = wm->emis[wm->nglface - 1] * Constant::StefanBoltzmann * 0.5 * pow_3(wm->tin + wm->thetas[wm->nglface - 1]);
6447 90 : Real64 rIn = 1.0 / (hInRad + wm->hcin);
6448 90 : Real64 Rbare = 0;
6449 :
6450 90 : switch (wm->ngllayer) {
6451 : // the switch cases here are just the integer number of layers, not exactly "magic" numbers 1, 2, 3. and 4.
6452 73 : case 1: {
6453 73 : Rbare = 1.0 / wm->scon[0];
6454 73 : wm->Rtot = rOut + Rbare + rIn;
6455 73 : SHGC = AbsBeamNorm(1) * (rOut + (0.5 / wm->scon[0])) / wm->Rtot; // BG changed for CR7682 (solar absorbed in middle of layer)
6456 73 : SHGC += AbsBeamShadeNorm;
6457 73 : SHGC += TSolNorm;
6458 73 : } break;
6459 :
6460 17 : case 2: {
6461 17 : hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
6462 17 : Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1];
6463 17 : wm->Rtot = rOut + Rbare + rIn;
6464 17 : SHGC = AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
6465 17 : AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot; // CR7682
6466 17 : SHGC += AbsBeamShadeNorm;
6467 17 : SHGC += TSolNorm;
6468 17 : } break;
6469 :
6470 0 : case 3: {
6471 0 : hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
6472 0 : hGapTot(2) = hgap(2) + std::abs(wm->A45) * 0.5 * pow_3(wm->thetas[3] + wm->thetas[4]);
6473 0 : Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 1.0 / wm->scon[2];
6474 0 : wm->Rtot = rOut + Rbare + rIn;
6475 0 : SHGC =
6476 0 : AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
6477 0 : AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot +
6478 0 : AbsBeamNorm(3) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 0.5 / wm->scon[2]) / wm->Rtot;
6479 0 : SHGC += AbsBeamShadeNorm;
6480 0 : SHGC += TSolNorm;
6481 0 : } break;
6482 :
6483 0 : case 4: {
6484 0 : hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
6485 0 : hGapTot(2) = hgap(2) + std::abs(wm->A45) * 0.5 * pow_3(wm->thetas[3] + wm->thetas[4]);
6486 0 : hGapTot(3) = hgap(3) + std::abs(wm->A67) * 0.5 * pow_3(wm->thetas[5] + wm->thetas[6]);
6487 0 : Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 1.0 / wm->scon[2] + 1.0 / hGapTot(3) +
6488 0 : 1.0 / wm->scon[3];
6489 0 : wm->Rtot = rOut + Rbare + rIn;
6490 0 : SHGC =
6491 0 : AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
6492 0 : AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot +
6493 0 : AbsBeamNorm(3) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 0.5 / wm->scon[2]) / wm->Rtot +
6494 0 : AbsBeamNorm(4) *
6495 0 : (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 1.0 / wm->scon[2] + 1.0 / hGapTot(3) +
6496 0 : 0.5 / wm->scon[3]) /
6497 0 : wm->Rtot; // CR7682
6498 0 : SHGC += AbsBeamShadeNorm;
6499 0 : SHGC += TSolNorm;
6500 0 : } break;
6501 0 : default:
6502 0 : break;
6503 : }
6504 90 : NominalConductance = 1.0 / (rOut + Rbare + rIn);
6505 90 : } // EvalNominalWindowCond()
6506 :
6507 : //****************************************************************************
6508 :
6509 90 : void WindowTempsForNominalCond(EnergyPlusData &state,
6510 : int const ConstrNum, // Construction number
6511 : Array1A<Real64> hgap, // Gap gas conductive conductance (W/m2-K)
6512 : Real64 const adjRatio // adjustment Ratio to hcin
6513 : )
6514 : {
6515 :
6516 : // SUBROUTINE INFORMATION:
6517 : // AUTHOR F. Winkelmann
6518 : // DATE WRITTEN September 2000
6519 : // MODIFIED Nov 2002, FW: increase MaxIterations from 15 to 100, add face
6520 : // temperature relaxation, and increase convergence tolerance by
6521 : // a factor of 10 if no convergence after MaxIterations,
6522 : // all for consistency with SolveForWindowTemperatures.
6523 : // Mar 2003, FW: increase convergence tolerance from 0.01 to 0.02;
6524 : // remove redundant relaxation on radiative conductances (both of
6525 : // these were also done in SolveForWindowTemperatures).
6526 : // Jan 2009, BG: changed interior convection coefficient correlation to match
6527 : // ISO 15099.
6528 : // Feb 2009, BG: extended coefficient to include absorbed radiation
6529 : // to cover summer conditions for SHGC determination.
6530 : // RE-ENGINEERED na
6531 :
6532 : // PURPOSE OF THIS SUBROUTINE:
6533 : // This is a shortened form of SolveForWindowTemperatures tailored
6534 : // for calculation of the nominal center-of-glass U-value for a window
6535 : // construction at ASHRAE winter conditions and for determining conditions at
6536 : // summer conditions for calculating SHGC.
6537 : // Evaluates the coefficients Aface and Bface in the system of linear
6538 : // algebraic equations
6539 : // Sum [Aface(i,j)*thetas(j)] = Bface(i), i = 1,nglface
6540 : // j=1,nglface
6541 : // where
6542 : // nglface = number of glass faces (= 2 * number of layers) and
6543 : // thetas(j) = temperature of face j
6544 :
6545 : // METHODOLOGY EMPLOYED:
6546 : // The Aface and Bface coefficients are determined by the equations for
6547 : // heat balance at the glass faces. The system of linear equations is solved
6548 : // by LU decomposition.
6549 :
6550 : // Argument array dimensioning
6551 90 : hgap.dim(5);
6552 :
6553 90 : int constexpr MaxIterations(100); // Maximum allowed number of iterations
6554 90 : Real64 constexpr errtemptol(0.02); // Tolerance on errtemp for convergence
6555 : static constexpr std::string_view RoutineName("WindowTempsForNominalCond");
6556 :
6557 90 : Array1D<Real64> hr(10); // Radiative conductance (W/m2-K)
6558 : Real64 hcinprev; // Value of hcin from previous iteration
6559 : int d; // +1 if number of row interchanges is even,
6560 : // -1 if odd (in LU decomposition)
6561 90 : Array1D_int indx(10); // Vector of row permutations in LU decomposition
6562 90 : Array2D<Real64> Aface(10, 10); // Coefficient in equation Aface*thetas = Bface
6563 90 : Array1D<Real64> Bface(10); // Coefficient in equation Aface*thetas = Bface
6564 : int iter; // Iteration number
6565 : Real64 errtemp; // Absolute value of sum of face temperature differences
6566 : // between iterations, divided by number of faces
6567 : Real64 TmeanFilm; // mean film temperature
6568 : Real64 TmeanFilmKelvin; // mean film temperature for property evaluation
6569 : Real64 rho; // density of (apparently dry) air [kg/m3]
6570 : Real64 g; // acceleration due to gravity [m/s2]
6571 : Real64 Height; // window cavity height [m]
6572 : Real64 Cp; // specific heat of air [J/kg-K]
6573 : Real64 lambda; // thermal conductivity of air [W/m-K]
6574 : Real64 mu; // dynamic viscosity of air [kg/m-s]
6575 : Real64 RaH; // Rayleigh number for cavity height [ Non dim]
6576 : Real64 TiltDeg; // glazing tilt in degrees
6577 : Real64 sineTilt; // sine of glazing tilt
6578 : Real64 Nuint; // Nusselt number for interior surface convection
6579 :
6580 90 : auto &wm = state.dataWindowManager;
6581 :
6582 90 : iter = 0;
6583 :
6584 : // Initialize face temperatures
6585 90 : StartingWinTempsForNominalCond(state);
6586 :
6587 : // Calculate radiative conductance
6588 90 : errtemp = errtemptol * 2.0;
6589 :
6590 90 : TiltDeg = 90.0;
6591 :
6592 90 : sineTilt = std::sin(TiltDeg * Constant::DegToRad); // degrees as arg
6593 :
6594 686 : while (iter < MaxIterations && errtemp > errtemptol) {
6595 1964 : for (int i = 1; i <= wm->nglface; ++i) {
6596 1368 : hr(i) = wm->emis[i - 1] * Constant::StefanBoltzmann * pow_3(wm->thetas[i - 1]);
6597 : //! fw 3/4/03 if ( iter >= 1 ) hr(i) = 0.5*(hrprev(i)+hr(i))
6598 : }
6599 :
6600 596 : Aface = 0.0;
6601 596 : Bface = 0.0;
6602 :
6603 : // Inside convective film conductance for vertical window
6604 596 : if (iter >= 1) {
6605 506 : hcinprev = wm->hcin;
6606 : }
6607 : // CR7670 BG this next correlation was used for hcin but is not "standard" for windows
6608 : // hcin = 1.31d0*((ABS(thetas(nglface)-tin))**0.3333d0)
6609 : // Begin calculating for ISO 15099 method.
6610 : // mean film temperature
6611 596 : TmeanFilmKelvin = wm->tin + 0.25 * (wm->thetas[wm->nglface - 1] - wm->tin); // eq. 133 in ISO 15099
6612 596 : TmeanFilm = TmeanFilmKelvin - 273.15;
6613 : // the following properties are constants or linear relations for "standard" type reporting
6614 596 : rho = Psychrometrics::PsyRhoAirFnPbTdbW(state, 101325.0, TmeanFilm, 0.0, RoutineName); // dry air assumption
6615 596 : g = 9.81;
6616 596 : Height = 1.0; // standard window rating practice is to use 1 meter (rather than actual)
6617 :
6618 596 : lambda = 2.873E-3 + 7.76E-5 * TmeanFilmKelvin; // Table B.1 in ISO 15099
6619 596 : mu = 3.723E-6 + 4.94E-8 * TmeanFilmKelvin; // Table B.2 in ISO 15099
6620 596 : Cp = 1002.737 + 1.2324E-2 * TmeanFilmKelvin; // Table B.3 in ISO 15099
6621 :
6622 : // eq 132 in ISO 15099
6623 596 : RaH = (pow_2(rho) * pow_3(Height) * g * Cp * (std::abs(wm->thetas[wm->nglface - 1] - wm->tin))) / (TmeanFilmKelvin * mu * lambda);
6624 :
6625 596 : Nuint = 0.56 * root_4(RaH * sineTilt); // eq. 135 in ISO 15099 (only need this one because tilt is 90 deg
6626 :
6627 596 : wm->hcin = Nuint * lambda / Height;
6628 :
6629 : // End calculations for ISO 15099 method.
6630 :
6631 596 : if (iter >= 1) {
6632 506 : wm->hcin = 0.5 * (hcinprev + wm->hcin);
6633 : }
6634 :
6635 596 : wm->hcin *= adjRatio;
6636 :
6637 596 : ++iter;
6638 :
6639 596 : GetHeatBalanceEqCoefMatrixSimple(state, wm->ngllayer, hr, hgap, Aface, Bface);
6640 :
6641 596 : LUdecomposition(state, Aface, wm->nglface, indx, d); // Note that these routines change Aface;
6642 596 : LUsolution(state, Aface, wm->nglface, indx, Bface); // face temperatures are returned in Bface
6643 :
6644 596 : errtemp = 0.0;
6645 1964 : for (int i = 1; i <= wm->nglface; ++i) {
6646 1368 : errtemp += std::abs(wm->thetas[i - 1] - Bface(i)) / wm->nglface;
6647 : }
6648 :
6649 1964 : for (int i = 1; i <= wm->nglface; ++i) {
6650 1368 : wm->thetas[i - 1] = 0.5 * (wm->thetas[i - 1] + Bface(i));
6651 : }
6652 : }
6653 :
6654 : // No convergence after MaxIterations; and/or error tolerance
6655 90 : if (errtemp >= 10 * errtemptol) {
6656 : // Fatal error: didn't converge
6657 0 : ShowFatalError(
6658 : state,
6659 0 : format("Convergence error in WindowTempsForNominalCond for construction {}", state.dataConstruction->Construct(ConstrNum).Name));
6660 : }
6661 90 : } // WindowTempsForNominalCond()
6662 :
6663 : //****************************************************************************
6664 :
6665 90 : void StartingWinTempsForNominalCond(EnergyPlusData &state)
6666 : {
6667 :
6668 : // SUBROUTINE INFORMATION:
6669 : // AUTHOR F. Winkelmann
6670 : // DATE WRITTEN September 2000
6671 :
6672 : // PURPOSE OF THIS SUBROUTINE:
6673 : // Initializes face temperature distribution prior to iteration.
6674 : // This is a shortened form of StartingWindowTemps for use in calculating
6675 : // the nominal center-of-glass U-value.
6676 :
6677 90 : Real64 constexpr hrad = 5.3; // Typical radiative conductance (W/m2-K)
6678 90 : Real64 constexpr hcinStartValue = 3.2; // Starting value for inside air film convective
6679 : // conductance (estimated for typical double glazing
6680 : // using 1.31(dT**0.333), where dT =
6681 : // room air temp - inside surface temp = 14.2K)
6682 90 : Real64 constexpr resgap = 0.21; // Typical gap resistance (m2-K/W)
6683 :
6684 90 : Array1D<Real64> rguess(11); // Combined radiative/convective resistance (m2-K/W) of
6685 : // inside or outside air film, or gap
6686 : Real64 restot; // Total window resistance including outside
6687 : // and inside air films (m2-K/W)
6688 : Real64 temdiff; // Inside/outside air temperature difference (K)
6689 : Real64 ressum; // Resistance sum (m2-K/W)
6690 :
6691 90 : auto const &wm = state.dataWindowManager;
6692 :
6693 90 : rguess(1) = 1.0 / (wm->hcout + hrad);
6694 90 : rguess(wm->nglface + 1) = 1.0 / (hcinStartValue + hrad);
6695 :
6696 197 : for (int i = 2; i <= wm->nglface; i += 2) {
6697 107 : rguess(i) = 1.0 / wm->scon[i / 2 - 1];
6698 107 : if (i < wm->nglface) {
6699 17 : rguess(i + 1) = resgap;
6700 : }
6701 : }
6702 90 : restot = 0.0;
6703 :
6704 394 : for (int i = 1; i <= wm->nglface + 1; ++i) {
6705 304 : restot += rguess(i);
6706 : }
6707 :
6708 90 : temdiff = wm->tin - wm->tout;
6709 90 : if (std::abs(temdiff) < 0.5) {
6710 0 : temdiff = 2.0;
6711 : }
6712 90 : ressum = 0.0;
6713 :
6714 304 : for (int i = 1; i <= wm->nglface; ++i) {
6715 214 : ressum += rguess(i);
6716 214 : wm->thetas[i - 1] = (ressum / restot) * temdiff + wm->tout;
6717 : }
6718 90 : } // StartingWinTempsForNominalCond()
6719 :
6720 : //****************************************************************************
6721 :
6722 110 : void ReportGlass(EnergyPlusData &state)
6723 : {
6724 :
6725 : // SUBROUTINE INFORMATION:
6726 : // AUTHOR Linda K. Lawrie
6727 : // DATE WRITTEN March 2000
6728 :
6729 : // PURPOSE OF THIS SUBROUTINE:
6730 : // This routine gives a detailed report to the user about
6731 : // the calculation parameters for windows and their associated
6732 : // materials.
6733 :
6734 110 : Real64 TempVar = 0.0; // just temporary usage for complex fenestration
6735 :
6736 : Real64 NominalConductanceWinter; // Nominal center-of-glass conductance of a window construction
6737 : // for ASHRAE winter conditions (W/m2-K):
6738 : // Inside air temperature = 21.1C (70F)
6739 : // Outside air temperature = -17.8C (0F)
6740 : // Windspeed = 6.71 m/s (15 mph)
6741 : // No solar radiation
6742 : Real64 NominalConductanceSummer; // Nominal center-of-glass conductance of a window construction
6743 : // for ASHRAE summer conditions (W/m2-K):
6744 : // Inside air temperature = 23.9C (75F)
6745 : // Outside air temperature = 35.0C (95F)
6746 : // Windspeed = 3.35 m/s (7.5 mph)
6747 : // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
6748 110 : Real64 SHGCWinter(0.0); // Center-of-glass solar heat gain coefficient for ASHRAE
6749 110 : Real64 SHGCSummer(0.0);
6750 : // winter and summer conditions
6751 : Real64 TransSolNorm; // Window construction solar transmittance at normal incidence
6752 : Real64 TransVisNorm; // Window construction visible transmittance at normal incidence
6753 : int errFlag; // Error flag
6754 :
6755 110 : auto &wm = state.dataWindowManager;
6756 :
6757 330 : General::ScanForReports(state, "Constructions", wm->DoReport, "Constructions");
6758 :
6759 110 : if (std::any_of(state.dataConstruction->Construct.begin(),
6760 110 : state.dataConstruction->Construct.end(),
6761 296 : [](Construction::ConstructionProps const &e) { return e.TypeIsWindow; })) {
6762 28 : wm->HasWindows = true;
6763 : }
6764 110 : if (std::any_of(state.dataConstruction->Construct.begin(),
6765 110 : state.dataConstruction->Construct.end(),
6766 323 : [](Construction::ConstructionProps const &e) { return e.WindowTypeBSDF; })) {
6767 1 : wm->HasComplexWindows = true; // Yes, this is a bit different than actually using them.
6768 : }
6769 110 : if (std::any_of(state.dataConstruction->Construct.begin(),
6770 110 : state.dataConstruction->Construct.end(),
6771 323 : [](Construction::ConstructionProps const &e) { return e.WindowTypeEQL; })) {
6772 6 : wm->HasEQLWindows = true; // for reporting purpose only
6773 : }
6774 110 : if (wm->DoReport && (wm->HasWindows || wm->HasComplexWindows || wm->HasEQLWindows)) {
6775 1 : auto const &s_mat = state.dataMaterial;
6776 : // Write Descriptions
6777 1 : print(state.files.eio,
6778 : "{}\n",
6779 : "! <WindowConstruction>,Construction Name,Index,#Layers,Roughness,Conductance {W/m2-K},Conductance (Before Adjusted) {W/m2-K},"
6780 : "Convection Coefficient Adjustment Ratio,SHGC,"
6781 : "Solar Transmittance at Normal Incidence,Visible Transmittance at Normal Incidence");
6782 1 : if ((s_mat->NumSimpleWindows > 0) || (s_mat->NumW5Glazings > 0) || (s_mat->NumW5AltGlazings > 0)) {
6783 1 : print(state.files.eio,
6784 : "{}\n",
6785 : "! <WindowMaterial:Glazing>, Material Name, Optical Data Type, Spectral Data Set Name, "
6786 : "Thickness {m}, Solar Transmittance,Front Solar Reflectance, Back Solar Reflectance, Visible "
6787 : "Transmittance, Front Visible Reflectance,Back Visible Reflectance,Infrared Transmittance, "
6788 : "Front Thermal Emissivity, Back Thermal Emissivity,Conductivity {W/m-K},Dirt Factor,Solar "
6789 : "Diffusing");
6790 : }
6791 1 : if ((s_mat->NumW5Gases > 0) || (s_mat->NumW5GasMixtures > 0)) {
6792 0 : print(state.files.eio, "{}\n", "! <WindowMaterial:Gas>,Material Name,GasType,Thickness {m}");
6793 : }
6794 1 : if (s_mat->NumShades > 0) {
6795 0 : print(state.files.eio,
6796 : "{}\n",
6797 : "! <WindowMaterial:Shade>,Material Name,Thickness {m},Conductivity {W/m-K},Thermal "
6798 : "Absorptance,Transmittance,Visible Transmittance,Shade Reflectance");
6799 : }
6800 1 : if (s_mat->NumScreens > 0) {
6801 0 : print(state.files.eio,
6802 : "{}\n",
6803 : "! <WindowMaterial:Screen>,Material Name,Thickness {m},Conductivity {W/m-K},Thermal "
6804 : "Absorptance,Transmittance,Reflectance,Visible Reflectance,Diffuse Reflectance,Diffuse Visible "
6805 : "Reflectance,Screen Material Diameter To Spacing Ratio,Screen To GlassDistance {m}");
6806 : }
6807 1 : if (s_mat->NumBlinds > 0) {
6808 1 : print(state.files.eio,
6809 : "{}\n",
6810 : "! <WindowMaterial:Blind>,Material Name,Slat Width {m},Slat Separation {m},Slat Thickness "
6811 : "{m},Slat Angle {deg},Slat Beam Solar Transmittance,Slat Beam Solar Front Reflectance,Blind To "
6812 : "Glass Distance {m}");
6813 : }
6814 :
6815 1 : if (wm->HasComplexWindows) {
6816 0 : print(state.files.eio,
6817 : "{}\n",
6818 : "! <WindowConstruction:Complex>,Construction Name,Index,#Layers,U-factor {W/m2-K},SHGC"
6819 : "NFRC Product Type,Assembly U-Factor {W/m2-K},Assembly SHGC,Assembly Visible Transmittance");
6820 : }
6821 :
6822 1 : if (wm->HasEQLWindows) {
6823 0 : print(state.files.eio,
6824 : "{}\n",
6825 : "! <Construction:WindowEquivalentLayer>,Construction Name,Index,#Layers,U-factor {W/m2-K},SHGC, "
6826 : "Solar Transmittance at Normal Incidence");
6827 : }
6828 1 : if (s_mat->NumEQLGlazings > 0) {
6829 0 : print(state.files.eio,
6830 : "{}\n",
6831 : "! <WindowMaterial:Glazing:EquivalentLayer>, Material Name, Optical Data Type, Spectral Data "
6832 : "Set Name, Front Side Beam-Beam Solar Transmittance, Back Side Beam-Beam Solar Transmittance, "
6833 : "Front Side Beam-Beam Solar Reflectance, Back Side Beam-Beam Solar Reflectance, Front Side "
6834 : "Beam-Diffuse Solar Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side "
6835 : "Beam-Diffuse Solar Reflectance, Back Side Beam-Diffuse Solar Reflectance, Diffuse-Diffuse "
6836 : "Solar Transmittance, Front Side Diffuse-Diffuse Solar Reflectance, Back Side Diffuse-Diffuse "
6837 : "Solar Reflectance, Infrared Transmittance, Front Side Infrared Emissivity, Back Side Infrared "
6838 : "Emissivity");
6839 : }
6840 1 : if (s_mat->NumEQLShades > 0) {
6841 0 : print(state.files.eio,
6842 : "{}\n",
6843 : "! <WindowMaterial:Shade:EquivalentLayer>, Material Name, Front Side Beam-Beam Solar "
6844 : "Transmittance, Back Side Beam-Beam Solar Transmittance, Front Side Beam-Diffuse Solar "
6845 : "Transmittance, Back Side Beam-Diffuse Solar Transmittance, Front Side Beam-Diffuse Solar "
6846 : "Reflectance, Back Side Beam-Diffuse Solar Reflectance, Infrared Transmittance, Front Side "
6847 : "Infrared Emissivity, Back Side Infrared Emissivity");
6848 : }
6849 :
6850 1 : if (s_mat->NumEQLDrapes > 0) {
6851 0 : print(state.files.eio,
6852 : "{}\n",
6853 : "! <WindowMaterial:Drape:EquivalentLayer>, Material Name, Front Side Beam-Beam Solar "
6854 : "Transmittance, Back Side Beam-Beam Solar Transmittance, Front Side Beam-Diffuse Solar "
6855 : "Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side Beam-Diffuse Solar "
6856 : "Reflectance, Back Side Beam-Diffuse Solar Reflectance, Infrared Transmittance, Front Side "
6857 : "Infrared Emissivity, Back Side Infrared Emissivity, Width of Pleated Fabric, Length of Pleated "
6858 : "Fabric");
6859 : }
6860 :
6861 1 : if (s_mat->NumEQLBlinds > 0) {
6862 0 : print(state.files.eio,
6863 : "{}\n",
6864 : "! <WindowMaterial:Blind:EquivalentLayer>, Material Name, Slat Orientation, Slat Width, Slat "
6865 : "Separation, Slat Crown, Slat Angle, Front Side Slate Beam-Diffuse Solar Transmittance, Back "
6866 : "Side Slate Beam-Diffuse Solar Transmittance, Front Side Slate Beam-Diffuse Solar Reflectance, "
6867 : "Back Side Slate Beam-Diffuse Solar Reflectance, Slat Diffuse-Diffuse Solar Transmittance, "
6868 : "Front Side Slat Diffuse-Diffuse Solar Reflectance, Back Side Slat Diffuse-Diffuse Solar "
6869 : "Reflectance, Infrared Transmittance, Front Side Infrared Emissivity, Back Side Infrared "
6870 : "Emissivity, Slat Angle Control");
6871 : }
6872 1 : if (s_mat->NumEQLScreens > 0) {
6873 0 : print(state.files.eio,
6874 : "{}\n",
6875 : "! <WindowMaterial:Screen:EquivalentLayer>, Material Name, Screen Beam-Beam Solar "
6876 : "Transmittance, Screen Beam-Diffuse Solar Transmittance, Screen Beam-Diffuse Solar Reflectance, "
6877 : "Screen Infrared Transmittance, Screen Infrared Emissivity, Screen Wire Spacing, Screen Wire "
6878 : "Diameter");
6879 : }
6880 1 : if (s_mat->NumEQLGaps > 0) {
6881 0 : print(state.files.eio, "{}\n", "! <WindowMaterial:Gap:EquivalentLayer>, Material Name, GasType, Gap Thickness {m}, Gap Vent Type");
6882 : }
6883 :
6884 26 : for (int ThisNum = 1; ThisNum <= state.dataHeatBal->TotConstructs; ++ThisNum) {
6885 25 : auto &construct = state.dataConstruction->Construct(ThisNum);
6886 25 : if (construct.WindowTypeBSDF) {
6887 :
6888 0 : int i = ThisNum;
6889 0 : WindowComplexManager::CalcComplexWindowThermal(
6890 : state, 0, i, TempVar, TempVar, TempVar, TempVar, DataBSDFWindow::Condition::Winter);
6891 0 : WindowComplexManager::CalcComplexWindowThermal(
6892 : state, 0, i, TempVar, TempVar, TempVar, TempVar, DataBSDFWindow::Condition::Summer);
6893 :
6894 : static constexpr std::string_view Format_800(" WindowConstruction:Complex,{},{},{},{:.3R},{:.3R}\n");
6895 0 : print(state.files.eio,
6896 : Format_800,
6897 0 : construct.Name,
6898 : ThisNum,
6899 0 : construct.TotSolidLayers,
6900 0 : state.dataHeatBal->NominalU(ThisNum),
6901 0 : construct.SummerSHGC);
6902 :
6903 25 : } else if (construct.TypeIsWindow) {
6904 : // Calculate for ASHRAE winter and summer conditions:
6905 : // (1) nominal center-of-glass conductance, including inside and outside air films,
6906 : // (2) solar heat gain coefficient (SHGC),
6907 : // (3) solar transmittance at normal incidence, and (4) visible transmittance at normal incidence.
6908 :
6909 5 : if (construct.WindowTypeEQL) {
6910 : // for equivalent layer Window already calculated
6911 : // NominalU(ThisNum)=NominalConductanceWinter
6912 : // Save the SHGC for later use in tabular report IVRS
6913 : // Construct(ThisNum)%SummerSHGC = SHGCSummer
6914 0 : construct.VisTransNorm = 0.0; // TODO list
6915 :
6916 : static constexpr std::string_view Format_799(" Construction:WindowEquivalentLayer,{},{},{},{:.3R},{:.3R},{:.3R}\n");
6917 0 : print(state.files.eio,
6918 : Format_799,
6919 0 : construct.Name,
6920 : ThisNum,
6921 0 : construct.TotSolidLayers,
6922 0 : state.dataHeatBal->NominalU(ThisNum),
6923 0 : construct.SummerSHGC,
6924 0 : construct.SolTransNorm);
6925 :
6926 : } else {
6927 :
6928 5 : CalcNominalWindowCond(state, ThisNum, 1, NominalConductanceWinter, SHGCWinter, TransSolNorm, TransVisNorm, errFlag);
6929 :
6930 5 : if (errFlag == 1) {
6931 0 : ShowWarningError(state, format("Window construction {} has an interior or exterior blind", construct.Name));
6932 0 : ShowContinueError(state, "but the corresponding construction without the blind cannot be found.");
6933 0 : ShowContinueError(state, "The ReportGlass entry for this construction will not be printed in eplusout.eio.");
6934 0 : continue;
6935 : }
6936 :
6937 : // Skip constructions with between-glass shade/blind until method is worked out to determine
6938 : // nominal conductance and SHGC.
6939 :
6940 5 : if (errFlag == 2) {
6941 0 : ShowWarningError(state, format("Window construction {} has a between-glass shade or blind", construct.Name));
6942 0 : ShowContinueError(state, "The ReportGlass entry for this construction will not be printed in eplusout.eio.");
6943 0 : continue;
6944 : }
6945 :
6946 5 : state.dataHeatBal->NominalU(ThisNum) = NominalConductanceWinter;
6947 5 : if (!construct.WindowTypeEQL) {
6948 5 : CalcNominalWindowCond(state, ThisNum, 2, NominalConductanceSummer, SHGCSummer, TransSolNorm, TransVisNorm, errFlag);
6949 : }
6950 : // Save the SHGC for later use in tabular report IVRS
6951 5 : construct.SummerSHGC = SHGCSummer;
6952 5 : construct.VisTransNorm = TransVisNorm;
6953 5 : construct.SolTransNorm = TransSolNorm;
6954 :
6955 : static constexpr std::string_view Format_700(" WindowConstruction,{},{},{},{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
6956 10 : print(state.files.eio,
6957 : Format_700,
6958 5 : construct.Name,
6959 : ThisNum,
6960 5 : construct.TotLayers,
6961 5 : Material::surfaceRoughnessNames[(int)construct.OutsideRoughness],
6962 : NominalConductanceWinter,
6963 5 : state.dataHeatBal->NominalUBeforeAdjusted(ThisNum),
6964 5 : state.dataHeatBal->CoeffAdjRatio(ThisNum),
6965 : SHGCSummer,
6966 : TransSolNorm,
6967 : TransVisNorm);
6968 : }
6969 : // Write(OutputFileConstrainParams, 705) TRIM(Construct(ThisNum)%Name), SHGCSummer ,TransVisNorm
6970 :
6971 11 : for (int i = 1; i <= construct.TotLayers; ++i) {
6972 6 : int Layer = construct.LayerPoint(i);
6973 6 : auto const *mat = s_mat->materials(Layer);
6974 6 : std::string SpectralDataName;
6975 :
6976 6 : switch (mat->group) {
6977 :
6978 0 : case Material::Group::Gas: {
6979 0 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
6980 0 : assert(matGas != nullptr);
6981 : static constexpr std::string_view Format_702(" WindowMaterial:Gas,{},{},{:.3R}\n");
6982 0 : print(state.files.eio, Format_702, matGas->Name, Material::gasTypeNames[(int)matGas->gases[0].type], matGas->Thickness);
6983 : //! fw CASE(WindowGasMixture)
6984 0 : } break;
6985 :
6986 0 : case Material::Group::Shade: {
6987 0 : auto const *matShade = dynamic_cast<Material::MaterialShade const *>(mat);
6988 0 : assert(matShade != nullptr);
6989 :
6990 : static constexpr std::string_view Format_703(" WindowMaterial:Shade,{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
6991 0 : print(state.files.eio,
6992 : Format_703,
6993 0 : matShade->Name,
6994 0 : matShade->Thickness,
6995 0 : matShade->Conductivity,
6996 0 : matShade->AbsorpThermal,
6997 0 : matShade->Trans,
6998 0 : matShade->TransVis,
6999 0 : matShade->ReflectShade);
7000 0 : } break;
7001 :
7002 1 : case Material::Group::Blind: {
7003 1 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(mat);
7004 :
7005 : static constexpr std::string_view Format_704(
7006 : " WindowMaterial:Blind,{},{:.4R},{:.4R},{:.4R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
7007 1 : print(state.files.eio,
7008 : Format_704,
7009 1 : matBlind->Name,
7010 1 : matBlind->SlatWidth,
7011 1 : matBlind->SlatSeparation,
7012 1 : matBlind->SlatThickness,
7013 1 : matBlind->SlatAngle,
7014 1 : matBlind->slatTAR.Sol.Ft.Bm[0].DfTra,
7015 1 : matBlind->slatTAR.Sol.Ft.Bm[0].DfRef,
7016 1 : matBlind->toGlassDist);
7017 1 : } break;
7018 :
7019 0 : case Material::Group::Screen: {
7020 0 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(mat);
7021 0 : assert(matScreen != nullptr);
7022 0 : auto const &btar = matScreen->btars[0][0]; // AR: Going with normal incidence here
7023 :
7024 : static constexpr std::string_view Format_706 =
7025 : " WindowMaterial:Screen,{},{:.5R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n";
7026 :
7027 : // AR: assuming normal incidence
7028 0 : print(state.files.eio,
7029 : Format_706,
7030 0 : matScreen->Name,
7031 0 : matScreen->Thickness,
7032 0 : matScreen->Conductivity,
7033 0 : matScreen->AbsorpThermal,
7034 0 : btar.BmTrans,
7035 0 : btar.RefSolFront,
7036 0 : btar.RefVisFront,
7037 0 : matScreen->DfRef,
7038 0 : matScreen->DfRefVis,
7039 0 : matScreen->diameterToSpacingRatio,
7040 0 : matScreen->toGlassDist);
7041 0 : } break;
7042 :
7043 5 : case Material::Group::Glass:
7044 : case Material::Group::GlassSimple: {
7045 5 : auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
7046 5 : assert(matGlass != nullptr);
7047 5 : std::string SolarDiffusing = "No";
7048 5 : if (matGlass->SolarDiffusing) {
7049 0 : SolarDiffusing = "Yes";
7050 : }
7051 :
7052 5 : if (matGlass->windowOpticalData == Window::OpticalDataModel::Spectral) {
7053 0 : SpectralDataName = s_mat->SpectralData(matGlass->GlassSpectralDataPtr).Name;
7054 5 : } else if (matGlass->windowOpticalData == Window::OpticalDataModel::SpectralAndAngle) {
7055 0 : SpectralDataName = format("{}, {}, {}",
7056 0 : matGlass->GlassSpecAngTransCurve->Name,
7057 0 : matGlass->GlassSpecAngFReflCurve->Name,
7058 0 : matGlass->GlassSpecAngBReflCurve->Name);
7059 : } else {
7060 5 : SpectralDataName = "";
7061 : }
7062 :
7063 : static constexpr std::string_view Format_707(
7064 : " WindowMaterial:Glazing,{},{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{"
7065 : ":.5R},{:.5R},{:.5R},{:.5R},{:.5R},{}\n");
7066 5 : print(state.files.eio,
7067 : Format_707,
7068 5 : matGlass->Name,
7069 5 : Window::opticalDataModelNames[(int)matGlass->windowOpticalData],
7070 : SpectralDataName,
7071 5 : matGlass->Thickness,
7072 5 : matGlass->Trans,
7073 5 : matGlass->ReflectSolBeamFront,
7074 5 : matGlass->ReflectSolBeamBack,
7075 5 : matGlass->TransVis,
7076 5 : matGlass->ReflectVisBeamFront,
7077 5 : matGlass->ReflectVisBeamBack,
7078 5 : matGlass->TransThermal,
7079 5 : matGlass->AbsorpThermalFront,
7080 5 : matGlass->AbsorpThermalBack,
7081 5 : matGlass->Conductivity,
7082 5 : matGlass->GlassTransDirtFactor,
7083 : SolarDiffusing);
7084 5 : } break;
7085 :
7086 0 : case Material::Group::GlassEQL: {
7087 0 : auto const *matEQL = dynamic_cast<Material::MaterialGlassEQL const *>(mat);
7088 0 : assert(matEQL != nullptr);
7089 0 : std::string OpticalDataType = "SpectralAverage";
7090 0 : SpectralDataName = "";
7091 : static constexpr std::string_view Format_708(
7092 : " WindowMaterial:Glazing:EquivalentLayer,{},{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}"
7093 : ",{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}\n");
7094 0 : print(state.files.eio,
7095 : Format_708,
7096 0 : matEQL->Name,
7097 : OpticalDataType,
7098 : SpectralDataName,
7099 0 : matEQL->TAR.Sol.Ft.Bm[0].BmTra,
7100 0 : matEQL->TAR.Sol.Bk.Bm[0].BmTra,
7101 0 : matEQL->TAR.Sol.Ft.Bm[0].BmRef,
7102 0 : matEQL->TAR.Sol.Bk.Bm[0].BmRef,
7103 0 : matEQL->TAR.Sol.Ft.Bm[0].DfTra,
7104 0 : matEQL->TAR.Sol.Bk.Bm[0].DfTra,
7105 0 : matEQL->TAR.Sol.Ft.Bm[0].DfRef,
7106 0 : matEQL->TAR.Sol.Bk.Bm[0].DfRef,
7107 0 : matEQL->TAR.Sol.Ft.Df.Tra,
7108 0 : matEQL->TAR.Sol.Ft.Df.Ref,
7109 0 : matEQL->TAR.Sol.Bk.Df.Ref,
7110 0 : matEQL->TAR.IR.Ft.Tra,
7111 0 : matEQL->TAR.IR.Ft.Emi,
7112 0 : matEQL->TAR.IR.Bk.Emi);
7113 0 : } break;
7114 :
7115 0 : case Material::Group::ShadeEQL: {
7116 0 : auto const *matEQL = dynamic_cast<Material::MaterialShadeEQL const *>(mat);
7117 0 : assert(matEQL != nullptr);
7118 : static constexpr std::string_view Format_709(
7119 : " WindowMaterial:Shade:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R}\n");
7120 0 : print(state.files.eio,
7121 : Format_709,
7122 0 : matEQL->Name,
7123 0 : matEQL->TAR.Sol.Ft.Bm[0].BmTra,
7124 0 : matEQL->TAR.Sol.Bk.Bm[0].BmTra,
7125 0 : matEQL->TAR.Sol.Ft.Bm[0].DfTra,
7126 0 : matEQL->TAR.Sol.Bk.Bm[0].DfTra,
7127 0 : matEQL->TAR.Sol.Ft.Bm[0].DfRef,
7128 0 : matEQL->TAR.Sol.Bk.Bm[0].DfRef,
7129 0 : matEQL->TAR.IR.Ft.Tra,
7130 0 : matEQL->TAR.IR.Ft.Emi,
7131 0 : matEQL->TAR.IR.Bk.Emi);
7132 0 : } break;
7133 :
7134 0 : case Material::Group::DrapeEQL: {
7135 0 : auto const *matEQL = dynamic_cast<Material::MaterialDrapeEQL const *>(mat);
7136 0 : assert(matEQL != nullptr);
7137 : static constexpr std::string_view Format_710(
7138 : " WindowMaterial:Drape:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},"
7139 : "{:.4R},{:.4R},{:.5R},{:.5R}\n");
7140 0 : print(state.files.eio,
7141 : Format_710,
7142 0 : matEQL->Name,
7143 0 : matEQL->TAR.Sol.Ft.Bm[0].BmTra,
7144 0 : matEQL->TAR.Sol.Ft.Bm[0].DfTra,
7145 0 : matEQL->TAR.Sol.Bk.Bm[0].DfTra,
7146 0 : matEQL->TAR.Sol.Ft.Bm[0].DfRef,
7147 0 : matEQL->TAR.Sol.Bk.Bm[0].DfRef,
7148 0 : matEQL->TAR.IR.Ft.Tra,
7149 0 : matEQL->TAR.IR.Ft.Emi,
7150 0 : matEQL->TAR.IR.Bk.Emi,
7151 0 : matEQL->pleatedWidth,
7152 0 : matEQL->pleatedLength);
7153 0 : } break;
7154 :
7155 0 : case Material::Group::ScreenEQL: {
7156 0 : auto const *matEQL = dynamic_cast<Material::MaterialScreenEQL const *>(mat);
7157 0 : assert(matEQL != nullptr);
7158 : static constexpr std::string_view Format_711(
7159 : " WindowMaterial:Screen:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R}"
7160 : ",{:.4R},{:.4R},{:.5R},{:.5R}\n");
7161 0 : print(state.files.eio,
7162 : Format_711,
7163 0 : matEQL->Name,
7164 0 : matEQL->TAR.Sol.Ft.Bm[0].BmTra,
7165 0 : matEQL->TAR.Sol.Ft.Bm[0].DfTra,
7166 0 : matEQL->TAR.Sol.Bk.Bm[0].DfTra,
7167 0 : matEQL->TAR.Sol.Ft.Bm[0].DfRef,
7168 0 : matEQL->TAR.Sol.Bk.Bm[0].DfRef,
7169 0 : matEQL->TAR.IR.Ft.Tra,
7170 0 : matEQL->TAR.IR.Ft.Emi,
7171 0 : matEQL->TAR.IR.Bk.Emi,
7172 0 : matEQL->wireSpacing,
7173 0 : matEQL->wireDiameter);
7174 0 : } break;
7175 :
7176 0 : case Material::Group::BlindEQL: {
7177 0 : auto const *matEQL = dynamic_cast<Material::MaterialBlindEQL const *>(mat);
7178 0 : assert(matEQL != nullptr);
7179 :
7180 : // Formats
7181 : static constexpr std::string_view Format_712(
7182 : " WindowMaterial:Blind:EquivalentLayer,{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:."
7183 : "5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}");
7184 0 : print(state.files.eio,
7185 : Format_712,
7186 0 : matEQL->Name,
7187 0 : DataWindowEquivalentLayer::orientationNames[(int)matEQL->SlatOrientation],
7188 0 : matEQL->SlatWidth,
7189 0 : matEQL->SlatSeparation,
7190 0 : matEQL->SlatCrown,
7191 0 : matEQL->SlatAngle,
7192 0 : matEQL->TAR.Sol.Ft.Bm[0].DfTra,
7193 0 : matEQL->TAR.Sol.Bk.Bm[0].DfTra,
7194 0 : matEQL->TAR.Sol.Ft.Bm[0].DfRef,
7195 0 : matEQL->TAR.Sol.Bk.Bm[0].DfRef,
7196 0 : matEQL->TAR.Sol.Ft.Df.Tra,
7197 0 : matEQL->TAR.Sol.Ft.Df.Ref,
7198 0 : matEQL->TAR.Sol.Bk.Df.Ref,
7199 0 : matEQL->TAR.IR.Ft.Tra,
7200 0 : matEQL->TAR.IR.Ft.Emi,
7201 0 : matEQL->TAR.IR.Bk.Emi);
7202 0 : } break;
7203 :
7204 0 : case Material::Group::WindowGapEQL: {
7205 0 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
7206 0 : assert(matGas != nullptr);
7207 : static constexpr std::string_view Format_713(" WindowMaterial:Gap:EquivalentLayer,{},{},{:.3R},{}\n");
7208 0 : print(state.files.eio,
7209 : Format_713,
7210 0 : matGas->Name,
7211 0 : Material::gasTypeNames[(int)matGas->gases[0].type],
7212 0 : matGas->Thickness,
7213 0 : Material::gapVentTypeNames[(int)matGas->gapVentType]);
7214 0 : } break;
7215 :
7216 0 : default:
7217 0 : break;
7218 : }
7219 6 : } // for (i)
7220 : } // if (construct.TypeIsWindow)
7221 : } // for (ThisNum)
7222 :
7223 109 : } else if (wm->HasWindows) {
7224 :
7225 143 : for (int ThisNum = 1; ThisNum <= state.dataHeatBal->TotConstructs; ++ThisNum) {
7226 116 : auto &construct = state.dataConstruction->Construct(ThisNum);
7227 116 : if (!construct.TypeIsWindow) {
7228 79 : continue;
7229 : }
7230 37 : if (construct.WindowTypeEQL) {
7231 6 : continue; // skip if equivalent layer window
7232 : }
7233 :
7234 : // Calculate for ASHRAE winter and summer conditions: (1)nominal center-of-glass conductance,
7235 : // (2) solar heat gain coefficient (SHGC), including inside and outside air films,
7236 : // (3) solar transmittance at normal incidence, and (4) visible transmittance at normal incidence.
7237 :
7238 31 : CalcNominalWindowCond(state, ThisNum, 1, NominalConductanceWinter, SHGCWinter, TransSolNorm, TransVisNorm, errFlag);
7239 31 : if (errFlag == 1 || errFlag == 2) {
7240 0 : continue;
7241 : }
7242 31 : state.dataHeatBal->NominalU(ThisNum) = NominalConductanceWinter;
7243 : // Need to have this because of window assembly reports (Simon)
7244 31 : construct.SummerSHGC = SHGCSummer;
7245 31 : construct.VisTransNorm = TransVisNorm;
7246 : }
7247 : }
7248 110 : } // ReportGlass()
7249 :
7250 : //*************************************************************************************
7251 :
7252 2 : void CalcWindowBlindProperties(EnergyPlusData &state)
7253 : {
7254 :
7255 : // SUBROUTINE INFORMATION:
7256 : // AUTHOR Hans Simmler
7257 : // DATE WRITTEN July-Aug 1995
7258 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
7259 : // Dec 2001 (FCW): add variable slat angle
7260 :
7261 : // PURPOSE OF THIS SUBROUTINE:
7262 : // Calculates solar-optical properties of a window blind
7263 : // from slat properties and solar profile angle. Assumes flat slats.
7264 :
7265 : // METHODOLOGY EMPLOYED:
7266 : // The solar profile angle is varied from -90 to +90 deg and slat angle is varied from 0 to 180deg,
7267 : // covering the full range of possible profile angles and slat angles.
7268 : // (The profile angle is defined as the angle of incidence when the radiation
7269 : // source is located in a plane that (1)is perpendicular to the plane of the blinds [which is
7270 : // the same as the window plane] and (2) contains the slat normal vector.)
7271 :
7272 : // In the time-step calculation,the blind properties vs. profile angle and slat angle
7273 : // that are calculated here will be applicable to windows and slats
7274 : // of arbitrary orientation, and to arbitrary sun positions, as long as the appropriate
7275 : // profile angle is used. The slat angle for a particular window with blinds is determined
7276 : // each time step in subroutine WindowShadingManager on the basis of user-specified
7277 : // slat control options.
7278 :
7279 : // REFERENCES:
7280 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
7281 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
7282 :
7283 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7284 :
7285 2 : Array1D<Real64> bld_pr(15); // Slat properties
7286 2 : Array1D<Real64> st_lay(16); // Solar-optical blind/glazing system properties
7287 : Real64 sun_el; // Solar profile angle (radians)
7288 2 : Array1D<Real64> sun_el_deg(Material::MaxProfAngs); // Solar profile angle (deg) corresponding to sun_el values
7289 : Real64 bld_el; // Slat angle (elevation of slat normal vector in plane
7290 : // perpendicular to window and containing the slat normal vector) (radians)
7291 :
7292 2 : auto &s_mat = state.dataMaterial;
7293 :
7294 46 : for (auto *mat : s_mat->materials) {
7295 44 : if (mat->group != Material::Group::Blind) {
7296 42 : continue;
7297 : }
7298 :
7299 2 : auto *matBlind = dynamic_cast<Material::MaterialBlind *>(mat);
7300 2 : assert(matBlind != nullptr);
7301 :
7302 2 : bld_pr(2) = matBlind->SlatWidth;
7303 2 : bld_pr(3) = matBlind->SlatSeparation;
7304 :
7305 6 : for (int ISolVis = 1; ISolVis <= 2; ++ISolVis) {
7306 4 : if (ISolVis == 1) { // For solar calculation
7307 2 : bld_pr(4) = 0.0;
7308 2 : bld_pr(5) = 0.0;
7309 2 : bld_pr(6) = 0.0;
7310 2 : bld_pr(7) = matBlind->slatTAR.Sol.Ft.Bm[0].DfTra;
7311 2 : bld_pr(8) = matBlind->slatTAR.Sol.Ft.Bm[0].DfRef;
7312 2 : bld_pr(9) = matBlind->slatTAR.Sol.Bk.Bm[0].DfRef;
7313 2 : bld_pr(10) = matBlind->slatTAR.Sol.Ft.Df.Tra;
7314 2 : bld_pr(11) = matBlind->slatTAR.Sol.Ft.Df.Ref;
7315 2 : bld_pr(12) = matBlind->slatTAR.Sol.Bk.Df.Ref;
7316 : } else { // For visible calculation
7317 2 : bld_pr(4) = 0.0;
7318 2 : bld_pr(5) = 0.0;
7319 2 : bld_pr(6) = 0.0;
7320 2 : bld_pr(7) = matBlind->slatTAR.Vis.Ft.Bm[0].DfTra;
7321 2 : bld_pr(8) = matBlind->slatTAR.Vis.Ft.Bm[0].DfRef;
7322 2 : bld_pr(9) = matBlind->slatTAR.Vis.Bk.Bm[0].DfRef;
7323 2 : bld_pr(10) = matBlind->slatTAR.Vis.Ft.Df.Tra;
7324 2 : bld_pr(11) = matBlind->slatTAR.Vis.Ft.Df.Ref;
7325 2 : bld_pr(12) = matBlind->slatTAR.Vis.Bk.Df.Ref;
7326 : }
7327 : // For IR calculation
7328 4 : bld_pr(13) = matBlind->slatTAR.IR.Ft.Tra;
7329 4 : bld_pr(14) = matBlind->slatTAR.IR.Ft.Emi;
7330 4 : bld_pr(15) = matBlind->slatTAR.IR.Bk.Emi;
7331 :
7332 : // Calculate diffuse properties of blind. If blind has variable slat angle, &
7333 : // vary slat angle from 0 to 180 deg in 10-deg steps (for Material::MaxSlatAngs = 19).
7334 : // If blind has fixed slat angle, calculate properties at that angle only.
7335 :
7336 728 : for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
7337 :
7338 724 : auto &btar = matBlind->TARs[iSlatAng];
7339 :
7340 724 : st_lay = 0.0;
7341 724 : bld_el = Material::dSlatAng * iSlatAng; // 0 <= bld_el <= 180 deg
7342 :
7343 724 : BlindOpticsDiffuse(state, matBlind->Num, ISolVis, bld_pr, bld_el, st_lay);
7344 :
7345 724 : if (ISolVis == 1) { // Fill blind diffuse solar and IR properties
7346 362 : btar.Sol.Ft.Df.Tra = st_lay(9);
7347 362 : btar.Sol.Ft.Df.Ref = st_lay(10);
7348 362 : btar.Sol.Bk.Df.Tra = st_lay(11);
7349 362 : btar.Sol.Bk.Df.Ref = st_lay(12);
7350 362 : btar.Sol.Ft.Df.Abs = max(0.0, 1.0 - st_lay(9) - st_lay(10));
7351 362 : btar.Sol.Bk.Df.Abs = max(0.0, 1.0 - st_lay(11) - st_lay(12));
7352 362 : btar.IR.Ft.Tra = st_lay(13);
7353 362 : btar.IR.Ft.Emi = st_lay(14);
7354 362 : btar.IR.Bk.Tra = st_lay(13);
7355 362 : btar.IR.Bk.Emi = st_lay(15);
7356 : } else { // Fill blind diffuse visible properties
7357 362 : btar.Vis.Ft.Df.Tra = st_lay(9);
7358 362 : btar.Vis.Ft.Df.Ref = st_lay(10);
7359 362 : btar.Vis.Bk.Df.Tra = st_lay(11);
7360 362 : btar.Vis.Bk.Df.Ref = st_lay(12);
7361 : }
7362 :
7363 : // If blind has variable slat angle, vary slat angle from 0 to 180 deg in 10-deg steps
7364 : // (for Material::MaxSlatAngs = 19). If blind has fixed slat angle, calculate properties at that angle only.
7365 :
7366 27512 : for (int IProfAng = 1; IProfAng <= Material::MaxProfAngs; ++IProfAng) {
7367 26788 : sun_el = -Constant::Pi / 2.0 + (Constant::Pi / 36.0) * (IProfAng - 1);
7368 26788 : sun_el_deg(IProfAng) = 57.2958 * sun_el;
7369 :
7370 : // Beam solar-optical properties of blind for given profile angle and slat angle
7371 :
7372 26788 : BlindOpticsBeam(state, matBlind->Num, bld_pr, bld_el, sun_el, st_lay);
7373 :
7374 26788 : if (ISolVis == 1) { // Fill blind beam solar properties
7375 13394 : btar.Sol.Ft.Bm[IProfAng].BmTra = st_lay(1);
7376 13394 : btar.Sol.Ft.Bm[IProfAng].BmRef = st_lay(2);
7377 13394 : btar.Sol.Bk.Bm[IProfAng].BmTra = st_lay(3);
7378 13394 : btar.Sol.Bk.Bm[IProfAng].BmRef = st_lay(4);
7379 13394 : btar.Sol.Ft.Bm[IProfAng].DfTra = st_lay(5);
7380 13394 : btar.Sol.Ft.Bm[IProfAng].DfRef = st_lay(6);
7381 13394 : btar.Sol.Bk.Bm[IProfAng].DfTra = st_lay(7);
7382 13394 : btar.Sol.Bk.Bm[IProfAng].DfRef = st_lay(8);
7383 13394 : btar.Sol.Ft.Bm[IProfAng].Abs = max(0.0, 1.0 - st_lay(6) - st_lay(1) - st_lay(5));
7384 13394 : btar.Sol.Bk.Bm[IProfAng].Abs = max(0.0, 1.0 - st_lay(7) - st_lay(3) - st_lay(8));
7385 :
7386 : } else { // Fill blind beam visible properties
7387 13394 : btar.Vis.Ft.Bm[IProfAng].BmTra = st_lay(1);
7388 13394 : btar.Vis.Ft.Bm[IProfAng].BmRef = st_lay(2);
7389 13394 : btar.Vis.Bk.Bm[IProfAng].BmTra = st_lay(3);
7390 13394 : btar.Vis.Bk.Bm[IProfAng].BmRef = st_lay(4);
7391 13394 : btar.Vis.Ft.Bm[IProfAng].DfTra = st_lay(5);
7392 13394 : btar.Vis.Ft.Bm[IProfAng].DfRef = st_lay(6);
7393 13394 : btar.Vis.Bk.Bm[IProfAng].DfTra = st_lay(7);
7394 13394 : btar.Vis.Bk.Bm[IProfAng].DfRef = st_lay(8);
7395 : }
7396 : } // End of loop over slat angles
7397 : } // End of loop over profile angles
7398 :
7399 4 : if (ISolVis == 1) {
7400 :
7401 364 : for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
7402 362 : auto &btar = matBlind->TARs[iSlatAng];
7403 :
7404 362 : Real64 sumDenom = 0.0, sumTra1 = 0.0, sumTra2 = 0.0, sumRef = 0.0, sumAbs = 0.0;
7405 :
7406 : // Integrate from -90 to 0 deg
7407 6878 : for (int IPhi = 1; IPhi <= 18; ++IPhi) {
7408 6516 : auto const &btargs = btar.Sol.Ft.Bm[IPhi];
7409 6516 : auto const &btargs1 = btar.Sol.Ft.Bm[IPhi + 1];
7410 :
7411 6516 : Real64 denom = Material::dProfAng * std::cos(-Constant::PiOvr2 + (IPhi - 0.5) * Material::dProfAng);
7412 6516 : sumDenom += denom;
7413 : // Why adding beam transmittance here?
7414 6516 : sumTra1 += denom * (btargs.BmTra + btargs1.BmTra) * 0.5;
7415 6516 : sumTra2 += denom * (btargs.DfTra + btargs1.DfTra) * 0.5;
7416 6516 : sumRef += denom * (btargs.DfRef + btargs1.DfRef) * 0.5;
7417 6516 : sumAbs += denom * (btargs.Abs + btargs1.Abs) * 0.5;
7418 : }
7419 :
7420 362 : btar.Sol.Ft.Df.TraGnd = std::max(0.0, sumTra1 / sumDenom) + std::max(0.0, sumTra2 / sumDenom);
7421 362 : btar.Sol.Ft.Df.RefGnd = std::max(0.0, sumRef / sumDenom);
7422 362 : btar.Sol.Ft.Df.AbsGnd = std::max(0.0, sumAbs / sumDenom);
7423 :
7424 362 : sumDenom = sumTra1 = sumTra2 = sumRef = sumAbs = 0.0;
7425 :
7426 : // Integrate from -90 to 0 deg
7427 6878 : for (int IPhi = 19; IPhi <= Material::MaxProfAngs - 1; ++IPhi) {
7428 6516 : auto const &btargs = btar.Sol.Ft.Bm[IPhi];
7429 6516 : auto const &btargs1 = btar.Sol.Ft.Bm[IPhi + 1];
7430 :
7431 6516 : Real64 denom = Material::dProfAng * std::cos(-Constant::PiOvr2 + (IPhi - 0.5) * Material::dProfAng);
7432 6516 : sumDenom += denom;
7433 : // Why adding beam transmittance here?
7434 6516 : sumTra1 += denom * (btargs.BmTra + btargs1.BmTra) * 0.5;
7435 6516 : sumTra2 += denom * (btargs.DfTra + btargs1.DfTra) * 0.5;
7436 6516 : sumRef += denom * (btargs.DfRef + btargs1.DfRef) * 0.5;
7437 6516 : sumAbs += denom * (btargs.Abs + btargs1.Abs) * 0.5;
7438 : }
7439 :
7440 362 : btar.Sol.Ft.Df.TraSky = std::max(0.0, sumTra1 / sumDenom) + std::max(0.0, sumTra2 / sumDenom);
7441 362 : btar.Sol.Ft.Df.RefSky = std::max(0.0, sumRef / sumDenom);
7442 362 : btar.Sol.Ft.Df.AbsSky = std::max(0.0, sumAbs / sumDenom);
7443 : } // for (iSlatAng)
7444 : }
7445 :
7446 : } // End of loop over solar vs. visible properties
7447 :
7448 : } // End of loop over blinds
7449 2 : } // CalcWindowBlindProperties()
7450 :
7451 : //*************************************************************************************
7452 :
7453 0 : void CalcWindowScreenProperties(EnergyPlusData &state)
7454 : {
7455 :
7456 : // SUBROUTINE INFORMATION:
7457 : // AUTHOR Richard Raustad
7458 : // DATE WRITTEN April 2006
7459 :
7460 : // PURPOSE OF THIS SUBROUTINE:
7461 : // Initialize static properties of window screens.
7462 :
7463 : // METHODOLOGY EMPLOYED:
7464 : // Loop through all surfaces to determine which window has an exterior screen. Static
7465 : // variables are defined here, dynamic variables are calculated in CalcScreenTransmittance.
7466 :
7467 : // Locals
7468 : // SUBROUTINE PARAMETER DEFINITIONS:
7469 0 : int constexpr M = 18;
7470 0 : int constexpr N = 18;
7471 :
7472 : int ConstrNumSh; // Index to shaded construction
7473 : int MatNum; // Index to material number
7474 : Real64 SumTrans; // Integration variable for transmittance
7475 : Real64 SumTransVis; // Integration variable for visible transmittance
7476 : Real64 SumReflect; // Integration variable for reflectance
7477 : Real64 SumReflectVis; // Integration variable for visible reflectance
7478 : Real64 SumArea; // Integration variable for area of quarter hemisphere
7479 : // is used on multiple surfaces
7480 :
7481 : // Pre-calculate these constants
7482 0 : std::vector<Real64> sunAzimuth;
7483 0 : std::vector<Real64> sin_sunAzimuth;
7484 0 : std::vector<Real64> cos_sunAzimuth;
7485 0 : std::vector<Real64> sunAltitude;
7486 0 : std::vector<Real64> sin_sunAltitude;
7487 0 : std::vector<Real64> cos_sunAltitude;
7488 0 : std::vector<Real64> skyArea; // Area of integration
7489 0 : Array2D<Real64> relativeAzimuth; // Relative azimuth angle of sun with respect to surface outward normal
7490 0 : Array2D<Real64> relativeAltitude; // Relative altitude angle of sun with respect to surface outward normal
7491 :
7492 0 : auto &s_mat = state.dataMaterial;
7493 0 : auto &s_surf = state.dataSurface;
7494 :
7495 0 : relativeAzimuth.allocate(N, M);
7496 0 : relativeAltitude.allocate(N, M);
7497 :
7498 0 : for (int j = 0; j <= N - 1; ++j) {
7499 0 : Real64 currAzimuth = (90.0 / N) * j * Constant::DegToRad;
7500 0 : sunAzimuth.push_back(currAzimuth); // Azimuth angle of sun during integration
7501 0 : sin_sunAzimuth.push_back(std::sin(currAzimuth));
7502 0 : cos_sunAzimuth.push_back(std::cos(currAzimuth));
7503 : }
7504 :
7505 0 : for (int i = 0; i <= M - 1; ++i) {
7506 0 : Real64 currAltitude = (90.0 / M) * i * Constant::DegToRad;
7507 0 : sunAltitude.push_back(currAltitude); // Altitude angle of sun during integration
7508 0 : sin_sunAltitude.push_back(std::sin(currAltitude));
7509 0 : cos_sunAltitude.push_back(std::cos(currAltitude));
7510 0 : skyArea.push_back(sin_sunAltitude[i] * cos_sunAltitude[i]);
7511 : }
7512 :
7513 0 : for (int j = 1; j <= N; ++j) {
7514 0 : for (int i = 1; i <= M; ++i) {
7515 : // Integrate transmittance using coordinate transform
7516 0 : relativeAzimuth(i, j) = std::asin(sin_sunAltitude[i - 1] * cos_sunAzimuth[j - 1]); // phi prime
7517 0 : relativeAltitude(i, j) = std::atan(std::tan(sunAltitude[i - 1]) * sin_sunAzimuth[j - 1]); // alpha
7518 : }
7519 : }
7520 :
7521 0 : bool PrintTransMap = false; // Flag used to print transmittance map
7522 :
7523 0 : for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
7524 0 : auto const &surf = s_surf->Surface(SurfNum);
7525 :
7526 0 : if (!surf.HasShadeControl) {
7527 0 : continue;
7528 : }
7529 :
7530 0 : if (s_surf->WindowShadingControl(surf.activeWindowShadingControl).ShadingType != WinShadingType::ExtScreen) {
7531 0 : continue;
7532 : }
7533 :
7534 0 : ConstrNumSh = surf.activeShadedConstruction;
7535 0 : MatNum = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1);
7536 0 : auto *matScreen = dynamic_cast<Material::MaterialScreen *>(s_mat->materials(MatNum));
7537 0 : assert(matScreen != nullptr);
7538 0 : s_surf->SurfaceWindow(SurfNum).screenNum = MatNum;
7539 :
7540 0 : if (matScreen->isUsed) {
7541 0 : continue; // Has already been initialized
7542 : }
7543 :
7544 0 : matScreen->isUsed = true;
7545 0 : if (matScreen->mapDegResolution > 0) {
7546 0 : PrintTransMap = true;
7547 : }
7548 :
7549 : // If a screen material is used more than once, the Material structure's screen data pointer holds the screen number
7550 : // of the last window surface. Use this method to access the screen parameter's only for static variables such as
7551 : // diffuse properties (InitGlassOpticalCalculations). For all cases where the screen properties are a function of
7552 : // sun azimuth and altitude angles, use the Screens structure.
7553 : // Invert calculation done in GetMaterialInput to find Diameter to Spacing ratio (Props(7)/Props(6))
7554 : // dataMaterial.Material(MaterNum)%Trans = (1 - MaterialProps(7)/MaterialProps(6))**2.0
7555 0 : matScreen->diameterToSpacingRatio = 1.0 - std::sqrt(matScreen->Trans);
7556 :
7557 : // Reflectance of screen material only
7558 0 : matScreen->CylinderRef = matScreen->ShadeRef / (1 - matScreen->Trans);
7559 0 : matScreen->CylinderRefVis = matScreen->ShadeRefVis / (1 - matScreen->Trans);
7560 :
7561 : // Integrate the transmittance over a quarter hemisphere for use in diffuse calculations
7562 0 : SumTrans = 0.0;
7563 0 : SumTransVis = 0.0;
7564 0 : SumReflect = 0.0;
7565 0 : SumReflectVis = 0.0;
7566 0 : SumArea = 0.0;
7567 : // Integration over quarter hemisphere in polar coordinates and converting to rectangular to call screen model.
7568 : // Proceed in reverse order such that the last calculation yields zero sun angle to window screen normal (angles=0,0).
7569 : // The properties calculated at zero sun angle are then used elsewhere prior to the start of the actual simulation.
7570 :
7571 0 : Material::ScreenBmTransAbsRef btar;
7572 :
7573 0 : for (int j = N; j >= 1; --j) {
7574 0 : for (int i = M; i >= 1; --i) {
7575 : // Integrate transmittance using coordinate transform
7576 : // TODO: switch to interpolation?
7577 0 : CalcScreenTransmittance(state, matScreen, relativeAltitude(i, j), relativeAzimuth(i, j), btar);
7578 0 : SumTrans += (btar.BmTrans + btar.DfTrans) * skyArea[i - 1];
7579 0 : SumTransVis += (btar.BmTransVis + btar.DfTransVis) * skyArea[i - 1];
7580 0 : SumReflect += btar.RefSolFront * skyArea[i - 1];
7581 0 : SumReflectVis += btar.RefVisFront * skyArea[i - 1];
7582 0 : SumArea += skyArea[i - 1];
7583 : }
7584 : }
7585 :
7586 : // Reflectance of overall screen including openings and scattered transmittance
7587 0 : matScreen->ShadeRef = matScreen->CylinderRef * (1.0 - (btar.BmTrans + btar.DfTrans));
7588 0 : matScreen->ShadeRefVis = matScreen->CylinderRefVis * (1.0 - (btar.BmTransVis + btar.DfTransVis));
7589 :
7590 0 : if (SumArea != 0) {
7591 0 : matScreen->DfTrans = SumTrans / SumArea;
7592 0 : matScreen->DfTransVis = SumTransVis / SumArea;
7593 0 : matScreen->DfRef = SumReflect / SumArea;
7594 0 : matScreen->DfRefVis = SumReflectVis / SumArea;
7595 : }
7596 0 : matScreen->DfAbs = max(0.0, (1.0 - matScreen->DfTrans - matScreen->DfRef));
7597 :
7598 0 : matScreen->AbsorpThermalBack = matScreen->DfAbs;
7599 0 : matScreen->AbsorpThermalFront = matScreen->DfAbs;
7600 0 : matScreen->ReflectSolBeamFront = matScreen->DfRef;
7601 0 : matScreen->ReflectSolBeamBack = matScreen->DfRef;
7602 :
7603 : // Initialize incident-angle dependent beam matrix (will interpolate from this)
7604 0 : for (int ip = 0; ip < Material::maxIPhi; ++ip) {
7605 0 : Real64 Phi = ip * matScreen->dPhi;
7606 0 : for (int it = 0; it < Material::maxITheta; ++it) {
7607 0 : Real64 Theta = it * matScreen->dTheta;
7608 0 : CalcScreenTransmittance(state, matScreen, Phi, Theta, matScreen->btars[ip][it]);
7609 : }
7610 : }
7611 :
7612 : } // for (SurfNum)
7613 :
7614 : // Write transmittance versus direct normal angle to csv file
7615 :
7616 0 : if (PrintTransMap) {
7617 : // Fortran version did not have error handling in case of file open failure. This one does.
7618 : // Which is correct?
7619 0 : auto screenCsvFile = state.files.screenCsv.open(state, "CalcWindowScreenComponents", state.files.outputControl.screen);
7620 :
7621 : // WRITE(ScreenTransUnitNo,*)' '
7622 0 : for (auto *mat : s_mat->materials) {
7623 :
7624 0 : if (mat->group != Material::Group::Screen) {
7625 0 : continue;
7626 : }
7627 0 : if (!mat->isUsed) {
7628 0 : continue;
7629 : }
7630 :
7631 0 : auto *screen = dynamic_cast<Material::MaterialScreen *>(mat);
7632 0 : assert(screen != nullptr);
7633 :
7634 : // Do not print transmittance map if angle increment is equal to 0
7635 0 : if (screen->mapDegResolution == 0) {
7636 0 : continue;
7637 : }
7638 :
7639 0 : int maxIPrint = int(90 / screen->mapDegResolution);
7640 :
7641 0 : print(screenCsvFile, "MATERIAL:WINDOWSCREEN:{}\n", screen->Name);
7642 0 : print(screenCsvFile,
7643 : "Tabular data for beam solar transmittance at varying \"relative\" azimuth (row) and "
7644 : "altitude (column) angles (deg) [relative to surface normal].\n");
7645 0 : for (int it = maxIPrint; it >= 0; --it) {
7646 0 : print(screenCsvFile, ",{}", it * screen->mapDegResolution);
7647 : }
7648 0 : print(screenCsvFile, "\n");
7649 :
7650 0 : for (int it = 0; it <= maxIPrint; ++it) {
7651 0 : print(screenCsvFile, "{}", it * screen->mapDegResolution);
7652 0 : for (int ip = maxIPrint; ip >= 0; --ip) {
7653 0 : Real64 phi = ip * screen->mapDegResolution * Constant::DegToRad;
7654 0 : Real64 theta = it * screen->mapDegResolution * Constant::DegToRad;
7655 : int ip1, ip2, it1, it2;
7656 : BilinearInterpCoeffs coeffs;
7657 0 : Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2);
7658 0 : GetBilinearInterpCoeffs(
7659 0 : phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs);
7660 0 : Real64 bmTrans = BilinearInterp(screen->btars[ip1][it1].BmTrans,
7661 0 : screen->btars[ip1][it2].BmTrans,
7662 0 : screen->btars[ip2][it1].BmTrans,
7663 0 : screen->btars[ip2][it2].BmTrans,
7664 0 : coeffs);
7665 : // bmTrans = screen->btars[ip][it].BmTrans;
7666 0 : print(screenCsvFile, ",{:.6R}", bmTrans);
7667 : }
7668 0 : print(screenCsvFile, "\n");
7669 : }
7670 0 : print(screenCsvFile, "\n\n");
7671 :
7672 0 : print(screenCsvFile, "MATERIAL:WINDOWSCREEN:{}\n", screen->Name);
7673 0 : print(screenCsvFile,
7674 : "Tabular data for scattered solar transmittance at varying \"relative\" azimuth (row) and "
7675 : "altitude (column) angles (deg) [relative to surface normal].\n");
7676 :
7677 0 : for (int it = 0; it <= maxIPrint; ++it) {
7678 0 : print(screenCsvFile, ",{}", it * screen->mapDegResolution);
7679 : }
7680 0 : print(screenCsvFile, "\n");
7681 :
7682 0 : for (int it = 0; it <= maxIPrint; ++it) {
7683 0 : print(screenCsvFile, "{}", it * screen->mapDegResolution);
7684 0 : for (int ip = 0; ip <= maxIPrint; ++ip) {
7685 0 : Real64 phi = ip * screen->mapDegResolution * Constant::DegToRad;
7686 0 : Real64 theta = it * screen->mapDegResolution * Constant::DegToRad;
7687 : int ip1, ip2, it1, it2;
7688 : BilinearInterpCoeffs coeffs;
7689 0 : Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2);
7690 0 : GetBilinearInterpCoeffs(
7691 0 : phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs);
7692 0 : Real64 dfTrans = BilinearInterp(screen->btars[ip1][it1].DfTrans,
7693 0 : screen->btars[ip1][it2].DfTrans,
7694 0 : screen->btars[ip2][it1].DfTrans,
7695 0 : screen->btars[ip2][it2].DfTrans,
7696 0 : coeffs);
7697 :
7698 : // dfTrans = screen->btars[ip][it].DfTrans;
7699 0 : print(screenCsvFile, ",{:.6R}", dfTrans);
7700 : }
7701 0 : print(screenCsvFile, "\n");
7702 : }
7703 0 : print(screenCsvFile, "\n\n");
7704 : }
7705 0 : } // if (PrintTransMap)
7706 0 : } // CalcWindowScreenProperties()
7707 :
7708 724 : void BlindOpticsDiffuse(EnergyPlusData &state,
7709 : int const BlindNum, // Blind number
7710 : int const ISolVis, // 1 = solar and IR calculation; 2 = visible calculation
7711 : Array1A<Real64> const c, // Slat properties
7712 : Real64 const b_el, // Slat elevation (radians)
7713 : Array1A<Real64> p // Blind properties
7714 : )
7715 : {
7716 :
7717 : // SUBROUTINE INFORMATION:
7718 : // AUTHOR Hans Simmler
7719 : // DATE WRITTEN July-Aug 1995
7720 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
7721 : // Aug 2002 (FCW): make corrections so that calculations are consistent with
7722 : // G(i) = Sum over j of J(j)*F(j,i). Previously, i,j was
7723 : // interchanged in F, so that
7724 : // G(i) = Sum over j of J(j)*F(i,j), which is wrong.
7725 : // This change was made to resolve discrepancies between EnergyPlus results
7726 : // and blind transmittance measurements made at Oklahoma State Univ.
7727 : // Feb 2004 (FCW): modify slat edge correction calc to avoid possible divide by zero
7728 :
7729 : // PURPOSE OF THIS SUBROUTINE:
7730 : // From the slat properties, calculates the diffuse solar, diffuse visible and IR
7731 : // transmission and reflection properties of a window blind.
7732 :
7733 : // REFERENCES:
7734 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
7735 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
7736 :
7737 : // Argument array dimensioning
7738 724 : c.dim(15);
7739 724 : p.dim(16);
7740 :
7741 724 : Array1D<Real64> fEdgeA(2); // Average slat edge correction factor for upper and lower quadrants
7742 : // seen by window blind
7743 724 : Array1D<Real64> j(6); // Slat section radiosity vector
7744 724 : Array1D<Real64> G(6); // Slat section irradiance vector
7745 724 : Array1D<Real64> Q(6); // Slat section radiance vector
7746 724 : Array2D<Real64> F(6, 6); // View factor array
7747 724 : Array2D<Real64> X(4, 4); // Exchange matrix
7748 724 : Array2D<Real64> Xinv(4, 4); // Inverse of exchange matrix
7749 724 : Array1D_int indx(4); // LU decomposition indices
7750 :
7751 : // The slat input properties are:
7752 : // c(1) 0. (unused)
7753 : // c(2) Slat width (m)
7754 : // c(3) Slat separation (m)
7755 : // c(4) 0. (unused)
7756 : // c(5) 0. (unused)
7757 : // c(6) 0. (unused)
7758 : // The following are solar or visible properties
7759 : // c(7) trans beam-diff
7760 : // c(8) refl front beam-diff
7761 : // c(9) refl back beam-diff
7762 : // c(10) trans diff-diff
7763 : // c(11) refl front diff-diff
7764 : // c(12) refl back diff-diff
7765 : // The following are hemispherical thermal IR properties
7766 : // c(13) trans diff-diff
7767 : // c(14) emiss front diff
7768 : // c(15) emiss back diff
7769 :
7770 : // The calculated blind properties are:
7771 : // The following are solar or visible properties
7772 : // p(1) trans front beam-beam
7773 : // p(2) refl front beam-beam
7774 : // p(3) trans back beam-beam
7775 : // p(4) refl back beam-beam
7776 : // p(5) trans front beam-diff
7777 : // p(6) refl front beam-diff
7778 : // p(7) trans back beam-diff
7779 : // p(8) refl back beam-diff
7780 : // p(9) trans front diff-diff
7781 : // p(10) refl front diff-diff
7782 : // p(11) trans back diff-diff
7783 : // p(12) refl back diff-diff
7784 : // The following are IR properties
7785 : // p(13) IR trans front (same as IR trans back)
7786 : // p(14) IR emissivity front
7787 : // p(15) IR emissivity back
7788 : // p(16) 0.0 (unused)
7789 :
7790 724 : auto &s_mat = state.dataMaterial;
7791 724 : auto *matBlind = dynamic_cast<Material::MaterialBlind *>(s_mat->materials(BlindNum));
7792 : // Calculate view factors between slat sections (slat is divided longitudinally into two equal parts)
7793 :
7794 724 : ViewFac(c(2), c(3), b_el, Constant::PiOvr2, F);
7795 :
7796 : // Set up exchange matrix X for diffuse properties
7797 :
7798 2172 : for (int k = 3; k <= 5; k += 2) {
7799 7240 : for (int m = 3; m <= 6; ++m) {
7800 5792 : X(m - 2, k - 2) = -c(12) * F(k, m) - c(10) * F(k + 1, m);
7801 5792 : X(m - 2, k - 1) = -c(10) * F(k, m) - c(11) * F(k + 1, m);
7802 : }
7803 : }
7804 :
7805 3620 : for (int k = 1; k <= 4; ++k) {
7806 2896 : ++X(k, k);
7807 : }
7808 :
7809 724 : indx = 0;
7810 724 : InvertMatrix(state, X, Xinv, indx, 4); // Autodesk:Note X modified by this call
7811 :
7812 : //---------Calculate diffuse short-wave properties for the front side of the blind
7813 :
7814 : // Sources
7815 :
7816 724 : Q(3) = c(12) * F(3, 1) + c(10) * F(4, 1);
7817 724 : Q(4) = c(10) * F(3, 1) + c(11) * F(4, 1);
7818 724 : Q(5) = c(12) * F(5, 1) + c(10) * F(6, 1);
7819 724 : Q(6) = c(10) * F(5, 1) + c(11) * F(6, 1);
7820 :
7821 : // Radiosities
7822 :
7823 724 : j(1) = 1.0;
7824 724 : j(2) = 0.0;
7825 3620 : for (int k = 3; k <= 6; ++k) {
7826 2896 : j(k) = 0.0;
7827 14480 : for (int m = 3; m <= 6; ++m) {
7828 11584 : j(k) += Xinv(m - 2, k - 2) * Q(m);
7829 : }
7830 : }
7831 :
7832 : // Irradiances
7833 5068 : for (int k = 1; k <= 6; ++k) {
7834 4344 : G(k) = 0.0;
7835 30408 : for (int m = 1; m <= 6; ++m) {
7836 : // G(k)=G(k)+F(k,m)*J(m)
7837 26064 : G(k) += j(m) * F(k, m);
7838 : }
7839 : }
7840 :
7841 : // Slat edge correction factor
7842 : std::array<Real64, numPhis> fEdgeSource; // Slat edge correction factor vs source elevation
7843 :
7844 724 : Real64 const phib = b_el; // Elevation of slat normal vector (radians)
7845 724 : Real64 constexpr delphis =
7846 : Constant::PiOvr2 /
7847 : 10.0; // Angle increment for integration over source distribution (radians) // This is a bug, the delta is 10.0, PiOvr2/10.0 is 9.0.
7848 :
7849 2172 : for (int IUpDown = 1; IUpDown <= 2; ++IUpDown) {
7850 15928 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
7851 14480 : Real64 phis = -((double)iPhi + 0.5) * delphis; // Source elevation (radians)
7852 14480 : if (IUpDown == 2) {
7853 7240 : phis = ((double)iPhi + 0.5) * delphis;
7854 : }
7855 14480 : fEdgeSource[iPhi] = 0.0;
7856 14480 : Real64 fEdge1 = 0.0;
7857 14480 : Real64 gamma = phib - phis;
7858 14480 : if (std::abs(std::sin(gamma)) > 0.01) {
7859 14320 : if ((phib > 0.0 && phib <= Constant::PiOvr2 && phis <= phib) ||
7860 7120 : (phib > Constant::PiOvr2 && phib <= Constant::Pi && phis > -(Constant::Pi - phib))) {
7861 10720 : fEdge1 = matBlind->SlatThickness * std::abs(std::sin(gamma)) /
7862 10720 : ((matBlind->SlatSeparation + matBlind->SlatThickness / std::abs(std::sin(phib))) * std::cos(phis));
7863 : }
7864 14320 : fEdgeSource[iPhi] = min(1.0, std::abs(fEdge1));
7865 : }
7866 : }
7867 1448 : fEdgeA(IUpDown) = DiffuseAverage(fEdgeSource);
7868 : }
7869 724 : Real64 fEdge = 0.5 * (fEdgeA(1) + fEdgeA(2)); // Slat edge correction factor
7870 :
7871 : // Front diffuse-diffuse transmittance (transmittance of slat edge assumed zero)
7872 724 : p(9) = G(2) * (1.0 - fEdge);
7873 :
7874 : // Front diffuse-diffuse reflectance (edge of slat is assumed to have same diffuse
7875 : // reflectance as front side of slat, c(11))
7876 724 : p(10) = G(1) * (1.0 - fEdge) + fEdge * c(11);
7877 :
7878 : //-----------Calculate diffuse short-wave properties for the back side of the blind
7879 :
7880 : // Sources
7881 :
7882 724 : Q(3) = c(12) * F(3, 2) + c(10) * F(4, 2);
7883 724 : Q(4) = c(10) * F(3, 2) + c(11) * F(4, 2);
7884 724 : Q(5) = c(12) * F(5, 2) + c(10) * F(6, 2);
7885 724 : Q(6) = c(10) * F(5, 2) + c(11) * F(6, 2);
7886 :
7887 : // Radiosities
7888 :
7889 724 : j(1) = 0.0;
7890 724 : j(2) = 1.0;
7891 3620 : for (int k = 3; k <= 6; ++k) {
7892 2896 : j(k) = 0.0;
7893 14480 : for (int m = 3; m <= 6; ++m) {
7894 11584 : j(k) += Xinv(m - 2, k - 2) * Q(m);
7895 : }
7896 : }
7897 :
7898 : // Irradiances
7899 :
7900 5068 : for (int k = 1; k <= 6; ++k) {
7901 4344 : G(k) = 0.0;
7902 30408 : for (int m = 1; m <= 6; ++m) {
7903 : // G(k)=G(k)+F(k,m)*J(m)
7904 26064 : G(k) += j(m) * F(k, m);
7905 : }
7906 : }
7907 :
7908 : // Back diffuse-diffuse transmittance
7909 724 : p(11) = G(1) * (1.0 - fEdge);
7910 :
7911 : // Back hemi-hemi reflectance
7912 724 : p(12) = G(2) * (1.0 - fEdge) + fEdge * c(11);
7913 :
7914 724 : if (ISolVis == 1) {
7915 :
7916 : //-----------Calculate IR properties of the blind
7917 : // (use same set of view factors as for diffuse short-wave properties)
7918 :
7919 : // Front and back slat IR reflectances
7920 362 : Real64 ri = 1 - c(13) - c(14); // Front and back IR slat reflectance
7921 362 : Real64 rib = 1 - c(13) - c(15);
7922 :
7923 : // Set up exchange matrix X for diffuse properties
7924 :
7925 1086 : for (int k = 3; k <= 5; k += 2) {
7926 3620 : for (int m = 3; m <= 6; ++m) {
7927 2896 : X(m - 2, k - 2) = -rib * F(k, m) - c(13) * F(k + 1, m);
7928 2896 : X(m - 2, k - 1) = -c(13) * F(k, m) - ri * F(k + 1, m);
7929 : }
7930 : }
7931 :
7932 1810 : for (int k = 1; k <= 4; ++k) {
7933 1448 : ++X(k, k);
7934 : }
7935 :
7936 362 : indx = 0;
7937 362 : InvertMatrix(state, X, Xinv, indx, 4); // Autodesk:Note X modified by this call
7938 :
7939 : //---------Calculate diffuse IR properties for the FRONT side of the blind
7940 :
7941 : // Sources
7942 :
7943 362 : Q(3) = rib * F(3, 1) + c(13) * F(4, 1);
7944 362 : Q(4) = c(13) * F(3, 1) + ri * F(4, 1);
7945 362 : Q(5) = rib * F(5, 1) + c(13) * F(6, 1);
7946 362 : Q(6) = c(13) * F(5, 1) + ri * F(6, 1);
7947 :
7948 : // Radiosities
7949 :
7950 362 : j(1) = 1.0;
7951 362 : j(2) = 0.0;
7952 1810 : for (int k = 3; k <= 6; ++k) {
7953 1448 : j(k) = 0.0;
7954 7240 : for (int m = 3; m <= 6; ++m) {
7955 5792 : j(k) += Xinv(m - 2, k - 2) * Q(m);
7956 : }
7957 : }
7958 :
7959 : // Irradiances
7960 2534 : for (int k = 1; k <= 6; ++k) {
7961 2172 : G(k) = 0.0;
7962 15204 : for (int m = 1; m <= 6; ++m) {
7963 : // G(k)=G(k)+F(k,m)*J(m)
7964 13032 : G(k) += j(m) * F(k, m);
7965 : }
7966 : }
7967 :
7968 : // Front diffuse-diffuse IR transmittance (transmittance of slat edge assumed zero)
7969 362 : p(13) = G(2) * (1.0 - fEdge);
7970 :
7971 : // Front diffuse-diffuse IR reflectance (edge of slat is assumed to have same IR
7972 : // reflectance as front side of slat, ri)
7973 362 : Real64 BlindIRreflFront = G(1) * (1.0 - fEdge) + fEdge * ri; // Blind front IR reflectance
7974 :
7975 : // Front IR emissivity
7976 362 : p(14) = max(0.0001, 1.0 - p(13) - BlindIRreflFront);
7977 :
7978 : //-----------Calculate diffuse IR properties for the BACK side of the blind
7979 :
7980 : // Sources
7981 :
7982 362 : Q(3) = rib * F(3, 2) + c(13) * F(4, 2);
7983 362 : Q(4) = c(13) * F(3, 2) + ri * F(4, 2);
7984 362 : Q(5) = rib * F(5, 2) + c(13) * F(6, 2);
7985 362 : Q(6) = c(13) * F(5, 2) + ri * F(6, 2);
7986 :
7987 : // Radiosities
7988 :
7989 362 : j(1) = 0.0;
7990 362 : j(2) = 1.0;
7991 1810 : for (int k = 3; k <= 6; ++k) {
7992 1448 : j(k) = 0.0;
7993 7240 : for (int m = 3; m <= 6; ++m) {
7994 5792 : j(k) += Xinv(m - 2, k - 2) * Q(m);
7995 : }
7996 : }
7997 :
7998 : // Irradiances
7999 :
8000 2534 : for (int k = 1; k <= 6; ++k) {
8001 2172 : G(k) = 0.0;
8002 15204 : for (int m = 1; m <= 6; ++m) {
8003 : // G(k)=G(k)+F(k,m)*J(m)
8004 13032 : G(k) += j(m) * F(k, m);
8005 : }
8006 : }
8007 :
8008 : // Back diffuse-diffuse IR reflectance
8009 362 : Real64 BlindIRreflBack = G(2) * (1.0 - fEdge) + fEdge * ri; // Blind back IR reflectance
8010 :
8011 : // Back IR emissivity
8012 362 : p(15) = max(0.0001, 1.0 - p(13) - BlindIRreflBack);
8013 :
8014 : } // End of IR properties calculation
8015 724 : } // BlindOpticsDiffuse()
8016 :
8017 : //**********************************************************************************************
8018 :
8019 26788 : void BlindOpticsBeam(EnergyPlusData &state,
8020 : int const BlindNum, // Blind number
8021 : Array1A<Real64> const c, // Slat properties (equivalent to BLD_PR)
8022 : Real64 const b_el, // Slat elevation (radians)
8023 : Real64 const s_el, // Solar profile angle (radians)
8024 : Array1A<Real64> p // Blind properties (equivalent to ST_LAY)
8025 : )
8026 : {
8027 :
8028 : // SUBROUTINE INFORMATION:
8029 : // AUTHOR Hans Simmler
8030 : // DATE WRITTEN July-Aug 1995
8031 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
8032 : // Aug 2002 (FCW): make corrections so that calculations are consistent with
8033 : // G(i) = Sum over j of J(j)*F(j,i). Previously, i,j was
8034 : // interchanged in F, so that
8035 : // G(i) = Sum over j of J(j)*F(i,j), which is wrong.
8036 : // This change was made to resolve discrepancies between EnergyPlus results
8037 : // and blind transmittance measurements made at Oklahoma State Univ.
8038 :
8039 : // PURPOSE OF THIS SUBROUTINE:
8040 : // Calculates the beam radiation properties of a
8041 : // window blind consisting of flat slats with known material properties.
8042 : // The calculation for the reverse direction is done with the radiation source
8043 : // reflected at the window plane.
8044 :
8045 : // REFERENCES:
8046 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
8047 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
8048 :
8049 : // Argument array dimensioning
8050 26788 : c.dim(15);
8051 26788 : p.dim(16);
8052 :
8053 : struct BlindInputs
8054 : {
8055 : Real64 slatWidth;
8056 : Real64 slatSeparation;
8057 : Real64 BmDfTrans;
8058 : Real64 BmDfRefFront;
8059 : Real64 BmDfRefBack;
8060 : Real64 DfDfTrans;
8061 : Real64 DfDfRefFront;
8062 : Real64 DfDfRefBack;
8063 : Real64 DfDfTransIR;
8064 : Real64 DfEmissFront;
8065 : Real64 DfEmissBack;
8066 : };
8067 :
8068 : // The slat input properties are:
8069 : // c(1) 0. (unused)
8070 : // c(2) Slat width (m)
8071 : // c(3) Slat separation (m)
8072 : // c(4) 0. (unused)
8073 : // c(5) 0. (unused)
8074 : // c(6) 0. (unused)
8075 : // The following are solar or visible properties
8076 : // c(7) trans beam-diff
8077 : // c(8) refl front beam-diff
8078 : // c(9) refl back beam-diff
8079 : // c(10) trans diff-diff
8080 : // c(11) refl front diff-diff
8081 : // c(12) refl back diff-diff
8082 : // The following are hemispherical thermal IR properties
8083 : // c(13) trans diff-diff
8084 : // c(14) emiss front diff
8085 : // c(15) emiss back diff
8086 :
8087 : struct BlindOutputs
8088 : {
8089 : Real64 BmBmTransFront;
8090 : Real64 BmBmRefFront;
8091 : Real64 BmBmTransBack;
8092 : Real64 BmBmRefBack;
8093 : Real64 BmDfTransFront;
8094 : Real64 BmDfRefFront;
8095 : Real64 BmDfTransBack;
8096 : Real64 BmDfRefBack;
8097 : Real64 DfDfTransFront;
8098 : Real64 DfDfRefFront;
8099 : Real64 DfDfTransBack;
8100 : Real64 DfDfRefBack;
8101 :
8102 : Real64 TransFrontIR;
8103 : Real64 TransBackIR;
8104 : Real64 EmissFrontIR;
8105 : Real64 EmissBackIR;
8106 : };
8107 :
8108 : // The calculated blind properties are:
8109 : // The following are solar or visible properties
8110 : // p(1) trans front beam-beam
8111 : // p(2) refl front beam-beam
8112 : // p(3) trans back beam-beam
8113 : // p(4) refl back beam-beam
8114 : // p(5) trans front beam-diff
8115 : // p(6) refl front beam-diff
8116 : // p(7) trans back beam-diff
8117 : // p(8) refl back beam-diff
8118 : // p(9) trans front diff-diff
8119 : // p(10) refl front diff-diff
8120 : // p(11) trans back diff-diff
8121 : // p(12) refl back diff-diff
8122 : // The following are IR properties
8123 : // p(13) IR trans front (same as IR trans back)
8124 : // p(14) IR emissivity front
8125 : // p(15) IR emissivity back
8126 : // p(16) 0.0 (unused)
8127 :
8128 : Real64 phib; // Elevation angle of normal vector to front of slat (0 to pi radians)
8129 : Real64 phis; // Elevation angle of source vector; same as "profile angle" (-pi/2 to pi/2 radians)
8130 : Real64 gamma; // phib - phis (radians)
8131 26788 : Array1D<Real64> j(6); // Slat surface section radiosity vector
8132 26788 : Array1D<Real64> G(6); // Slat surface section irradiance vector
8133 26788 : Array1D<Real64> Q(6); // Slat surface section source vector
8134 26788 : Array2D<Real64> F(6, 6); // View factor array
8135 26788 : Array2D<Real64> X(4, 4); // X*J = Q
8136 26788 : Array2D<Real64> Xinv(4, 4); // J = Xinv*Q
8137 : Real64 fEdge; // Slat edge correction factor
8138 : Real64 fEdge1;
8139 26788 : Array1D_int indx(4); // Indices for LU decomposition
8140 :
8141 26788 : auto &s_mat = state.dataMaterial;
8142 26788 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlindNum));
8143 :
8144 26788 : p = 0.0;
8145 :
8146 : // Elevation of radiation source; source is assumed to be in a plane that
8147 : // (1) contains the slat outward normal and (2) is perpendicular to plane of the blinds.
8148 26788 : phis = s_el;
8149 :
8150 : // Elevation of slat outward normal
8151 26788 : phib = b_el;
8152 :
8153 : // Loop twice for front and back side properties of blind
8154 80364 : for (int i = 0; i <= 2; i += 2) {
8155 :
8156 : // For back-side properties, reflect the source position so that it is the mirror
8157 : // image of the original source position, where the "mirror" is in the plane of the
8158 : // blinds. This is equivalent to keeping the original source position but rotating
8159 : // the slats so that the original slat angle (e.g., 45 deg) becomes 180 - original slat
8160 : // angle (135 deg).
8161 :
8162 53576 : if (i == 2) {
8163 26788 : phib = Constant::Pi - phib;
8164 : }
8165 :
8166 : // Correction factor that accounts for finite thickness of slats. It is used to modify the
8167 : // blind transmittance and reflectance to account for reflection and absorption by the
8168 : // edge of the slat. fEdge is ratio of area subtended by edge of slat
8169 : // to area between tops of adjacent slats.
8170 :
8171 53576 : fEdge = 0.0;
8172 53576 : fEdge1 = 0.0;
8173 53576 : gamma = phib - phis;
8174 53576 : if (std::abs(std::sin(gamma)) > 0.01) {
8175 53272 : if ((phib > 0.0 && phib <= Constant::PiOvr2 && phis <= phib) ||
8176 26496 : (phib > Constant::PiOvr2 && phib <= Constant::Pi && phis > -(Constant::Pi - phib))) {
8177 39448 : fEdge1 = matBlind->SlatThickness * std::abs(std::sin(gamma)) /
8178 39448 : ((matBlind->SlatSeparation + matBlind->SlatThickness / std::abs(std::sin(phib))) * std::cos(phis));
8179 : }
8180 53272 : fEdge = min(1.0, std::abs(fEdge1));
8181 : }
8182 :
8183 : // Direct-to-direct transmittance (portion of beam that passes between slats without
8184 : // without touching them
8185 :
8186 53576 : p(1 + i) = matBlind->BeamBeamTrans(phis, phib);
8187 : // Direct-to-direct reflectance; this is zero for now since all reflection is assumed to be diffuse.
8188 53576 : p(2 + i) = 0.0;
8189 :
8190 : // View factors between slat sections for calculating direct-to-diffuse transmittance and reflectance
8191 53576 : ViewFac(c(2), c(3), phib, phis, F);
8192 :
8193 : // Set up exchange matrix X for calculating direct-to-diffuse properties
8194 :
8195 160728 : for (int k = 3; k <= 5; k += 2) {
8196 535760 : for (int m = 3; m <= 6; ++m) {
8197 428608 : X(m - 2, k - 2) = -c(12) * F(k, m) - c(10) * F(k + 1, m);
8198 428608 : X(m - 2, k - 1) = -c(10) * F(k, m) - c(11) * F(k + 1, m);
8199 : }
8200 : }
8201 :
8202 267880 : for (int k = 1; k <= 4; ++k) {
8203 214304 : ++X(k, k);
8204 : }
8205 :
8206 53576 : indx = 0;
8207 : // In the following, note that InvertMatrix changes X
8208 53576 : InvertMatrix(state, X, Xinv, indx, 4);
8209 :
8210 : // Set up sources for direct-diffuse slat properties
8211 53576 : if (std::abs(phis - phib) <= Constant::PiOvr2) { // Beam hits front of slat
8212 26892 : Q(3) = c(4) + c(7); // beam-beam trans of slat + beam-diff trans of slat
8213 26892 : Q(4) = c(5) + c(8); // front beam-beam refl of slat + front beam-diff refl of slat
8214 : } else { // Beam hits back of slat
8215 26684 : Q(3) = c(6) + c(9); // back beam-beam refl of slat + back beam-diff refl of slat
8216 26684 : Q(4) = c(4) + c(7); // beam-beam trans of slat + beam-diff trans of slat
8217 : }
8218 :
8219 : // Correct for fraction of beam that is not directly transmitted; 1 - this fraction is
8220 : // the fraction of the incoming beam that is incident on the front or back surfaces of the slats.
8221 53576 : Q(3) *= (1.0 - p(1 + i));
8222 53576 : Q(4) *= (1.0 - p(1 + i));
8223 :
8224 : // Radiosities (radiance of slat sections)
8225 53576 : j(1) = 0.0;
8226 53576 : j(2) = 0.0;
8227 267880 : for (int k = 3; k <= 6; ++k) {
8228 214304 : j(k) = 0.0;
8229 642912 : for (int m = 3; m <= 4; ++m) {
8230 428608 : j(k) += Xinv(m - 2, k - 2) * Q(m);
8231 : }
8232 : }
8233 :
8234 : // Irradiance on slat sections
8235 375032 : for (int k = 1; k <= 6; ++k) {
8236 321456 : G(k) = 0.0;
8237 1607280 : for (int m = 3; m <= 6; ++m) {
8238 1285824 : G(k) += j(m) * F(k, m);
8239 : }
8240 : }
8241 :
8242 : // Direct-to-diffuse transmittance
8243 53576 : p(5 + i) = G(2) * (1.0 - fEdge);
8244 :
8245 : // Direct-to-diffuse reflectance (assuming the edge reflectance is the same as the
8246 : // reflectance of the front side of the slat, C(8))
8247 53576 : p(6 + i) = G(1) * (1.0 - fEdge) + fEdge * c(8);
8248 :
8249 : } // End of loop over front and back side properties of blind
8250 26788 : } // BlindOpticsBeam()
8251 :
8252 : //********************************************************************************************
8253 :
8254 54300 : void ViewFac(Real64 const s, // Slat width (m)
8255 : Real64 const h, // Distance between faces of adjacent slats (m)
8256 : Real64 const phib, // Elevation angle of normal to slat (radians)
8257 : Real64 const phis, // Profile angle of radiation source (radians)
8258 : Array2A<Real64> F // View factor array
8259 : )
8260 : {
8261 :
8262 : // SUBROUTINE INFORMATION:
8263 : // AUTHOR Hans Simmler
8264 : // DATE WRITTEN July-Aug 1995
8265 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
8266 : // Apr 2002 (FCW): prevent sqrt of small negative argument
8267 :
8268 : // PURPOSE OF THIS SUBROUTINE:
8269 : // Calculates the view factors between sections of adjacent slats,
8270 : // where each slat is divided longitudinally into two equal sections whose
8271 : // dimensions depend on source profile angle and slat geometry. The view
8272 : // factors are used in BlindOpticsBeam and BlindOpticsDiffuse to determine blind
8273 : // transmittance and reflectance for short-wave and long-wave radiation.
8274 :
8275 : // METHODOLOGY EMPLOYED:
8276 : // Uses expressions for view factor between flat strips with a common edge
8277 : // and flat strips displaced from one another. See engineering documentation.
8278 :
8279 : // REFERENCES:
8280 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
8281 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
8282 :
8283 : // Argument array dimensioning
8284 54300 : F.dim(6, 6);
8285 :
8286 54300 : Array1D<Real64> L(6); // Length of slat sections: L1 = L2 = h; L3, L5 = length
8287 :
8288 54300 : Real64 h2 = pow_2(h);
8289 54300 : Real64 ht = 2.0 * h;
8290 54300 : Real64 co = std::cos(phis); // Cosine of source profile angle
8291 54300 : if (std::abs(co) < 0.001) {
8292 3620 : co = 0.0;
8293 : }
8294 54300 : Real64 w = ht; // Slat geometry variable (m)
8295 54300 : if (co != 0.0) {
8296 50680 : w = s * std::cos(phib - phis) / co;
8297 : }
8298 54300 : Real64 L3 = s * h / std::abs(w);
8299 54300 : if (L3 > s) {
8300 17016 : L3 = s;
8301 : }
8302 54300 : Real64 L5 = s - L3;
8303 54300 : Real64 a = ht * std::cos(phib); // Intermediate variable (m)
8304 : // MAX(0.,...) in the following prevents small negative argument for sqrt
8305 54300 : Real64 d1 = std::sqrt(max(0.0, s * s + h2 + a * s)); // Slat geometry variables (m)
8306 54300 : Real64 d2 = std::sqrt(max(0.0, s * s + h2 - a * s));
8307 54300 : Real64 d3 = std::sqrt(max(0.0, L3 * L3 + h2 + a * L3));
8308 54300 : Real64 d4 = std::sqrt(max(0.0, L3 * L3 + h2 - a * L3));
8309 54300 : Real64 d5 = std::sqrt(max(0.0, L5 * L5 + h2 - a * L5));
8310 54300 : Real64 d6 = std::sqrt(max(0.0, L5 * L5 + h2 + a * L5));
8311 380100 : for (int i = 1; i <= 6; ++i) {
8312 325800 : F(i, i) = 0.0;
8313 : }
8314 54300 : F(1, 1) = 0.0;
8315 54300 : F(2, 1) = (d1 + d2 - 2.0 * s) / ht;
8316 54300 : F(3, 1) = (h + L3 - d3) / ht;
8317 54300 : F(4, 1) = (h + L3 - d4) / ht;
8318 54300 : F(5, 1) = (L5 + d3 - d1) / ht;
8319 54300 : F(6, 1) = (L5 + d4 - d2) / ht;
8320 54300 : F(3, 2) = (L3 + d5 - d2) / ht;
8321 54300 : F(4, 2) = (L3 + d6 - d1) / ht;
8322 54300 : F(5, 2) = (h + L5 - d5) / ht;
8323 54300 : F(6, 2) = (h + L5 - d6) / ht;
8324 54300 : F(4, 3) = (d3 + d4 - ht) / (2.0 * L3);
8325 54300 : F(5, 3) = 0.0;
8326 54300 : F(6, 3) = (d2 + h - d4 - d5) / (2.0 * L3);
8327 54300 : F(5, 4) = (d1 + h - d3 - d6) / (2.0 * L3);
8328 54300 : F(6, 4) = 0.0;
8329 54300 : F(6, 5) = 0.0;
8330 54300 : if (L5 > 0.0) {
8331 37284 : F(6, 5) = (d5 + d6 - ht) / (2.0 * L5);
8332 : }
8333 54300 : L(1) = h;
8334 54300 : L(2) = h;
8335 54300 : L(3) = L3;
8336 54300 : L(4) = L3; // L4, L6 = length of lower slat
8337 54300 : L(5) = L5;
8338 54300 : L(6) = L5;
8339 325800 : for (int i = 2; i <= 6; ++i) {
8340 1086000 : for (int j = 1; j <= i - 1; ++j) {
8341 814500 : F(j, i) = 0.0;
8342 814500 : if (L(i) > 0.0) {
8343 661356 : F(j, i) = F(i, j) * L(j) / L(i);
8344 : }
8345 : }
8346 : }
8347 54300 : } // ViewFac()
8348 :
8349 : //*****************************************************************************************
8350 :
8351 54662 : void InvertMatrix(EnergyPlusData &state,
8352 : Array2D<Real64> &a, // Matrix to be inverted
8353 : Array2D<Real64> &y, // Inverse of matrix a
8354 : Array1D_int &indx, // Index vector for LU decomposition
8355 : int const n)
8356 : {
8357 :
8358 : // SUBROUTINE INFORMATION:
8359 : // AUTHOR Hans Simmler
8360 : // DATE WRITTEN July-Aug 1995
8361 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
8362 :
8363 : // PURPOSE OF THIS SUBROUTINE:
8364 : // Inverts a matrix.
8365 :
8366 : // METHODOLOGY EMPLOYED:
8367 : // Uses LU decomposition.
8368 :
8369 54662 : Array1D<Real64> tmp(n);
8370 :
8371 : int d;
8372 :
8373 54662 : y = 0.0;
8374 273310 : for (int i = 1; i <= n; ++i) {
8375 218648 : y(i, i) = 1.0;
8376 : }
8377 54662 : indx = 0;
8378 :
8379 54662 : LUdecomposition(state, a, n, indx, d);
8380 :
8381 273310 : for (int j = 1; j <= n; ++j) {
8382 218648 : tmp = 0.0;
8383 218648 : tmp(j) = 1;
8384 218648 : LUsolution(state, a, n, indx, tmp);
8385 1093240 : for (int i = 1; i <= n; ++i) {
8386 874592 : y(j, i) = tmp(i);
8387 : }
8388 : }
8389 54662 : } // InvertMatrix()
8390 :
8391 : // added for custom solar or visible spectrum
8392 :
8393 111 : void CheckAndReadCustomSprectrumData(EnergyPlusData &state)
8394 : {
8395 :
8396 : // SUBROUTINE INFORMATION:
8397 : // AUTHOR T. Hong
8398 : // DATE WRITTEN August 2013
8399 :
8400 : // PURPOSE OF THIS SUBROUTINE:
8401 : // Check, read, and assign the custom solar or visible spectrum to:
8402 : // solar: nume, wle(nume), e(nume). nume = 107
8403 : // visible: numt3, wlt3(numt3), y30(numt3). numt3 = 81
8404 : // Three related IDD objects:
8405 : // EnergyManagementSystem:ConstructionIndexVariable
8406 : // Site:SolarAndVisibleSpectrum, Site:SpectrumData
8407 :
8408 : // METHODOLOGY EMPLOYED:
8409 : // Overwriting the default values
8410 :
8411 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8412 111 : bool ErrorsFound(false); // If errors detected in input
8413 : int NumAlphas; // Number of Alphas for each GetobjectItem call
8414 : int NumNumbers; // Number of Numbers for each GetobjectItem call
8415 : int NumArgs;
8416 111 : Array1D_string cAlphaArgs; // Alpha input items for object
8417 111 : Array1D<Real64> rNumericArgs; // Numeric input items for object
8418 :
8419 111 : auto const &wm = state.dataWindowManager;
8420 :
8421 111 : if (wm->RunMeOnceFlag) {
8422 0 : return;
8423 : }
8424 :
8425 : // Step 1 - check whether there is custom solar or visible spectrum
8426 111 : std::string cCurrentModuleObject = "Site:SolarAndVisibleSpectrum";
8427 111 : int NumSiteSpectrum = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8428 :
8429 : // no custom spectrum data, done!
8430 111 : if (NumSiteSpectrum == 0) {
8431 111 : wm->RunMeOnceFlag = true;
8432 111 : return;
8433 : }
8434 :
8435 : // read custom spectrum data from Site:SolarAndVisibleSpectrum
8436 0 : if (NumSiteSpectrum > 1) { // throw error
8437 0 : ShowSevereError(state, format("Only one {} object is allowed", cCurrentModuleObject));
8438 0 : ErrorsFound = true;
8439 : }
8440 :
8441 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
8442 0 : cAlphaArgs.allocate(NumAlphas);
8443 0 : rNumericArgs.dimension(NumNumbers, 0.0);
8444 :
8445 0 : if (NumSiteSpectrum == 1) {
8446 : int IOStatus;
8447 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8448 : cCurrentModuleObject,
8449 : 1,
8450 0 : state.dataIPShortCut->cAlphaArgs,
8451 : NumAlphas,
8452 0 : state.dataIPShortCut->rNumericArgs,
8453 : NumNumbers,
8454 : IOStatus);
8455 :
8456 : // use default spectrum data, done!
8457 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "Default")) {
8458 0 : wm->RunMeOnceFlag = true;
8459 0 : return;
8460 : }
8461 :
8462 : // now read custom solar and visible spectrum data
8463 0 : std::string cSolarSpectrum = state.dataIPShortCut->cAlphaArgs(3);
8464 0 : std::string cVisibleSpectrum = state.dataIPShortCut->cAlphaArgs(4);
8465 :
8466 0 : cCurrentModuleObject = "Site:SpectrumData";
8467 0 : NumSiteSpectrum = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8468 0 : if (NumSiteSpectrum == 0) { // throw error
8469 0 : ShowSevereError(state, format("No {} object is found", cCurrentModuleObject));
8470 0 : ErrorsFound = true;
8471 : }
8472 :
8473 0 : cAlphaArgs.deallocate();
8474 0 : rNumericArgs.deallocate();
8475 :
8476 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
8477 0 : cAlphaArgs.allocate(NumAlphas);
8478 0 : rNumericArgs.dimension(NumNumbers, 0.0);
8479 :
8480 0 : int iSolarSpectrum = 0;
8481 0 : int iVisibleSpectrum = 0;
8482 0 : for (int Loop = 1; Loop <= NumSiteSpectrum; ++Loop) {
8483 : // Step 2 - read user-defined spectrum data
8484 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8485 : cCurrentModuleObject,
8486 : Loop,
8487 0 : state.dataIPShortCut->cAlphaArgs,
8488 : NumAlphas,
8489 0 : state.dataIPShortCut->rNumericArgs,
8490 : NumNumbers,
8491 : IOStatus);
8492 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), cSolarSpectrum)) {
8493 0 : iSolarSpectrum = Loop;
8494 : // overwrite the default solar spectrum
8495 0 : if (NumNumbers > 2 * nume) {
8496 0 : ShowSevereError(
8497 : state,
8498 0 : format("Solar spectrum data pair is more than 107 - {} - {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
8499 0 : ErrorsFound = true;
8500 : } else {
8501 : // Step 3 - overwrite default solar spectrum data
8502 0 : for (int iTmp = 1; iTmp <= nume; ++iTmp) {
8503 0 : if (iTmp <= NumNumbers / 2) {
8504 0 : wm->wle[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp - 1);
8505 0 : wm->e[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp);
8506 : } else {
8507 0 : wm->wle[iTmp - 1] = 0.0;
8508 0 : wm->e[iTmp - 1] = 0.0;
8509 : }
8510 : }
8511 : }
8512 : }
8513 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), cVisibleSpectrum)) {
8514 0 : iVisibleSpectrum = Loop;
8515 : // overwrite the default solar spectrum
8516 0 : if (NumNumbers > 2 * numt3) {
8517 0 : ShowSevereError(state,
8518 0 : format("Visible spectrum data pair is more than 81 - {} - {}",
8519 : cCurrentModuleObject,
8520 0 : state.dataIPShortCut->cAlphaArgs(1)));
8521 0 : ErrorsFound = true;
8522 : } else {
8523 : // Step 3 - overwrite default visible spectrum data
8524 0 : for (int iTmp = 1; iTmp <= numt3; ++iTmp) {
8525 0 : if (iTmp <= NumNumbers / 2) {
8526 0 : wm->wlt3[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp - 1);
8527 0 : wm->y30[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp);
8528 : } else {
8529 0 : wm->wlt3[iTmp - 1] = 0.0;
8530 0 : wm->y30[iTmp - 1] = 0.0;
8531 : }
8532 : }
8533 : }
8534 : }
8535 0 : if ((iSolarSpectrum > 0) && (iVisibleSpectrum > 0)) {
8536 0 : break;
8537 : }
8538 : }
8539 0 : }
8540 :
8541 0 : cAlphaArgs.deallocate();
8542 0 : rNumericArgs.deallocate();
8543 :
8544 0 : if (ErrorsFound) {
8545 0 : ShowFatalError(state, "Errors found in processing input for user-defined solar/visible spectrum");
8546 : }
8547 :
8548 0 : wm->RunMeOnceFlag = true;
8549 333 : } // CheckAndReadCustomSpectrumData()
8550 :
8551 : //*****************************************************************************************
8552 :
8553 211 : void initWindowModel(EnergyPlusData &state)
8554 : {
8555 211 : const std::string objectName = "WindowsCalculationEngine";
8556 211 : auto const &wm = state.dataWindowManager;
8557 211 : wm->inExtWindowModel = CWindowModel::WindowModelFactory(state, objectName);
8558 211 : wm->winOpticalModel = CWindowOpticalModel::WindowOpticalModelFactory(state);
8559 211 : } // InitWindowModel()
8560 :
8561 : //*****************************************************************************************
8562 :
8563 : } // namespace Window
8564 :
8565 : } // namespace EnergyPlus
|