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) CalcWindowBlindProperties(state);
342 :
343 : // Initialize SurfaceScreen structure
344 110 : if (s_mat->NumScreens > 0) CalcWindowScreenProperties(state);
345 :
346 : // Get glazing system optical properties of constructions with glass or glass plus
347 : // shade, screen or blind
348 : // Loop over constructions and find those that are glazing constructions
349 433 : for (int ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
350 323 : auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
351 330 : if (!thisConstruct.TypeIsWindow) continue;
352 42 : if (thisConstruct.WindowTypeBSDF) continue; // Skip Complex Fenestrations, they have separate
353 41 : if (thisConstruct.WindowTypeEQL) continue; // skip Equivalent Layer Fenestration
354 : // handling of optical properties
355 :
356 : // When pulling in develop, the following block appears to have been modified in develop,
357 : // but removed entirely in this branch. I'm going to leave it commented.
358 : // Pre-calculate constants
359 : // for (int IPhi = 1; IPhi <= 10; ++IPhi) {
360 : // CosPhiIndepVar(IPhi) = std::cos((IPhi - 1) * 10.0 * Constant::DegToRad);
361 : //}
362 :
363 35 : TotLay = thisConstruct.TotLayers;
364 :
365 35 : auto const *mat = s_mat->materials(thisConstruct.LayerPoint(1));
366 :
367 : // First layer must be glass, shade, screen or blind to be a glazing construction
368 35 : if (mat->group != Material::Group::Glass && mat->group != Material::Group::Shade && mat->group != Material::Group::Screen &&
369 12 : mat->group != Material::Group::Blind && mat->group != Material::Group::GlassSimple)
370 0 : continue;
371 :
372 35 : ShadeLayNum = 0;
373 35 : ExtShade = false;
374 35 : IntShade = false;
375 35 : BGShade = false;
376 35 : ExtBlind = false;
377 35 : IntBlind = false;
378 35 : BGBlind = false;
379 35 : ExtScreen = false;
380 35 : StormWinConst = false;
381 35 : wm->lSimpleGlazingSystem = false;
382 :
383 35 : if (mat->group == Material::Group::GlassSimple) {
384 12 : auto const *matWin = dynamic_cast<Material::MaterialGlass const *>(mat);
385 12 : assert(matWin != nullptr);
386 :
387 : // what if outside layer is shade, blind, or screen?
388 12 : wm->lSimpleGlazingSystem = true;
389 12 : wm->SimpleGlazingSHGC = matWin->SimpleWindowSHGC;
390 12 : wm->SimpleGlazingU = matWin->SimpleWindowUfactor;
391 : }
392 :
393 35 : if (has_prefix(thisConstruct.Name, "BARECONSTRUCTIONWITHSTORMWIN") || has_prefix(thisConstruct.Name, "SHADEDCONSTRUCTIONWITHSTORMWIN"))
394 0 : StormWinConst = true;
395 :
396 : // Get layer number of shade/blind
397 35 : if (mat->group == Material::Group::Shade) {
398 0 : ExtShade = true;
399 0 : ShadeLayNum = 1;
400 35 : } else if (s_mat->materials(thisConstruct.LayerPoint(TotLay))->group == Material::Group::Shade) {
401 0 : IntShade = true;
402 0 : ShadeLayNum = TotLay;
403 35 : } else if (thisConstruct.TotLayers == 5) {
404 0 : if (s_mat->materials(thisConstruct.LayerPoint(3))->group == Material::Group::Shade) {
405 0 : BGShade = true;
406 0 : ShadeLayNum = 3;
407 : }
408 35 : } else if (thisConstruct.TotLayers == 7) {
409 0 : if (s_mat->materials(thisConstruct.LayerPoint(5))->group == Material::Group::Shade) {
410 0 : BGShade = true;
411 0 : ShadeLayNum = 5;
412 : }
413 : }
414 :
415 35 : if (mat->group == Material::Group::Blind) {
416 0 : ExtBlind = true;
417 0 : ShadeLayNum = 1;
418 0 : BlNum = thisConstruct.LayerPoint(ShadeLayNum);
419 35 : } else if (s_mat->materials(thisConstruct.LayerPoint(TotLay))->group == Material::Group::Blind) {
420 1 : IntBlind = true;
421 1 : ShadeLayNum = TotLay;
422 1 : BlNum = thisConstruct.LayerPoint(ShadeLayNum);
423 34 : } else if (thisConstruct.TotLayers == 5) {
424 0 : if (s_mat->materials(thisConstruct.LayerPoint(3))->group == Material::Group::Blind) {
425 0 : BGBlind = true;
426 0 : ShadeLayNum = 3;
427 0 : BlNum = thisConstruct.LayerPoint(ShadeLayNum);
428 : }
429 34 : } else if (thisConstruct.TotLayers == 7) {
430 0 : if (s_mat->materials(thisConstruct.LayerPoint(5))->group == Material::Group::Blind) {
431 0 : BGBlind = true;
432 0 : ShadeLayNum = 5;
433 0 : BlNum = thisConstruct.LayerPoint(ShadeLayNum);
434 : }
435 : }
436 :
437 35 : if (mat->group == Material::Group::Screen) {
438 0 : ShadeLayNum = 1;
439 0 : ExtScreen = true;
440 : }
441 :
442 35 : ScreenOn = ExtScreen;
443 35 : BlindOn = IntBlind || ExtBlind || BGBlind;
444 35 : ShadeOn = IntShade || ExtShade || BGShade;
445 35 : wm->BGFlag = BGBlind || BGShade;
446 :
447 : // For construction with interior or exterior shade, get shade thermal absorptance (emissivity)
448 : // (accounting for inter-reflection with glazing) and correct the inside glass InsideAbsorpThermal
449 : // for presence of interior shade. Assumes inner and outer glass layers have zero thermal transmittance.
450 :
451 35 : if (IntShade || ExtShade || ExtScreen) {
452 0 : ShadeLayPtr = thisConstruct.LayerPoint(ShadeLayNum);
453 0 : auto const *matShade = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(ShadeLayPtr));
454 0 : assert(matShade != nullptr);
455 0 : if (ExtScreen) {
456 0 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(matShade);
457 0 : assert(matScreen != nullptr);
458 0 : TauShIR = matScreen->DfTrans;
459 : } else {
460 0 : TauShIR = matShade->TransThermal;
461 : }
462 0 : EpsShIR = matShade->AbsorpThermal;
463 0 : RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
464 0 : if (ExtShade || ExtScreen) { // Exterior shade or screen
465 0 : EpsGlIR = s_mat->materials(thisConstruct.LayerPoint(2))->AbsorpThermalFront;
466 : } else { // Interior shade
467 0 : EpsGlIR = s_mat->materials(thisConstruct.LayerPoint(TotLay - 1))->AbsorpThermalBack;
468 : }
469 0 : RhoGlIR = max(0.0, 1.0 - EpsGlIR);
470 0 : thisConstruct.ShadeAbsorpThermal = EpsShIR * (1.0 + TauShIR * RhoGlIR / (1.0 - RhoShIR * RhoGlIR));
471 0 : if (IntShade) thisConstruct.InsideAbsorpThermal *= TauShIR / (1.0 - RhoShIR * RhoGlIR);
472 : }
473 :
474 : // From the individual glass layer properties, get the glazing system optical properties
475 : // for BARE GLASS (i.e., interior, exterior or between-glass shade or blind, or exterior screen, if present, not in place).
476 : // Get one set of system properties for solar incident on front of
477 : // window and a second set for solar incident on back of window. (The back-incident
478 : // properties are used with interior short-wave radiation striking the window from inside.)
479 :
480 : // After the front and back system optical properties are calculated for bare glass,
481 : // a correction is made for the effect of a shade, screen or blind if one of these
482 : // is present in the construction.
483 :
484 35 : NGlass = thisConstruct.TotGlassLayers;
485 :
486 : //--------------------------------------------------------------------------------------------
487 : // Front calculation (solar incident from outside of room); bare glass portion of construction
488 : //--------------------------------------------------------------------------------------------
489 :
490 35 : lquasi = false;
491 35 : AllGlassIsSpectralAverage = true;
492 35 : wm->LayerNum = {0};
493 :
494 : // Loop over glass layers in the construction
495 80 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
496 45 : int LayNum = 1 + 2 * (IGlass - 1);
497 45 : if (ExtShade || ExtBlind || ExtScreen) LayNum = 2 + 2 * (IGlass - 1);
498 45 : if (BGShade || BGBlind) {
499 0 : LayNum = 1;
500 0 : if (NGlass == 2) {
501 0 : if (IGlass == 2) LayNum = 5;
502 : } else { // NGlass = 3
503 0 : if (IGlass == 2) LayNum = 3;
504 0 : if (IGlass == 3) LayNum = 7;
505 : }
506 : }
507 :
508 45 : wm->LayerNum[IGlass - 1] = LayNum;
509 45 : LayPtr = thisConstruct.LayerPoint(LayNum);
510 45 : auto *matGlass = dynamic_cast<Material::MaterialGlass *>(s_mat->materials(LayPtr));
511 45 : assert(matGlass != nullptr);
512 45 : SpecDataNum = matGlass->GlassSpectralDataPtr;
513 45 : if (SpecDataNum != 0) {
514 4 : if (!wm->BGFlag) AllGlassIsSpectralAverage = false;
515 :
516 4 : auto const &specData = s_mat->SpectralData(SpecDataNum);
517 : // Get the spectral data for the transmittance, front reflectance and
518 : // back reflectance (all at normal incidence) for this layer.
519 : // In this case, "front" means incident from the outside and "back"
520 : // means incident from the inside.
521 4 : numptDAT = specData.NumOfWavelengths;
522 4 : numpt[IGlass - 1] = numptDAT;
523 :
524 1072 : for (int ILam = 1; ILam <= numptDAT; ++ILam) {
525 1068 : wlt[IGlass - 1][ILam - 1] = specData.WaveLength(ILam);
526 1068 : t[IGlass - 1][ILam - 1] = specData.Trans(ILam);
527 1068 : if ((IGlass == 1 || (IGlass == 2 && StormWinConst)) && (!wm->BGFlag))
528 441 : t[IGlass - 1][ILam - 1] *= matGlass->GlassTransDirtFactor;
529 1068 : rff[IGlass - 1][ILam - 1] = specData.ReflFront(ILam);
530 1068 : rbb[IGlass - 1][ILam - 1] = specData.ReflBack(ILam);
531 : }
532 :
533 : // If there is spectral data for between-glass shades or blinds, calc the average spectral properties for use.
534 4 : if (wm->BGFlag) {
535 : // Add warning message for the glazing defined with full spectral data.
536 0 : ShowWarningError(
537 : state,
538 0 : format(
539 : "Window glazing material \"{}\" was defined with full spectral data and has been converted to average spectral data",
540 0 : matGlass->Name));
541 0 : ShowContinueError(
542 : state,
543 0 : format("due to its use with between-glass shades or blinds of the window construction \"{}\".", thisConstruct.Name));
544 0 : ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage.");
545 0 : ShowContinueError(state,
546 : "If this material is also used in other window constructions without between-glass shades or blinds,");
547 0 : ShowContinueError(state,
548 : "then make a duplicate material (with new name) if you want to model those windows (and reference the new "
549 : "material) using the full spectral data.");
550 : // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack
551 : // assuming wlt same as wle
552 0 : wm->tmpTrans = solarSpectrumAverage(state, t[0]);
553 0 : wm->tmpReflectSolBeamFront = solarSpectrumAverage(state, rff[0]);
554 0 : wm->tmpReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]);
555 :
556 : // visible properties
557 0 : wm->tmpTransVis = visibleSpectrumAverage(state, t[0]);
558 0 : wm->tmpReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]);
559 0 : wm->tmpReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]);
560 :
561 : // set this material to average spectral data
562 0 : matGlass->GlassSpectralDataPtr = 0;
563 0 : matGlass->Trans = wm->tmpTrans;
564 0 : matGlass->TransVis = wm->tmpTransVis;
565 0 : matGlass->ReflectSolBeamFront = wm->tmpReflectSolBeamFront;
566 0 : matGlass->ReflectSolBeamBack = wm->tmpReflectSolBeamBack;
567 0 : matGlass->ReflectVisBeamFront = wm->tmpReflectVisBeamFront;
568 0 : matGlass->ReflectVisBeamBack = wm->tmpReflectVisBeamBack;
569 0 : SpecDataNum = 0;
570 : }
571 : }
572 :
573 : // No spectral data for this layer; use spectral average values
574 45 : if (SpecDataNum == 0 && matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
575 39 : lquasi = true;
576 39 : numpt[IGlass - 1] = 2;
577 39 : t[IGlass - 1][0] = matGlass->Trans;
578 39 : if (IGlass == 1 || (IGlass == 2 && StormWinConst)) t[IGlass - 1][0] *= matGlass->GlassTransDirtFactor;
579 39 : t[IGlass - 1][1] = matGlass->TransVis;
580 39 : if (IGlass == 1 || (IGlass == 2 && StormWinConst)) t[IGlass - 1][1] *= matGlass->GlassTransDirtFactor;
581 39 : rff[IGlass - 1][0] = matGlass->ReflectSolBeamFront;
582 39 : rbb[IGlass - 1][0] = matGlass->ReflectSolBeamBack;
583 39 : rff[IGlass - 1][1] = matGlass->ReflectVisBeamFront;
584 39 : rbb[IGlass - 1][1] = matGlass->ReflectVisBeamBack;
585 : }
586 :
587 45 : if (matGlass->windowOpticalData == Window::OpticalDataModel::SpectralAndAngle) {
588 2 : if (!wm->BGFlag) AllGlassIsSpectralAverage = false;
589 2 : numptDAT = wm->wle.size();
590 2 : numpt[IGlass - 1] = numptDAT;
591 2 : if (wm->BGFlag) {
592 : // 5/16/2012 CR 8793. Add warning message for the glazing defined with full spectral data.
593 0 : ShowWarningError(state,
594 0 : format("Window glazing material \"{}\" was defined with full spectral and angular data and has been "
595 : "converted to average spectral data",
596 0 : matGlass->Name));
597 0 : ShowContinueError(
598 : state,
599 0 : format("due to its use with between-glass shades or blinds of the window construction \"{}\".", thisConstruct.Name));
600 0 : ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage.");
601 0 : ShowContinueError(state,
602 : "If this material is also used in other window constructions without between-glass shades or blinds,");
603 0 : ShowContinueError(state,
604 : "then make a duplicate material (with new name) if you want to model those windows (and reference the new "
605 : "material) using the full spectral data.");
606 : // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack
607 : // assuming wlt same as wle
608 0 : for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
609 0 : Real64 lam = wm->wle[ILam - 1];
610 0 : wlt[IGlass - 1][ILam - 1] = lam;
611 0 : t[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngTransCurve->value(state, 0.0, lam);
612 0 : rff[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngFReflCurve->value(state, 0.0, lam);
613 0 : rbb[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngBReflCurve->value(state, 0.0, lam);
614 : }
615 0 : wm->tmpTrans = solarSpectrumAverage(state, t[0]);
616 0 : wm->tmpReflectSolBeamFront = solarSpectrumAverage(state, rff[0]);
617 0 : wm->tmpReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]);
618 :
619 : // visible properties
620 0 : wm->tmpTransVis = visibleSpectrumAverage(state, t[0]);
621 0 : wm->tmpReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]);
622 0 : wm->tmpReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]);
623 :
624 : // set this material to average spectral data
625 0 : matGlass->windowOpticalData = Window::OpticalDataModel::SpectralAverage;
626 0 : matGlass->Trans = wm->tmpTrans;
627 0 : matGlass->TransVis = wm->tmpTransVis;
628 0 : matGlass->ReflectSolBeamFront = wm->tmpReflectSolBeamFront;
629 0 : matGlass->ReflectSolBeamBack = wm->tmpReflectSolBeamBack;
630 0 : matGlass->ReflectVisBeamFront = wm->tmpReflectVisBeamFront;
631 0 : matGlass->ReflectVisBeamBack = wm->tmpReflectVisBeamBack;
632 0 : SpecDataNum = 0;
633 : }
634 : }
635 : } // End of loop over glass layers in the construction for front calculation
636 :
637 : // Loop over incidence angle from 0 to 90 deg in 10 deg increments.
638 : // Get glass layer properties, then glazing system properties (which include the
639 : // effect of inter-reflection among glass layers) at each incidence angle.
640 :
641 : // <<<<<<< HEAD
642 : // This was not a clear merge conflict, so I'm just taking the branch code and we'll see.
643 : std::array<Real64, numPhis> cosPhisLocal;
644 : // =======
645 : // for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
646 : // // 10 degree increment for incident angle is only value for a construction without a layer = SpectralAndAngle
647 : // Phi = double(IPhi - 1) * 10.0;
648 : // CosPhi = std::cos(Phi * Constant::DegToRad);
649 : // if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
650 : // >>>>>>> origin/develop
651 :
652 385 : for (int iPhi = 0; iPhi < numPhis; ++iPhi)
653 350 : cosPhisLocal[iPhi] = std::cos((double)iPhi * dPhiDeg * Constant::DegToRad);
654 :
655 385 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
656 : // For each wavelength, get glass layer properties at this angle of incidence
657 : // from properties at normal incidence
658 800 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
659 450 : LayPtr = thisConstruct.LayerPoint(wm->LayerNum[IGlass - 1]);
660 450 : auto *matGlass = dynamic_cast<Material::MaterialGlass *>(s_mat->materials(LayPtr));
661 450 : assert(matGlass != nullptr);
662 450 : if (matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
663 11890 : for (int ILam = 1; ILam <= numpt[IGlass - 1]; ++ILam) {
664 11460 : TransAndReflAtPhi(cosPhisLocal[iPhi],
665 11460 : t[IGlass - 1][ILam - 1],
666 11460 : rff[IGlass - 1][ILam - 1],
667 11460 : rbb[IGlass - 1][ILam - 1],
668 11460 : tPhi[IGlass - 1][ILam - 1],
669 11460 : rfPhi[IGlass - 1][ILam - 1],
670 11460 : rbPhi[IGlass - 1][ILam - 1],
671 11460 : wm->lSimpleGlazingSystem,
672 11460 : wm->SimpleGlazingSHGC,
673 11460 : wm->SimpleGlazingU);
674 : }
675 : } else {
676 4320 : for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
677 2140 : Real64 lam = wm->wle[ILam - 1];
678 2140 : wlt[IGlass - 1][ILam - 1] = lam;
679 2140 : tPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngTransCurve->value(state, iPhi * dPhiDeg, lam);
680 2140 : rfPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngFReflCurve->value(state, iPhi * dPhiDeg, lam);
681 2140 : rbPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngBReflCurve->value(state, iPhi * dPhiDeg, lam);
682 : }
683 : }
684 : // For use with between-glass shade/blind, save angular properties of isolated glass
685 : // for case that all glass layers were input with spectral-average properties
686 : // only used by between-glass shades or blinds
687 450 : if (AllGlassIsSpectralAverage) {
688 390 : tBareSolPhi(IGlass)[iPhi] = tPhi[IGlass - 1][0];
689 390 : tBareVisPhi(IGlass)[iPhi] = tPhi[IGlass - 1][1];
690 390 : rfBareSolPhi(IGlass)[iPhi] = rfPhi[IGlass - 1][0];
691 390 : rfBareVisPhi(IGlass)[iPhi] = rfPhi[IGlass - 1][1];
692 390 : rbBareSolPhi(IGlass)[iPhi] = rbPhi[IGlass - 1][0];
693 390 : rbBareVisPhi(IGlass)[iPhi] = rbPhi[IGlass - 1][1];
694 390 : afBareSolPhi(IGlass)[iPhi] = max(0.0, 1.0 - (tBareSolPhi(IGlass)[iPhi] + rfBareSolPhi(IGlass)[iPhi]));
695 390 : abBareSolPhi(IGlass)[iPhi] = max(0.0, 1.0 - (tBareSolPhi(IGlass)[iPhi] + rbBareSolPhi(IGlass)[iPhi]));
696 : }
697 : }
698 :
699 : // For each wavelength in the solar spectrum, calculate system properties
700 : // stPhi, srfPhi, srbPhi and saPhi at this angle of incidence.
701 : // In the following the argument "1" indicates that spectral average solar values
702 : // should be used for layers without spectral data.
703 :
704 350 : std::array<Real64, nume> stPhi = {0.0}; // Glazing system transmittance at angle of incidence for each wavelength in wle
705 350 : std::array<Real64, nume> srfPhi = {0.0}; // Glazing system front reflectance at angle of incidence for each wavelength in wle
706 350 : std::array<Real64, nume> srbPhi = {0.0}; // Glazing system back reflectance at angle of incidence for each wavelength in wle
707 : // For each layer, glazing system absorptance at angle of incidence
708 350 : Array2D<Real64> saPhi(maxGlassLayers, nume, 0.0);
709 :
710 350 : SystemSpectralPropertiesAtPhi(state, 1, NGlass, 0.0, 2.54, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
711 :
712 : // Get solar properties of system by integrating over solar irradiance spectrum.
713 : // For now it is assumed that the exterior and interior irradiance spectra are the same.
714 350 : tsolPhi[iPhi] = solarSpectrumAverage(state, stPhi);
715 350 : rfsolPhi[iPhi] = solarSpectrumAverage(state, srfPhi);
716 350 : rbsolPhi[iPhi] = solarSpectrumAverage(state, srbPhi);
717 :
718 800 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
719 48600 : for (int ILam = 1; ILam <= nume; ++ILam) {
720 48150 : sabsPhi(ILam) = saPhi(IGlass, ILam);
721 : }
722 450 : solabsPhi(IGlass)[iPhi] = solarSpectrumAverage(state, sabsPhi);
723 : }
724 :
725 : // Get visible properties of system by integrating over solar irradiance
726 : // spectrum weighted by photopic response.
727 : // Need to redo the calculation of system spectral properties here only if
728 : // one or more glass layers have no spectral data (lquasi = .TRUE.); in this
729 : // case the spectral average visible properties will be used for the layers
730 : // without spectral data, as indicated by the argument "2".
731 :
732 350 : if (lquasi) SystemSpectralPropertiesAtPhi(state, 2, NGlass, 0.37, 0.78, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
733 350 : tvisPhi[iPhi] = visibleSpectrumAverage(state, stPhi);
734 350 : rfvisPhi[iPhi] = visibleSpectrumAverage(state, srfPhi);
735 350 : rbvisPhi[iPhi] = visibleSpectrumAverage(state, srbPhi);
736 :
737 350 : } // End of loop over incidence angles for front calculation
738 :
739 : // only used by between-glass shades or blinds
740 35 : if (AllGlassIsSpectralAverage) {
741 71 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
742 39 : W5LsqFit(cosPhisLocal, tBareSolPhi(IGlass), thisConstruct.tBareSolCoef(IGlass));
743 39 : W5LsqFit(cosPhisLocal, tBareVisPhi(IGlass), thisConstruct.tBareVisCoef(IGlass));
744 39 : W5LsqFit(cosPhisLocal, rfBareSolPhi(IGlass), thisConstruct.rfBareSolCoef(IGlass));
745 39 : W5LsqFit(cosPhisLocal, rfBareVisPhi(IGlass), thisConstruct.rfBareVisCoef(IGlass));
746 39 : W5LsqFit(cosPhisLocal, rbBareSolPhi(IGlass), thisConstruct.rbBareSolCoef(IGlass));
747 39 : W5LsqFit(cosPhisLocal, rbBareVisPhi(IGlass), thisConstruct.rbBareVisCoef(IGlass));
748 39 : W5LsqFit(cosPhisLocal, afBareSolPhi(IGlass), thisConstruct.afBareSolCoef(IGlass));
749 39 : W5LsqFit(cosPhisLocal, abBareSolPhi(IGlass), thisConstruct.abBareSolCoef(IGlass));
750 : }
751 : }
752 :
753 35 : thisConstruct.ReflectSolDiffFront = DiffuseAverage(rfsolPhi);
754 35 : thisConstruct.ReflectSolDiffBack = DiffuseAverage(rbsolPhi);
755 35 : thisConstruct.ReflectVisDiffFront = DiffuseAverage(rfvisPhi);
756 35 : thisConstruct.ReflectVisDiffBack = DiffuseAverage(rbvisPhi);
757 :
758 35 : tsolDiff = DiffuseAverage(tsolPhi);
759 35 : tvisDiff = DiffuseAverage(tvisPhi);
760 35 : thisConstruct.TransDiff = tsolDiff;
761 35 : thisConstruct.TransDiffVis = tvisDiff;
762 80 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
763 45 : solabsPhiLay = solabsPhi(IGlass); // Is this a deep copy?
764 45 : solabsDiff(IGlass) = DiffuseAverage(solabsPhiLay);
765 45 : thisConstruct.AbsDiff(IGlass) = solabsDiff(IGlass);
766 :
767 : // For use with between-glass shade/blind, get diffuse properties of isolated glass for case when
768 : // all glass layers were input with spectral-average properties
769 : // only used by between-glass shades or blinds
770 45 : if (AllGlassIsSpectralAverage) {
771 39 : thisConstruct.tBareSolDiff(IGlass) = DiffuseAverage(tBareSolPhi(IGlass));
772 39 : thisConstruct.tBareVisDiff(IGlass) = DiffuseAverage(tBareVisPhi(IGlass));
773 39 : thisConstruct.rfBareSolDiff(IGlass) = DiffuseAverage(rfBareSolPhi(IGlass));
774 39 : thisConstruct.rfBareVisDiff(IGlass) = DiffuseAverage(rfBareVisPhi(IGlass));
775 39 : thisConstruct.rbBareSolDiff(IGlass) = DiffuseAverage(rbBareSolPhi(IGlass));
776 39 : thisConstruct.rbBareVisDiff(IGlass) = DiffuseAverage(rbBareVisPhi(IGlass));
777 39 : thisConstruct.afBareSolDiff(IGlass) = max(0.0, 1.0 - (thisConstruct.tBareSolDiff(IGlass) + thisConstruct.rfBareSolDiff(IGlass)));
778 39 : thisConstruct.abBareSolDiff(IGlass) = max(0.0, 1.0 - (thisConstruct.tBareSolDiff(IGlass) + thisConstruct.rbBareSolDiff(IGlass)));
779 : }
780 : }
781 :
782 : //------------------------------------------------------------------------------------------
783 : // Back calculation (solar incident from inside of room); bare glass portion of construction
784 : //------------------------------------------------------------------------------------------
785 :
786 35 : lquasi = false;
787 35 : wm->LayerNum = {0};
788 :
789 : // Loop over glass layers in the construction.
790 80 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
791 45 : int LayNum = 1 + (NGlass - IGlass) * 2;
792 45 : if (ExtShade || ExtBlind || ExtScreen) LayNum = 2 + (NGlass - IGlass) * 2;
793 45 : if (BGShade || BGBlind) {
794 0 : if (NGlass == 2) {
795 0 : if (IGlass == 1) LayNum = 5;
796 0 : if (IGlass == 2) LayNum = 1;
797 : } else { // NGlass = 3
798 0 : if (IGlass == 1) LayNum = 7;
799 0 : if (IGlass == 2) LayNum = 3;
800 0 : if (IGlass == 3) LayNum = 1;
801 : }
802 : }
803 45 : wm->LayerNum[IGlass - 1] = LayNum;
804 45 : LayPtr = thisConstruct.LayerPoint(LayNum);
805 45 : auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(s_mat->materials(LayPtr));
806 45 : assert(matGlass != nullptr);
807 :
808 45 : if (matGlass->GlassSpectralDataPtr != 0) {
809 4 : auto const &specData = s_mat->SpectralData(matGlass->GlassSpectralDataPtr);
810 : // Get the spectral data for the transmittance, front reflectance and
811 : // back reflectance (all at normal incidence) for this layer.
812 : // In this case, "front" means incident from the inside and "back"
813 : // means incident from the outside.
814 :
815 4 : numptDAT = specData.NumOfWavelengths;
816 4 : numpt[IGlass - 1] = numptDAT;
817 :
818 1072 : for (int ILam = 1; ILam <= numptDAT; ++ILam) {
819 1068 : wlt[IGlass - 1][ILam - 1] = specData.WaveLength(ILam);
820 1068 : t[IGlass - 1][ILam - 1] = specData.Trans(ILam);
821 1068 : if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) t[IGlass - 1][ILam - 1] *= matGlass->GlassTransDirtFactor;
822 1068 : rff[IGlass - 1][ILam - 1] = specData.ReflBack(ILam);
823 1068 : rbb[IGlass - 1][ILam - 1] = specData.ReflFront(ILam);
824 : }
825 :
826 : // No spectral data for this layer; use spectral average values
827 41 : } else if (matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
828 39 : lquasi = true;
829 39 : numpt[IGlass - 1] = 2;
830 39 : t[IGlass - 1][0] = matGlass->Trans;
831 39 : if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) t[IGlass - 1][0] *= matGlass->GlassTransDirtFactor;
832 39 : t[IGlass - 1][1] = matGlass->TransVis;
833 39 : if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) t[IGlass - 1][1] *= matGlass->GlassTransDirtFactor;
834 39 : rff[IGlass - 1][0] = matGlass->ReflectSolBeamBack;
835 39 : rbb[IGlass - 1][0] = matGlass->ReflectSolBeamFront;
836 39 : rff[IGlass - 1][1] = matGlass->ReflectVisBeamBack;
837 39 : rbb[IGlass - 1][1] = matGlass->ReflectVisBeamFront;
838 :
839 : // Using SpectralAndAngle here
840 : } else {
841 2 : numptDAT = wm->wle.size();
842 2 : numpt[IGlass - 1] = numptDAT;
843 : }
844 : } // End of loop over glass layers in the construction for back calculation
845 :
846 : // Loop over incidence angle from 0 to 90 deg in 10 deg increments.
847 : // Get bare glass layer properties, then glazing system properties at each incidence angle.
848 : // The glazing system properties include the effect of inter-reflection among glass layers,
849 : // but exclude the effect of a shade or blind if present in the construction.
850 : // When a construction has a layer = SpectralAndAngle, the 10 degree increment will be overridden.
851 :
852 : // another odd merge conflict, I'm just taking the branch code
853 : //<<<<<<< HEAD
854 385 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
855 : //=======
856 : // for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
857 : // Phi = double(IPhi - 1) * 10.0;
858 : // CosPhi = std::cos(Phi * Constant::DegToRad);
859 : // if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
860 :
861 : // >>>>>>> origin/develop
862 : // For each wavelength, get glass layer properties at this angle of incidence
863 : // from properties at normal incidence
864 800 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
865 450 : LayPtr = thisConstruct.LayerPoint(wm->LayerNum[IGlass - 1]);
866 450 : auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(s_mat->materials(LayPtr));
867 450 : assert(matGlass != nullptr);
868 450 : if (matGlass->windowOpticalData != Window::OpticalDataModel::SpectralAndAngle) {
869 11890 : for (int ILam = 1; ILam <= numpt[IGlass - 1]; ++ILam) {
870 :
871 11460 : TransAndReflAtPhi(cosPhisLocal[iPhi],
872 11460 : t[IGlass - 1][ILam - 1],
873 11460 : rff[IGlass - 1][ILam - 1],
874 11460 : rbb[IGlass - 1][ILam - 1],
875 11460 : tPhi[IGlass - 1][ILam - 1],
876 11460 : rfPhi[IGlass - 1][ILam - 1],
877 11460 : rbPhi[IGlass - 1][ILam - 1],
878 11460 : wm->lSimpleGlazingSystem,
879 11460 : wm->SimpleGlazingSHGC,
880 11460 : wm->SimpleGlazingU);
881 : }
882 :
883 : } else {
884 4320 : for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
885 2140 : Real64 lam = wm->wle[ILam - 1];
886 2140 : wlt[IGlass - 1][ILam - 1] = lam;
887 2140 : tPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngTransCurve->value(state, iPhi * dPhiDeg, lam);
888 2140 : rfPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngFReflCurve->value(state, iPhi * dPhiDeg, lam);
889 2140 : rbPhi[IGlass - 1][ILam - 1] = matGlass->GlassSpecAngBReflCurve->value(state, iPhi * dPhiDeg, lam);
890 : }
891 : }
892 : }
893 :
894 : // For each wavelength in the solar spectrum, calculate system properties
895 : // stPhi, srfPhi, srbPhi and saPhi at this angle of incidence
896 350 : std::array<Real64, nume> stPhi = {0.0}; // Glazing system transmittance at angle of incidence for each wavelength in wle
897 350 : std::array<Real64, nume> srfPhi = {0.0}; // Glazing system front reflectance at angle of incidence for each wavelength in wle
898 350 : std::array<Real64, nume> srbPhi = {0.0}; // Glazing system back reflectance at angle of incidence for each wavelength in wle
899 : // For each layer, glazing system absorptance at angle of incidence
900 350 : Array2D<Real64> saPhi(maxGlassLayers, nume, 0.0);
901 :
902 350 : SystemSpectralPropertiesAtPhi(state, 1, NGlass, 0.0, 2.54, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
903 :
904 : // Get back absorptance properties of system by integrating over solar irradiance spectrum.
905 : // For now it is assumed that the exterior and interior irradiance spectra are the same.
906 :
907 800 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
908 48600 : for (int j = 1; j <= nume; ++j) {
909 48150 : sabsPhi(j) = saPhi(IGlass, j);
910 : }
911 450 : solabsBackPhi(IGlass)[iPhi] = solarSpectrumAverage(state, sabsPhi);
912 : }
913 :
914 350 : } // End of loop over incidence angles for back calculation
915 :
916 80 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
917 45 : IGlassBack = NGlass - IGlass + 1;
918 45 : thisConstruct.AbsDiffBack(IGlass) = DiffuseAverage(solabsBackPhi(IGlassBack));
919 : }
920 :
921 : //-----------------------------------------------------------------------
922 : // Correction for effect of shade, screen or blind if present in the construction
923 : //-----------------------------------------------------------------------
924 :
925 : // For construction with shade, screen or blind, get system shading device absorptance
926 : // and correct the system glass layer absorptances for the effect of reflection
927 : // and transmission by shade, screen or blind. Get system reflectance (front and back,
928 : // solar and visible)
929 35 : auto &constr = thisConstruct;
930 :
931 : // Solar and visible properties of isolated shade or blind
932 : // (Note: for shades or screen we go through the following loop over slat angles only once.)
933 :
934 35 : Real64 const tsolDiff_2(pow_2(tsolDiff));
935 35 : Real64 const tvisDiff_2(pow_2(tvisDiff));
936 :
937 35 : if (IntShade) {
938 0 : auto const *matSh = dynamic_cast<Material::MaterialShade const *>(s_mat->materials(constr.LayerPoint(ShadeLayNum)));
939 0 : assert(matSh != nullptr);
940 0 : ShadeAbs = matSh->AbsorpSolar;
941 0 : ShadeTrans = matSh->Trans;
942 0 : ShadeTransVis = matSh->TransVis;
943 0 : ShadeRefl = matSh->ReflectShade;
944 0 : ShadeReflVis = matSh->ReflectShadeVis;
945 0 : rsh = ShadeRefl;
946 0 : rshv = ShadeReflVis;
947 0 : tsh = ShadeTrans;
948 0 : tshv = ShadeTransVis;
949 0 : ash = ShadeAbs;
950 :
951 : // Correction factors for inter-reflections between glass and shading device
952 0 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffBack);
953 0 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffBack);
954 :
955 : // Front incident solar, beam, interior shade
956 0 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
957 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
958 0 : solabsPhi(IGlass)[iPhi] += tsolPhi[iPhi] * ShadeRefl * ShadeReflFac * constr.AbsDiffBack(IGlass);
959 : }
960 0 : solabsShadePhi[iPhi] = tsolPhi[iPhi] * ShadeReflFac * ShadeAbs;
961 0 : tsolPhi[iPhi] *= ShadeReflFac * ShadeTrans;
962 0 : tvisPhi[iPhi] *= ShadeReflFacVis * ShadeTransVis;
963 : }
964 :
965 : // Front incident solar, diffuse, interior shade
966 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
967 0 : constr.AbsDiff(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
968 : }
969 :
970 0 : constr.AbsDiffShade = tsolDiff * ShadeReflFac * ShadeAbs;
971 0 : constr.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
972 0 : constr.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
973 0 : constr.ReflectSolDiffFront += tsolDiff_2 * ShadeRefl * ShadeReflFac;
974 0 : constr.ReflectVisDiffFront += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
975 :
976 : // Back incident solar, diffuse, interior shade
977 :
978 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
979 0 : constr.AbsDiffBack(IGlass) *= ShadeTrans * ShadeReflFac;
980 : }
981 :
982 0 : constr.AbsDiffBackShade = ShadeAbs * (1 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffBack);
983 0 : constr.ReflectSolDiffBack = ShadeRefl + pow_2(ShadeTrans) * constr.ReflectSolDiffBack * ShadeReflFac;
984 0 : constr.ReflectVisDiffBack = ShadeReflVis + pow_2(ShadeTransVis) * constr.ReflectVisDiffBack * ShadeReflFacVis;
985 :
986 : // Exterior Shade
987 35 : } else if (ExtShade) {
988 0 : auto const *matSh = dynamic_cast<Material::MaterialShade const *>(s_mat->materials(constr.LayerPoint(ShadeLayNum)));
989 0 : assert(matSh != nullptr);
990 0 : ShadeAbs = matSh->AbsorpSolar;
991 0 : ShadeTrans = matSh->Trans;
992 0 : ShadeTransVis = matSh->TransVis;
993 0 : ShadeRefl = matSh->ReflectShade;
994 0 : ShadeReflVis = matSh->ReflectShadeVis;
995 0 : rsh = ShadeRefl;
996 0 : rshv = ShadeReflVis;
997 0 : tsh = ShadeTrans;
998 0 : tshv = ShadeTransVis;
999 0 : ash = ShadeAbs;
1000 :
1001 : // Correction factors for inter-reflections between glass and shading device
1002 0 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffFront);
1003 0 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffFront);
1004 :
1005 0 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
1006 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1007 0 : solabsPhi(IGlass)[iPhi] = ShadeTrans * solabsDiff(IGlass) * ShadeReflFac;
1008 : }
1009 0 : tsolPhi[iPhi] = ShadeTrans * ShadeReflFac * tsolDiff;
1010 0 : tvisPhi[iPhi] = ShadeTransVis * ShadeReflFacVis * tvisDiff;
1011 0 : solabsShadePhi[iPhi] = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffFront);
1012 : }
1013 :
1014 : // Front incident solar, diffuse, exterior shade/screen/blind
1015 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1016 0 : constr.AbsDiff(IGlass) = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
1017 : }
1018 :
1019 : // Front incident solar, diffuse, exterior shade/screen
1020 0 : constr.AbsDiffShade = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffFront);
1021 0 : constr.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
1022 0 : constr.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1023 0 : constr.ReflectSolDiffFront = ShadeRefl + pow_2(ShadeTrans) * constr.ReflectSolDiffFront * ShadeReflFac;
1024 0 : constr.ReflectVisDiffFront = ShadeReflVis + pow_2(ShadeTransVis) * constr.ReflectVisDiffFront * ShadeReflFacVis;
1025 :
1026 : // Back incident solar, diffuse, exterior shade/screen
1027 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1028 0 : constr.AbsDiffBack(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
1029 : }
1030 0 : constr.AbsDiffBackShade = tsolDiff * ShadeReflFac * ShadeAbs;
1031 0 : constr.ReflectSolDiffBack += tsolDiff_2 * ShadeRefl * ShadeReflFac;
1032 0 : constr.ReflectVisDiffBack += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1033 :
1034 : // Between-glass shade
1035 35 : } else if (BGShade) {
1036 0 : auto const *matSh = dynamic_cast<Material::MaterialShade const *>(s_mat->materials(constr.LayerPoint(ShadeLayNum)));
1037 0 : assert(matSh != nullptr);
1038 0 : ShadeAbs = matSh->AbsorpSolar;
1039 0 : ShadeTrans = matSh->Trans;
1040 0 : ShadeTransVis = matSh->TransVis;
1041 0 : ShadeRefl = matSh->ReflectShade;
1042 0 : ShadeReflVis = matSh->ReflectShadeVis;
1043 0 : rsh = ShadeRefl;
1044 0 : rshv = ShadeReflVis;
1045 0 : tsh = ShadeTrans;
1046 0 : tshv = ShadeTransVis;
1047 0 : ash = ShadeAbs;
1048 :
1049 : // Between-glass shade/blind; assumed to be between glass #2 and glass #3
1050 0 : tsh2 = pow_2(tsh);
1051 0 : tshv2 = pow_2(tshv);
1052 0 : td1 = constr.tBareSolDiff(1);
1053 0 : td2 = constr.tBareSolDiff(2);
1054 0 : td1v = constr.tBareVisDiff(1);
1055 0 : td2v = constr.tBareVisDiff(2);
1056 0 : afd1 = constr.afBareSolDiff(1);
1057 0 : afd2 = constr.afBareSolDiff(2);
1058 0 : abd1 = constr.abBareSolDiff(1);
1059 0 : abd2 = constr.abBareSolDiff(2);
1060 0 : rb1 = constr.rbBareSolDiff(1);
1061 0 : rb2 = constr.rbBareSolDiff(2);
1062 0 : rb1v = constr.rbBareVisDiff(1);
1063 0 : rb2v = constr.rbBareVisDiff(2);
1064 0 : rf1 = constr.rfBareSolDiff(1);
1065 0 : rf2 = constr.rfBareSolDiff(2);
1066 0 : rf1v = constr.rfBareVisDiff(1);
1067 0 : rf2v = constr.rfBareVisDiff(2);
1068 :
1069 0 : if (NGlass == 2) {
1070 :
1071 : // Front incident solar, beam, between-glass shade, NGlass = 2
1072 :
1073 0 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
1074 0 : t1 = tBareSolPhi(1)[iPhi];
1075 0 : t1v = tBareVisPhi(1)[iPhi];
1076 0 : af1 = afBareSolPhi(1)[iPhi];
1077 0 : ab1 = abBareSolPhi(1)[iPhi];
1078 0 : tsolPhi[iPhi] = t1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * td2;
1079 0 : tvisPhi[iPhi] = t1v * (tshv + rshv * rb1v * tshv + tshv * rf2v * rshv) * td2v;
1080 0 : solabsShadePhi[iPhi] = t1 * (ash + rsh * rb1 + tsh * rf2) * ash;
1081 0 : solabsPhi(1)[iPhi] = af1 + t1 * (rsh + rsh * rb1 * rsh + tsh * rf2 * tsh) * abd1;
1082 0 : solabsPhi(2)[iPhi] = t1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * afd2;
1083 : } // End of loop over incidence angles
1084 :
1085 : // Front incident solar, diffuse, between-glass shade, NGlass = 2
1086 :
1087 0 : constr.TransDiff = td1 * (tsh + rsh * rb1 * tsh + tsh * rb2 * rsh) * td2;
1088 0 : constr.TransDiffVis = td1v * (tshv + rshv * rb1v * tshv + tshv * rb2v * rshv) * td2v;
1089 0 : constr.AbsDiffShade = td1 * (ash + rsh * rb1 * ash + tsh * rf2 * ash);
1090 0 : constr.AbsDiff(1) = afd1 + td1 * (rsh + tsh * rb2 * tsh) * abd1;
1091 0 : constr.AbsDiff(2) = td1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * afd2;
1092 0 : constr.ReflectSolDiffFront = rf1 + td1 * (rsh + rsh * rb1 * rsh + tsh * rf2 * tsh) * td1;
1093 0 : constr.ReflectVisDiffFront = rf1v + td1v * (rshv + rshv * rb1v * rshv + tshv * rf2v * tshv) * td1v;
1094 :
1095 : // Back incident solar, diffuse, between-glass shade, NGlass = 2
1096 :
1097 0 : constr.AbsDiffBackShade = td2 * (ash + rsh * rf2 * ash + tsh * rb1 * ash);
1098 0 : constr.AbsDiffBack(1) = td2 * (tsh + rsh * rf2 * tsh + tsh * rb1 * rsh) * abd1;
1099 0 : constr.AbsDiffBack(2) = abd2 + td2 * (rsh + rsh * rf2 * rsh + tsh * rb1 * tsh) * afd2;
1100 0 : constr.ReflectSolDiffBack = rb2 + td2 * (rsh + rsh * rf2 * rsh + tsh * rb1 * tsh) * td2;
1101 0 : constr.ReflectVisDiffBack = rb2v + td2v * (rshv + rshv * rf2v * rshv + tshv * rb1v * tshv) * td2v;
1102 :
1103 0 : } else if (NGlass == 3) {
1104 :
1105 0 : td3 = constr.tBareSolDiff(3);
1106 0 : td3v = constr.tBareVisDiff(3);
1107 0 : afd3 = constr.afBareSolDiff(3);
1108 0 : abd3 = constr.abBareSolDiff(3);
1109 0 : rb3 = constr.rbBareSolDiff(3);
1110 0 : rb3v = constr.rbBareVisDiff(3);
1111 0 : rf3 = constr.rfBareSolDiff(3);
1112 0 : rf3v = constr.rfBareVisDiff(3);
1113 :
1114 : // Front incident solar, beam, between-glass shade, NGlass = 3
1115 :
1116 0 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
1117 0 : t1 = tBareSolPhi(1)[iPhi];
1118 0 : t1v = tBareVisPhi(1)[iPhi];
1119 0 : t2 = tBareSolPhi(2)[iPhi];
1120 0 : t2v = tBareVisPhi(2)[iPhi];
1121 0 : af1 = afBareSolPhi(1)[iPhi];
1122 0 : af2 = afBareSolPhi(2)[iPhi];
1123 0 : ab1 = abBareSolPhi(1)[iPhi];
1124 0 : ab2 = abBareSolPhi(2)[iPhi];
1125 0 : rbmf2 = max(0.0, 1.0 - (t2 + af2));
1126 :
1127 0 : tsolPhi[iPhi] = t1 * t2 * (tsh + tsh * rf3 * rsh + rsh * td2 * rb1 * td2 * tsh + rsh * rb2 * tsh) * td3;
1128 0 : tvisPhi[iPhi] = t1v * t2v * (tshv + tshv * rf3v * rshv + rshv * td2v * rb1v * td2v * tshv + rshv * rb2v * tshv) * td3v;
1129 0 : solabsShadePhi[iPhi] = t1 * t2 * (1 + rsh * td2 * rb1 * td2 + rsh * rb2) * ash;
1130 0 : solabsPhi(1)[iPhi] = af1 + rbmf2 * ab1 + t1 * t2 * rsh * (1 + rf3 * tsh + rb2 * rsh + td2 * rb1 * td2 * rsh) * td2 * abd1;
1131 0 : solabsPhi(2)[iPhi] = t1 * af2 + t1 * t2 * ((rsh + tsh * rf3 * tsh + rsh * rb2 * rsh) * abd2 + rsh * td2 * rb1 * afd2);
1132 0 : solabsPhi(3)[iPhi] = t1 * t2 * (tsh + rsh * (rb2 * tsh + td2 * rb2 * td2 * tsh + rf3 * rsh)) * afd3;
1133 : } // End of loop over incidence angle
1134 :
1135 : // Front incident solar, diffuse, between-glass shade, NGlass = 3
1136 :
1137 0 : constr.TransDiff = td1 * td2 * (tsh + rsh * td2 * rb1 * td2 * tsh + rsh * rb2 * tsh + tsh * rf3 * rsh) * td3;
1138 0 : constr.TransDiffVis = td1v * td2v * (tshv + rshv * td2v * rb1v * td2v * tshv + rshv * rb2v * tshv + tshv * rf3v * rshv) * td3v;
1139 0 : constr.AbsDiffShade = td1 * td2 * (ash * (1 + rsh * td2 * rb1 * td2 + rsh * rb2 * ash) + tsh * rf3 * ash);
1140 0 : constr.AbsDiff(1) =
1141 0 : afd1 + td1 * (rf2 + td2 * (rsh + rsh * rb2 * rsh + tsh * rf3 * tsh + rsh * td2 * rb1 * td2 * rsh) * td2) * abd1;
1142 0 : constr.AbsDiff(2) = td1 * (afd2 + td2 * (rsh + rsh * rb2 * rsh + tsh * rf3 * tsh) * abd2);
1143 0 : constr.AbsDiff(3) = td1 * td2 * (tsh + rsh * rb2 * tsh + rsh * td2 * rb1 * td2 * tsh + tsh * rf3 * rsh) * afd3;
1144 0 : constr.ReflectSolDiffFront =
1145 0 : rf1 + td1 * rf2 * td1 + td1 * td2 * (rsh + tsh * rf3 * tsh + rsh * rb2 * rsh + rsh * td2 * rb1 * td2 * rsh) * td2 * td1;
1146 0 : constr.ReflectVisDiffFront =
1147 0 : rf1v + td1v * rf2v * td1v +
1148 0 : td1v * td2v * (rshv + tshv * rf3v * tshv + rshv * rb2v * rshv + rshv * td2v * rb1v * td2v * rshv) * td2v * td1v;
1149 :
1150 : // Back incident solar, diffuse, between-glass shade, NGlass = 3
1151 :
1152 0 : constr.AbsDiffBackShade = td3 * ((1 + rsh * rf3) * ash + (tsh * td2 * rb1 * td2 + tsh * rb2) * ash);
1153 0 : constr.AbsDiffBack(1) = td3 * (tsh + rsh * rf3 * tsh + tsh * rb2 * rsh + tsh * td2 * rb1 * td2 * rsh) * td2 * abd1;
1154 0 : constr.AbsDiffBack(2) = td3 * ((tsh + rsh * rf3 * tsh) * abd2 + (tsh * td2 * rb1 * td2 + tsh * rb2) * afd2);
1155 0 : constr.AbsDiffBack(3) = abd3 + td3 * (rsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * afd3;
1156 0 : constr.ReflectSolDiffBack = rb3 + td3 * (rsh + rsh * rf3 * rsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * td3;
1157 0 : constr.ReflectVisDiffBack =
1158 0 : rb3v + td3v * (rshv + rshv * rf3 * rshv + tshv * rb2v * tshv + tshv * td2v * rb1v * td2v * tshv) * td3v;
1159 :
1160 : } // End of check if NGlass = 3
1161 :
1162 : // Interior blind
1163 35 : } else if (IntBlind) {
1164 1 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
1165 :
1166 182 : for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
1167 181 : auto const &btar = matBlind->TARs[iSlatAng];
1168 181 : ShadeTrans = btar.Sol.Ft.Df.Tra;
1169 181 : ShadeTransGnd = btar.Sol.Ft.Df.TraGnd;
1170 181 : ShadeTransSky = btar.Sol.Ft.Df.TraSky;
1171 181 : ShadeTransVis = btar.Vis.Ft.Df.Tra;
1172 181 : ShadeAbs = btar.Sol.Ft.Df.Abs;
1173 181 : ShadeRefl = btar.Sol.Ft.Df.Ref;
1174 181 : ShadeReflGnd = btar.Sol.Ft.Df.RefGnd;
1175 181 : ShadeReflSky = btar.Sol.Ft.Df.RefSky;
1176 181 : ShadeReflVis = btar.Vis.Ft.Df.Ref;
1177 :
1178 : // Correction factors for inter-reflections between glass and shading device
1179 181 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * thisConstruct.ReflectSolDiffBack);
1180 181 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * thisConstruct.ReflectVisDiffBack);
1181 :
1182 : // Front incident solar, diffuse, interior blind
1183 362 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1184 181 : auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
1185 181 : dfAbs.Sol.Ft.Df.Abs = constr.AbsDiff(IGlass) + tsolDiff * ShadeRefl * ShadeReflFac * constr.AbsDiffBack(IGlass);
1186 181 : dfAbs.Sol.Ft.Df.AbsGnd = constr.AbsDiff(IGlass) + tsolDiff * ShadeReflGnd * ShadeReflFac * constr.AbsDiffBack(IGlass);
1187 181 : dfAbs.Sol.Ft.Df.AbsSky = constr.AbsDiff(IGlass) + tsolDiff * ShadeReflSky * ShadeReflFac * constr.AbsDiffBack(IGlass);
1188 : }
1189 :
1190 181 : auto &cbtar = constr.blindTARs[iSlatAng];
1191 :
1192 181 : cbtar.Sol.Ft.Df.Abs = tsolDiff * ShadeReflFac * ShadeAbs;
1193 181 : cbtar.Sol.Ft.Df.AbsGnd = tsolDiff * ShadeReflFac * btar.Sol.Ft.Df.AbsGnd;
1194 181 : cbtar.Sol.Ft.Df.AbsSky = tsolDiff * ShadeReflFac * btar.Sol.Ft.Df.AbsSky;
1195 181 : cbtar.Sol.Ft.Df.Tra = tsolDiff * ShadeReflFac * ShadeTrans;
1196 181 : cbtar.Sol.Ft.Df.TraGnd = tsolDiff * ShadeReflFac * ShadeTransGnd;
1197 181 : cbtar.Sol.Ft.Df.TraSky = tsolDiff * ShadeReflFac * ShadeTransSky;
1198 181 : cbtar.Vis.Ft.Df.Tra = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1199 181 : cbtar.Sol.Ft.Df.Ref = constr.ReflectSolDiffFront + tsolDiff_2 * ShadeRefl * ShadeReflFac;
1200 181 : cbtar.Vis.Ft.Df.Ref = constr.ReflectVisDiffFront + tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1201 :
1202 : // Back incident solar, diffuse, interior blind
1203 :
1204 362 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1205 181 : auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
1206 181 : dfAbs.Sol.Bk.Df.Abs = constr.AbsDiffBack(IGlass) * ShadeTrans * ShadeReflFac;
1207 : }
1208 :
1209 181 : cbtar.Sol.Bk.Df.Abs = btar.Sol.Bk.Df.Abs + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffBack * ShadeAbs;
1210 181 : cbtar.Sol.Bk.Df.Ref = btar.Sol.Bk.Df.Ref + pow_2(ShadeTrans) * constr.ReflectSolDiffBack * ShadeReflFac;
1211 181 : cbtar.Vis.Bk.Df.Ref = btar.Vis.Bk.Df.Ref + pow_2(ShadeTransVis) * constr.ReflectVisDiffBack * ShadeReflFacVis;
1212 : }
1213 :
1214 : // Exterior blind
1215 34 : } else if (ExtBlind) {
1216 0 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
1217 :
1218 0 : for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
1219 0 : auto const &btar = matBlind->TARs[iSlatAng];
1220 0 : ShadeTrans = btar.Sol.Ft.Df.Tra;
1221 0 : ShadeTransGnd = btar.Sol.Ft.Df.TraGnd;
1222 0 : ShadeTransSky = btar.Sol.Ft.Df.TraSky;
1223 0 : ShadeTransVis = btar.Vis.Ft.Df.Tra;
1224 0 : ShadeAbs = btar.Sol.Bk.Df.Abs;
1225 0 : ShadeRefl = btar.Sol.Bk.Df.Ref;
1226 0 : ShadeReflVis = btar.Vis.Bk.Df.Ref;
1227 :
1228 : // Correction factors for inter-reflections between glass and shading device
1229 0 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffFront);
1230 0 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffFront);
1231 :
1232 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1233 0 : auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
1234 0 : dfAbs.Sol.Ft.Df.Abs = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
1235 0 : dfAbs.Sol.Ft.Df.AbsGnd = ShadeTransGnd * ShadeReflFac * solabsDiff(IGlass);
1236 0 : dfAbs.Sol.Ft.Df.AbsSky = ShadeTransSky * ShadeReflFac * solabsDiff(IGlass);
1237 : }
1238 :
1239 0 : auto &cbtar = constr.blindTARs[iSlatAng];
1240 0 : cbtar.Sol.Ft.Df.Abs = btar.Sol.Ft.Df.Abs + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
1241 0 : cbtar.Sol.Ft.Df.AbsGnd = btar.Sol.Ft.Df.AbsGnd + ShadeTransGnd * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
1242 0 : cbtar.Sol.Ft.Df.AbsSky = btar.Sol.Ft.Df.AbsSky + ShadeTransSky * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
1243 0 : cbtar.Sol.Ft.Df.Tra = tsolDiff * ShadeReflFac * ShadeTrans;
1244 0 : cbtar.Sol.Ft.Df.TraGnd = tsolDiff * ShadeReflFac * ShadeTransGnd;
1245 0 : cbtar.Sol.Ft.Df.TraSky = tsolDiff * ShadeReflFac * ShadeTransSky;
1246 0 : cbtar.Vis.Ft.Df.Tra = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1247 0 : cbtar.Sol.Ft.Df.Ref = ShadeRefl + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffFront * ShadeReflFac;
1248 0 : cbtar.Vis.Ft.Df.Ref = ShadeReflVis + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffFront * ShadeReflFacVis;
1249 :
1250 : // Back incident solar, diffuse, exterior shade/blind
1251 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1252 0 : auto &dfAbs = constr.layerSlatBlindDfAbs(IGlass)[iSlatAng];
1253 0 : dfAbs.Sol.Bk.Df.Abs = constr.AbsDiffBack(IGlass) + tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
1254 : }
1255 :
1256 0 : cbtar.Sol.Bk.Df.Abs = tsolDiff * ShadeReflFac * ShadeAbs;
1257 0 : cbtar.Sol.Bk.Df.Ref = constr.ReflectSolDiffBack + tsolDiff_2 * ShadeRefl * ShadeReflFac;
1258 0 : cbtar.Vis.Bk.Df.Ref = constr.ReflectVisDiffBack + tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1259 : }
1260 :
1261 : // Between-glass blind
1262 34 : } else if (BGBlind) {
1263 0 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
1264 0 : assert(matBlind != nullptr);
1265 :
1266 : // Between-glass shade/blind; assumed to be between glass #2 and glass #3
1267 0 : tsh2 = pow_2(tsh);
1268 0 : tshv2 = pow_2(tshv);
1269 0 : td1 = constr.tBareSolDiff(1);
1270 0 : td2 = constr.tBareSolDiff(2);
1271 0 : td1v = constr.tBareVisDiff(1);
1272 0 : td2v = constr.tBareVisDiff(2);
1273 0 : afd1 = constr.afBareSolDiff(1);
1274 0 : afd2 = constr.afBareSolDiff(2);
1275 0 : abd1 = constr.abBareSolDiff(1);
1276 0 : abd2 = constr.abBareSolDiff(2);
1277 0 : rb1 = constr.rbBareSolDiff(1);
1278 0 : rb2 = constr.rbBareSolDiff(2);
1279 0 : rb1v = constr.rbBareVisDiff(1);
1280 0 : rb2v = constr.rbBareVisDiff(2);
1281 0 : rf1 = constr.rfBareSolDiff(1);
1282 0 : rf2 = constr.rfBareSolDiff(2);
1283 0 : rf1v = constr.rfBareVisDiff(1);
1284 0 : rf2v = constr.rfBareVisDiff(2);
1285 :
1286 0 : for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
1287 0 : auto const &btar = matBlind->TARs[iSlatAng];
1288 0 : tsh = btar.Sol.Ft.Df.Tra;
1289 0 : tshGnd = btar.Sol.Ft.Df.TraGnd;
1290 0 : tshSky = btar.Sol.Ft.Df.TraSky;
1291 0 : tshv = btar.Vis.Ft.Df.Tra;
1292 0 : rfsh = btar.Sol.Ft.Df.Ref;
1293 0 : rfshGnd = btar.Sol.Ft.Df.RefGnd;
1294 0 : rfshSky = btar.Sol.Ft.Df.RefSky;
1295 0 : rfshv = btar.Vis.Ft.Df.Ref;
1296 0 : rbsh = btar.Sol.Bk.Df.Ref;
1297 0 : rbshv = btar.Vis.Bk.Df.Ref;
1298 0 : afsh = btar.Sol.Ft.Df.Abs;
1299 0 : afshGnd = btar.Sol.Ft.Df.AbsGnd;
1300 0 : afshSky = btar.Sol.Ft.Df.AbsSky;
1301 0 : absh = btar.Sol.Bk.Df.Abs;
1302 :
1303 0 : auto &cbtar = constr.blindTARs[iSlatAng];
1304 0 : if (NGlass == 2) {
1305 : // Front incident solar, diffuse, between-glass blind, NGlass = 2
1306 0 : auto &dfAbs1 = constr.layerSlatBlindDfAbs(1)[iSlatAng];
1307 0 : auto &dfAbs2 = constr.layerSlatBlindDfAbs(2)[iSlatAng];
1308 0 : dfAbs1.Sol.Ft.Df.Abs = afd1 + td1 * (rfsh + rfsh * rb1 * rfsh + tsh * rb2 * tsh) * abd1;
1309 0 : dfAbs1.Sol.Ft.Df.AbsGnd = afd1 + td1 * (rfshGnd + rfshGnd * rb1 * rfshGnd + tshGnd * rb2 * tsh) * abd1;
1310 0 : dfAbs1.Sol.Ft.Df.AbsSky = afd1 + td1 * (rfshSky + rfshSky * rb1 * rfshSky + tshSky * rb2 * tsh) * abd1;
1311 0 : dfAbs2.Sol.Ft.Df.Abs = td1 * (tsh + rfsh * rb1 * tsh + tsh * rf2 * rbsh) * afd2;
1312 0 : dfAbs2.Sol.Ft.Df.AbsGnd = td1 * (tshGnd + rfshGnd * rb1 * tsh + tshGnd * rf2 * rbsh) * afd2;
1313 0 : dfAbs2.Sol.Ft.Df.AbsSky = td1 * (tshSky + rfshSky * rb1 * tsh + tshSky * rf2 * rbsh) * afd2;
1314 0 : cbtar.Sol.Ft.Df.Abs = td1 * (afsh + rfsh * rb1 * afsh + tsh * rf2 * absh);
1315 0 : cbtar.Sol.Ft.Df.AbsGnd = td1 * (afshGnd + rfsh * rb1 * afsh + tshGnd * rf2 * absh);
1316 0 : cbtar.Sol.Ft.Df.AbsSky = td1 * (afshSky + rfsh * rb1 * afsh + tshSky * rf2 * absh);
1317 0 : cbtar.Sol.Ft.Df.Tra = td1 * (tsh + rfsh * rb1 * tsh + tsh * rb2 * rbsh) * td2;
1318 0 : cbtar.Sol.Ft.Df.TraGnd = td1 * (tshGnd + rfsh * rb1 * tshGnd + tshGnd * rb2 * rbsh) * td2;
1319 0 : cbtar.Sol.Ft.Df.TraSky = td1 * (tshSky + rfsh * rb1 * tshSky + tshSky * rb2 * rbsh) * td2;
1320 0 : cbtar.Vis.Ft.Df.Tra = td1v * (tshv + rfshv * rb1v * tshv + tshv * rb2v * rbshv) * td2v;
1321 0 : cbtar.Sol.Ft.Df.Ref = rf1 + td1 * (rfsh + rfsh * rb1 * rfsh + tsh * rf2 * tsh) * td1;
1322 0 : cbtar.Vis.Ft.Df.Ref = rf1v + td1v * (rfshv + rfshv * rb1v * rfshv + tshv * rf2v * tshv) * td1v;
1323 :
1324 : // Back incident solar, diffuse, between-glass blind, NGlass = 2
1325 :
1326 0 : dfAbs1.Sol.Bk.Df.Abs = td2 * (tsh + rbsh * rf2 * tsh + tsh * rb1 * rfsh) * abd1;
1327 0 : dfAbs2.Sol.Bk.Df.Abs = abd2 + td2 * (rbsh + rbsh * rf2 * rbsh + tsh * rb1 * tsh) * afd2;
1328 0 : cbtar.Sol.Bk.Df.Abs = td2 * (absh + rbsh * rf2 * absh + tsh * rb1 * afsh);
1329 0 : cbtar.Sol.Bk.Df.Ref = rb2 + td2 * (rbsh + rbsh * rf2 * rbsh + tsh * rb1 * tsh) * td2;
1330 0 : cbtar.Vis.Bk.Df.Ref = rb2v + td2v * (rbshv + rbshv * rf2v * rbshv + tshv * rb1v * tshv) * td2v;
1331 :
1332 0 : } else if (NGlass == 3) {
1333 0 : auto &dfAbs1 = constr.layerSlatBlindDfAbs(1)[iSlatAng];
1334 0 : auto &dfAbs2 = constr.layerSlatBlindDfAbs(2)[iSlatAng];
1335 0 : auto &dfAbs3 = constr.layerSlatBlindDfAbs(3)[iSlatAng];
1336 0 : td3 = constr.tBareSolDiff(3);
1337 0 : td3v = constr.tBareVisDiff(3);
1338 0 : afd3 = constr.afBareSolDiff(3);
1339 0 : abd3 = constr.abBareSolDiff(3);
1340 0 : rb3 = constr.rbBareSolDiff(3);
1341 0 : rb3v = constr.rbBareVisDiff(3);
1342 0 : rf3 = constr.rfBareSolDiff(3);
1343 0 : rf3v = constr.rfBareVisDiff(3);
1344 :
1345 : // Front incident solar, diffuse, between-glass blind, NGlass = 3
1346 :
1347 0 : dfAbs1.Sol.Ft.Df.Abs =
1348 0 : afd1 + td1 * (rf2 + td2 * (rfsh + rfsh * rb2 * rfsh + tsh * rf3 * tsh + rfsh * td2 * rb1 * td2 * rfsh) * td2) * abd1;
1349 0 : dfAbs1.Sol.Ft.Df.AbsGnd =
1350 0 : afd1 +
1351 0 : td1 * (rf2 + td2 * (rfshGnd + rfshGnd * rb2 * rfsh + tshGnd * rf3 * tsh + rfshGnd * td2 * rb1 * td2 * rfsh) * td2) * abd1;
1352 0 : dfAbs1.Sol.Ft.Df.AbsSky =
1353 0 : afd1 +
1354 0 : td1 * (rf2 + td2 * (rfshSky + rfshSky * rb2 * rfsh + tshSky * rf3 * tsh + rfshSky * td2 * rb1 * td2 * rfsh) * td2) * abd1;
1355 0 : dfAbs2.Sol.Ft.Df.Abs = td1 * (afd2 + td2 * (rfsh + rfsh * rb2 * rfsh + tsh * rf3 * tsh) * abd2);
1356 0 : dfAbs2.Sol.Ft.Df.AbsGnd = td1 * (afd2 + td2 * (rfshGnd + rfshGnd * rb2 * rfsh + tshGnd * rf3 * tsh) * abd2);
1357 0 : dfAbs2.Sol.Ft.Df.AbsSky = td1 * (afd2 + td2 * (rfshSky + rfshSky * rb2 * rfsh + tshSky * rf3 * tsh) * abd2);
1358 0 : dfAbs3.Sol.Ft.Df.Abs = td1 * td2 * (tsh + rfsh * rb2 * tsh + rfsh * td2 * rb1 * td2 * tsh + tsh * rf3 * rbsh) * afd3;
1359 0 : dfAbs3.Sol.Ft.Df.AbsGnd =
1360 0 : td1 * td2 * (tshGnd + rfshGnd * rb2 * tsh + rfshGnd * td2 * rb1 * td2 * tsh + tshGnd * rf3 * rbsh) * afd3;
1361 0 : dfAbs3.Sol.Ft.Df.AbsSky =
1362 0 : td1 * td2 * (tshSky + rfshSky * rb2 * tsh + rfshSky * td2 * rb1 * td2 * tsh + tshSky * rf3 * rbsh) * afd3;
1363 0 : cbtar.Sol.Ft.Df.Abs = td1 * td2 * (afsh * (1 + rfsh * td2 * rb1 * td2) + rfsh * rb2 * afsh + tsh * rf3 * absh);
1364 0 : cbtar.Sol.Ft.Df.AbsGnd = td1 * td2 * (afshGnd + afsh * rfsh * (td2 * rb1 * td2 + rb2) + tshGnd * rf3 * absh);
1365 0 : cbtar.Sol.Ft.Df.AbsSky = td1 * td2 * (afshSky + afsh * rfsh * (td2 * rb1 * td2 + rb2) + tshSky * rf3 * absh);
1366 0 : cbtar.Sol.Ft.Df.Tra = td1 * td2 * (tsh + rfsh * td2 * rb1 * td2 * tsh + rfsh * rb2 * tsh + tsh * rf3 * rbsh) * td3;
1367 0 : cbtar.Sol.Ft.Df.TraGnd =
1368 0 : td1 * td2 * (tshGnd + rfsh * td2 * rb1 * td2 * tshGnd + rfsh * rb2 * tshGnd + tshGnd * rf3 * rbsh) * td3;
1369 0 : cbtar.Sol.Ft.Df.TraSky =
1370 0 : td1 * td2 * (tshSky + rfsh * td2 * rb1 * td2 * tshSky + rfsh * rb2 * tshSky + tshSky * rf3 * rbsh) * td3;
1371 0 : cbtar.Vis.Ft.Df.Tra =
1372 0 : td1v * td2v * (tshv + rfshv * td2v * rb1v * td2v * tshv + rfshv * rb2v * tshv + tshv * rf3v * rbshv) * td3v;
1373 0 : cbtar.Sol.Ft.Df.Ref = rf1 + td1 * rf2 * td1 +
1374 0 : td1 * td2 * (rfsh + tsh * rf3 * tsh + rfsh * rb2 * rfsh + rfsh * td2 * rb1 * td2 * rfsh) * td2 * td1;
1375 0 : cbtar.Vis.Ft.Df.Ref =
1376 0 : rf1v + td1v * rf2v * td1v +
1377 0 : td1v * td2v * (rfshv + tshv * rf3v * tshv + rfshv * rb2v * rfshv + rfshv * td2v * rb1v * td2v * rfshv) * td2v * td1v;
1378 :
1379 : // Back incident solar, diffuse, between-glass blind, NGlass = 3
1380 :
1381 0 : dfAbs1.Sol.Bk.Df.Abs = td3 * (tsh + rbsh * rf3 * tsh + tsh * rb2 * rfsh + tsh * td2 * rb1 * td2 * rfsh) * td2 * abd1;
1382 0 : dfAbs2.Sol.Bk.Df.Abs = td3 * ((tsh + rbsh * rf3 * tsh) * abd2 + (tsh * td2 * rb1 * td2 + tsh * rb2) * afd2);
1383 0 : dfAbs3.Sol.Bk.Df.Abs = abd3 + td3 * (rbsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * afd3;
1384 0 : cbtar.Sol.Bk.Df.Abs = td3 * ((1 + rbsh * rf3) * absh + (tsh * td2 * rb1 * td2 + tsh * rb2) * afsh);
1385 0 : cbtar.Sol.Bk.Df.Ref = rb3 + td3 * (rbsh + rbsh * rf3 * rbsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * td3;
1386 0 : cbtar.Vis.Bk.Df.Ref =
1387 0 : rb3v + td3v * (rbshv + rbshv * rf3v * rbshv + tshv * rb2v * tshv + tshv * td2v * rb1v * td2v * tshv) * td3v;
1388 : } // if (NGlass == 3)
1389 : } // for (iSlatAng)
1390 :
1391 : // Exterior screen
1392 34 : } else if (ExtScreen) {
1393 : // diffuse screen properties are calculated during initialization (quarter-hemispherical integration of beam properties)
1394 0 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(s_mat->materials(thisConstruct.LayerPoint(ShadeLayNum)));
1395 0 : assert(matScreen != nullptr);
1396 :
1397 0 : ShadeAbs = matScreen->DfAbs;
1398 0 : ShadeTrans = matScreen->DfTrans;
1399 0 : ShadeTransVis = matScreen->DfTransVis;
1400 0 : ShadeRefl = matScreen->DfRef;
1401 0 : ShadeReflVis = matScreen->DfRefVis;
1402 0 : rsh = ShadeRefl;
1403 0 : rshv = ShadeReflVis;
1404 0 : tsh = ShadeTrans;
1405 0 : tshv = ShadeTransVis;
1406 0 : ash = ShadeAbs;
1407 :
1408 : // Correction factors for inter-reflections between glass and shading device
1409 0 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * constr.ReflectSolDiffFront);
1410 0 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * constr.ReflectVisDiffFront);
1411 :
1412 : // Front incident solar, diffuse, exterior shade/screen/blind
1413 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1414 0 : constr.AbsDiff(IGlass) = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
1415 : }
1416 :
1417 : // Front incident solar, diffuse, exterior shade/screen
1418 0 : constr.AbsDiffShade = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * constr.ReflectSolDiffFront);
1419 0 : constr.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
1420 0 : constr.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1421 0 : constr.ReflectSolDiffFront = ShadeRefl + pow_2(ShadeTrans) * constr.ReflectSolDiffFront * ShadeReflFac;
1422 0 : constr.ReflectVisDiffFront = ShadeReflVis + pow_2(ShadeTransVis) * constr.ReflectVisDiffFront * ShadeReflFacVis;
1423 :
1424 : // Back incident solar, diffuse, exterior shade/screen
1425 0 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1426 0 : constr.AbsDiffBack(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
1427 : }
1428 0 : constr.AbsDiffBackShade = tsolDiff * ShadeReflFac * ShadeAbs;
1429 0 : constr.ReflectSolDiffBack += tsolDiff_2 * ShadeRefl * ShadeReflFac;
1430 0 : constr.ReflectVisDiffBack += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1431 : } // if (ExtScreen)
1432 :
1433 : // Curve fits to get solar transmittance, reflectance, layer absorptance and
1434 : // visible transmittance as polynomials in cosine of incidence angle
1435 :
1436 35 : if (!BlindOn && !ScreenOn) { // Bare glass or shade on
1437 34 : W5LsqFit(cosPhisLocal, tsolPhi, thisConstruct.TransSolBeamCoef);
1438 34 : W5LsqFit(cosPhisLocal, rfsolPhi, thisConstruct.ReflSolBeamFrontCoef);
1439 34 : W5LsqFit(cosPhisLocal, rbsolPhi, thisConstruct.ReflSolBeamBackCoef);
1440 34 : W5LsqFit(cosPhisLocal, tvisPhi, thisConstruct.TransVisBeamCoef);
1441 :
1442 78 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1443 : // Front absorptance coefficients for glass layers
1444 44 : W5LsqFit(cosPhisLocal, solabsPhi(IGlass), thisConstruct.AbsBeamCoef(IGlass));
1445 :
1446 : // Back absorptance coefficients for glass layers
1447 44 : IGlassBack = NGlass - IGlass + 1;
1448 44 : W5LsqFit(cosPhisLocal, solabsBackPhi(IGlassBack), thisConstruct.AbsBeamBackCoef(IGlass));
1449 : }
1450 :
1451 : // To check goodness of fit //Tuned
1452 :
1453 374 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
1454 340 : tsolPhiFit[iPhi] = 0.0;
1455 340 : tvisPhiFit[iPhi] = 0.0;
1456 :
1457 : //<<<<<<< HEAD
1458 2380 : for (int CoefNum = 0; CoefNum < maxPolyCoef; ++CoefNum) {
1459 2040 : tsolPhiFit[iPhi] += thisConstruct.TransSolBeamCoef[CoefNum] * cosPhisLocal[iPhi];
1460 2040 : tvisPhiFit[iPhi] += thisConstruct.TransVisBeamCoef[CoefNum] * cosPhisLocal[iPhi];
1461 : //=======
1462 : // Phi = double(IPhi - 1) * 10.0;
1463 : // CosPhi = std::cos(Phi * Constant::DegToRad);
1464 : // if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
1465 : // Real64 cos_pow(1.0);
1466 : // for (int CoefNum = 1; CoefNum <= 6; ++CoefNum) {
1467 : // cos_pow *= CosPhi;
1468 : // tsolPhiFit(IPhi) += thisConstruct.TransSolBeamCoef(CoefNum) * cos_pow;
1469 : // tvisPhiFit(IPhi) += thisConstruct.TransVisBeamCoef(CoefNum) * cos_pow;
1470 : // >>>>>>> origin/develop
1471 : }
1472 : }
1473 : }
1474 :
1475 35 : if (ShadeOn) W5LsqFit(cosPhisLocal, solabsShadePhi, thisConstruct.AbsBeamShadeCoef);
1476 :
1477 : } // End of loop over constructions
1478 :
1479 : // Get effective glass and shade/blind emissivities for windows that have interior blind or
1480 : // shade. These are used to calculate zone MRT contribution from window when
1481 : // interior blind/shade is deployed.
1482 :
1483 : // Loop for ordinary windows
1484 942 : for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
1485 832 : auto const &surf = s_surf->Surface(SurfNum);
1486 832 : if (!surf.HeatTransSurf) continue;
1487 814 : if (!state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
1488 52 : if (s_surf->SurfWinWindowModelType(SurfNum) == WindowModel::BSDF) continue; // Irrelevant for Complex Fen
1489 52 : if (state.dataConstruction->Construct(surf.Construction).WindowTypeEQL) continue; // not required
1490 :
1491 45 : ConstrNumSh = surf.activeShadedConstruction;
1492 45 : if (ConstrNumSh == 0) continue;
1493 9 : TotLay = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
1494 :
1495 9 : auto &surfShade = s_surf->surfShades(SurfNum);
1496 :
1497 9 : auto const *mat = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay));
1498 9 : auto const *matFen = dynamic_cast<Material::MaterialFen const *>(mat);
1499 9 : assert(matFen != nullptr);
1500 :
1501 9 : if (mat->group == Material::Group::Shade) {
1502 0 : EpsGlIR = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay - 1))->AbsorpThermalBack;
1503 0 : RhoGlIR = 1 - EpsGlIR;
1504 0 : TauShIR = matFen->TransThermal;
1505 0 : EpsShIR = matFen->AbsorpThermal;
1506 0 : RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
1507 0 : surfShade.effShadeEmi = EpsShIR * (1.0 + RhoGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR));
1508 0 : surfShade.effGlassEmi = EpsGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR);
1509 :
1510 9 : } else if (mat->group == Material::Group::Blind) {
1511 8 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(mat);
1512 8 : assert(matBlind != nullptr);
1513 8 : surfShade.glass.epsIR = s_mat->materials(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay - 1))->AbsorpThermalBack;
1514 8 : surfShade.glass.rhoIR = 1 - surfShade.glass.epsIR;
1515 :
1516 : // surfShade.blind has not been initialized yet
1517 8 : surfShade.blind.slatAngDeg = matBlind->SlatAngle;
1518 8 : surfShade.blind.slatAng = surfShade.blind.slatAngDeg * Constant::DegToRad;
1519 :
1520 8 : Material::GetSlatIndicesInterpFac(
1521 8 : surfShade.blind.slatAng, surfShade.blind.slatAngIdxLo, surfShade.blind.slatAngIdxHi, surfShade.blind.slatAngInterpFac);
1522 8 : surfShade.blind.TAR.interpSlatAng(
1523 8 : matBlind->TARs[surfShade.blind.slatAngIdxLo], matBlind->TARs[surfShade.blind.slatAngIdxHi], surfShade.blind.slatAngInterpFac);
1524 :
1525 8 : TauShIR = surfShade.blind.TAR.IR.Ft.Tra;
1526 8 : EpsShIR = surfShade.blind.TAR.IR.Bk.Emi;
1527 8 : RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
1528 8 : surfShade.effShadeEmi = EpsShIR * (1.0 + surfShade.glass.rhoIR * TauShIR / (1.0 - surfShade.glass.rhoIR * RhoShIR));
1529 8 : surfShade.effGlassEmi = surfShade.glass.epsIR * TauShIR / (1.0 - surfShade.glass.rhoIR * RhoShIR);
1530 :
1531 : } // End of check if interior shade or interior blind
1532 : } // End of surface loop
1533 :
1534 942 : for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
1535 832 : auto const &surf = s_surf->Surface(SurfNum);
1536 832 : if (surf.Construction <= 0) continue;
1537 816 : auto const &construct = state.dataConstruction->Construct(surf.Construction);
1538 816 : if (!construct.TypeIsWindow) continue;
1539 :
1540 : // Total thickness of glazing system (used in calculation of inside reveal reflection/absorption
1541 52 : s_surf->SurfWinTotGlazingThickness(SurfNum) = 0.0;
1542 164 : for (int LayNum = 1; LayNum <= construct.TotLayers; ++LayNum) {
1543 112 : s_surf->SurfWinTotGlazingThickness(SurfNum) += s_mat->materials(construct.LayerPoint(LayNum))->Thickness;
1544 : }
1545 : // Sine and cosine of azimuth and tilt
1546 : // SurfaceWindow(SurfNum)%SinAzim = Surface(SurfNum)%SinAzim
1547 : // SurfaceWindow(SurfNum)%CosAzim = Surface(SurfNum)%CosAzim
1548 : // SurfaceWindow(SurfNum)%SinTilt = Surface(SurfNum)%SinTilt
1549 : // SurfaceWindow(SurfNum)%CosTilt = Surface(SurfNum)%CosTilt
1550 : // ! Outward normal unit vector (pointing away from room)
1551 : // SurfaceWindow(SurfNum)%OutNormVec(1) = Surface(SurfNum)%OutNormVec(1)
1552 : // SurfaceWindow(SurfNum)%OutNormVec(2) = Surface(SurfNum)%OutNormVec(2)
1553 : // SurfaceWindow(SurfNum)%OutNormVec(3) = Surface(SurfNum)%OutNormVec(3)
1554 : // write(outputfiledebug,*) 'window='//TRIM(surface(SurfNum)%name)
1555 : // write(outputfiledebug,*) ' swindow%outnormvec=',surfacewindow(SurfNum)%outnormvec
1556 : // write(outputfiledebug,*) ' surface%outnormvec=',surface(SurfNum)%outnormvec
1557 : // Window center
1558 52 : Rectangle = false;
1559 52 : Triangle = false;
1560 52 : if (surf.Sides == 3) Triangle = true;
1561 52 : if (surf.Sides == 4) Rectangle = true;
1562 52 : if (Rectangle) {
1563 : // Vertices of window (numbered counter-clockwise starting at upper left as viewed from inside of room).
1564 : // Assumes original vertices are numbered counter-clockwise from upper left as viewed from outside.
1565 52 : W3 = surf.Vertex(2);
1566 52 : W2 = surf.Vertex(3);
1567 52 : W1 = surf.Vertex(4);
1568 0 : } else if (Triangle) {
1569 0 : W3 = surf.Vertex(2);
1570 0 : W2 = surf.Vertex(3);
1571 0 : W1 = surf.Vertex(1);
1572 : }
1573 52 : W21 = W1 - W2;
1574 52 : W23 = W3 - W2;
1575 52 : if (Rectangle) {
1576 52 : s_surf->SurfaceWindow(SurfNum).WinCenter = W2 + (W23 + W21) / 2.0;
1577 0 : } else if (Triangle) {
1578 0 : s_surf->SurfaceWindow(SurfNum).WinCenter = W2 + (W23 + W21) / 3.0;
1579 : }
1580 : } // End of surface loop
1581 :
1582 110 : ReportGlass(state);
1583 110 : } // InitGlassOpticalCalculations()
1584 :
1585 : //*****************************************************************************************
1586 :
1587 111 : void W5InitGlassParameters(EnergyPlusData &state)
1588 : {
1589 : // Initializes variables used in the window optical and thermal calculation.
1590 :
1591 : Real64 FrWidth; // Window frame width {m}
1592 : Real64 FrEdgeWidth; // Frame edge width {m}
1593 : Real64 DivWidth; // Window divider width {m}
1594 : Real64 DivEdgeWidth; // Divider edge width {m}
1595 : Real64 GlHeight; // Height of glazed part of window {m}
1596 : Real64 GlWidth; // Width of glazed part of window {m}
1597 : int NumHorDividers; // Number of horizontal divider elements
1598 : int NumVertDividers; // Number of vertical divider elements
1599 : int DifOverrideCount; // Count the number of SolarDiffusing material overrides
1600 :
1601 111 : auto &s_mat = state.dataMaterial;
1602 111 : auto &s_surf = state.dataSurface;
1603 :
1604 435 : for (auto &constr : state.dataConstruction->Construct) {
1605 324 : if (constr.FromWindow5DataFile) continue;
1606 324 : if (constr.WindowTypeBSDF) continue;
1607 323 : constr.TransDiff = 0.0;
1608 323 : constr.TransDiffVis = 0.0;
1609 323 : constr.AbsDiffBackShade = 0.0;
1610 323 : constr.ShadeAbsorpThermal = 0.0;
1611 323 : constr.ReflectSolDiffBack = 0.0;
1612 323 : constr.ReflectSolDiffFront = 0.0;
1613 323 : constr.ReflectVisDiffFront = 0.0;
1614 :
1615 323 : std::fill(constr.AbsBeamShadeCoef.begin(), constr.AbsBeamShadeCoef.end(), 0.0);
1616 323 : std::fill(constr.TransSolBeamCoef.begin(), constr.TransSolBeamCoef.end(), 0.0);
1617 323 : std::fill(constr.ReflSolBeamFrontCoef.begin(), constr.ReflSolBeamFrontCoef.end(), 0.0);
1618 323 : std::fill(constr.ReflSolBeamBackCoef.begin(), constr.ReflSolBeamBackCoef.begin(), 0.0);
1619 323 : std::fill(constr.TransVisBeamCoef.begin(), constr.TransVisBeamCoef.end(), 0.0);
1620 323 : constr.AbsDiff = 0.0;
1621 323 : constr.AbsDiffBack = 0.0;
1622 2512 : for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
1623 15323 : for (int index = 0; index < maxPolyCoef; ++index) {
1624 13134 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).AbsBeamCoef(Layer)[index] = 0.0;
1625 13134 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).AbsBeamBackCoef(Layer)[index] = 0.0;
1626 : }
1627 : }
1628 : }
1629 :
1630 : // Set some static exterior-window frame and divider SurfaceWindow values
1631 : // from values in FrameDivider derived type
1632 945 : for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
1633 834 : auto const &surf = s_surf->Surface(SurfNum);
1634 834 : if (surf.FrameDivider == 0) continue;
1635 :
1636 7 : auto &surfWin = s_surf->SurfaceWindow(SurfNum);
1637 7 : auto const &frdiv = s_surf->FrameDivider(surf.FrameDivider);
1638 :
1639 7 : FrWidth = frdiv.FrameWidth;
1640 7 : GlHeight = surf.Height;
1641 7 : GlWidth = surf.Width;
1642 7 : NumVertDividers = frdiv.VertDividers;
1643 7 : NumHorDividers = frdiv.HorDividers;
1644 7 : s_surf->SurfWinFrameConductance(SurfNum) = frdiv.FrameConductance;
1645 7 : s_surf->SurfWinFrameSolAbsorp(SurfNum) = frdiv.FrameSolAbsorp;
1646 7 : s_surf->SurfWinFrameVisAbsorp(SurfNum) = frdiv.FrameVisAbsorp;
1647 7 : s_surf->SurfWinFrameEmis(SurfNum) = frdiv.FrameEmis;
1648 7 : s_surf->SurfWinFrEdgeToCenterGlCondRatio(SurfNum) = frdiv.FrEdgeToCenterGlCondRatio;
1649 7 : s_surf->SurfWinDividerType(SurfNum) = DataSurfaces::FrameDividerType::DividedLite;
1650 7 : if (frdiv.DividerType == DataSurfaces::FrameDividerType::Suspended)
1651 0 : s_surf->SurfWinDividerType(SurfNum) = DataSurfaces::FrameDividerType::Suspended;
1652 7 : DivWidth = frdiv.DividerWidth;
1653 7 : s_surf->SurfWinDividerConductance(SurfNum) = frdiv.DividerConductance;
1654 7 : s_surf->SurfWinDividerSolAbsorp(SurfNum) = frdiv.DividerSolAbsorp;
1655 7 : s_surf->SurfWinDividerVisAbsorp(SurfNum) = frdiv.DividerVisAbsorp;
1656 7 : s_surf->SurfWinDividerEmis(SurfNum) = frdiv.DividerEmis;
1657 7 : s_surf->SurfWinDivEdgeToCenterGlCondRatio(SurfNum) = frdiv.DivEdgeToCenterGlCondRatio;
1658 :
1659 7 : s_surf->SurfWinOutsideRevealSolAbs(SurfNum) = frdiv.OutsideRevealSolAbs;
1660 7 : s_surf->SurfWinInsideSillDepth(SurfNum) = frdiv.InsideSillDepth;
1661 7 : s_surf->SurfWinInsideReveal(SurfNum) = frdiv.InsideReveal;
1662 7 : s_surf->SurfWinInsideSillSolAbs(SurfNum) = frdiv.InsideSillSolAbs;
1663 7 : s_surf->SurfWinInsideRevealSolAbs(SurfNum) = frdiv.InsideRevealSolAbs;
1664 :
1665 7 : FrEdgeWidth = frdiv.FrameEdgeWidth;
1666 7 : DivEdgeWidth = frdiv.DividerEdgeWidth;
1667 7 : s_surf->SurfWinFrameEdgeArea(SurfNum) =
1668 7 : 2 * FrEdgeWidth * (GlHeight - FrEdgeWidth - NumHorDividers * DivWidth + GlWidth - FrEdgeWidth - NumVertDividers * DivWidth);
1669 7 : s_surf->SurfWinDividerEdgeArea(SurfNum) =
1670 14 : 2 * DivEdgeWidth * (NumHorDividers * (GlWidth - 2 * FrEdgeWidth) + NumVertDividers * (GlHeight - 2 * FrEdgeWidth)) -
1671 7 : NumHorDividers * NumVertDividers * (4 * pow_2(DivEdgeWidth) + 4 * FrEdgeWidth * DivWidth);
1672 7 : surfWin.centerGlassArea = surf.Area - s_surf->SurfWinFrameEdgeArea(SurfNum) - s_surf->SurfWinDividerEdgeArea(SurfNum);
1673 7 : surfWin.edgeGlassCorrFac =
1674 7 : (s_surf->SurfWinFrameEdgeArea(SurfNum) * s_surf->SurfWinFrEdgeToCenterGlCondRatio(SurfNum) +
1675 7 : s_surf->SurfWinDividerEdgeArea(SurfNum) * s_surf->SurfWinDivEdgeToCenterGlCondRatio(SurfNum) + surfWin.centerGlassArea) /
1676 7 : (s_surf->SurfWinFrameEdgeArea(SurfNum) + s_surf->SurfWinDividerEdgeArea(SurfNum) + surfWin.centerGlassArea);
1677 : } // for (SurfNum)
1678 :
1679 : // Set SolarDiffusing to true for exterior windows that have a construction with an innermost diffusing glass layer
1680 111 : DifOverrideCount = 0;
1681 945 : for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
1682 834 : auto const &surf = s_surf->Surface(SurfNum);
1683 834 : s_surf->SurfWinSolarDiffusing(SurfNum) = false;
1684 834 : if (surf.Class != SurfaceClass::Window || surf.ExtBoundCond != ExternalEnvironment || s_surf->SurfWinStormWinConstr(SurfNum) != 0)
1685 780 : continue;
1686 :
1687 54 : int ConstrNum = surf.Construction;
1688 54 : int MatNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(state.dataConstruction->Construct(ConstrNum).TotLayers);
1689 54 : auto const *mat = s_mat->materials(MatNum);
1690 54 : if (mat->group != Material::Group::Glass) continue;
1691 :
1692 30 : if (!dynamic_cast<Material::MaterialGlass const *>(mat)->SolarDiffusing) continue;
1693 :
1694 0 : if (!surf.HasShadeControl) {
1695 0 : s_surf->SurfWinSolarDiffusing(SurfNum) = true;
1696 : // There is a shading control
1697 0 : } else if (s_surf->WindowShadingControl(surf.activeWindowShadingControl).ShadingType == WinShadingType::SwitchableGlazing) {
1698 0 : s_surf->SurfWinSolarDiffusing(SurfNum) = true;
1699 : } else {
1700 0 : s_surf->SurfWinSolarDiffusing(SurfNum) = false;
1701 0 : ++DifOverrideCount;
1702 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1703 0 : ShowWarningError(state,
1704 0 : format("W5InitGlassParameters: Window=\"{}\" has interior material with Solar Diffusing=Yes, but "
1705 : "existing Window Shading Device sets Diffusing=No.",
1706 0 : surf.Name));
1707 : }
1708 : }
1709 : } // for (SurfNum)
1710 :
1711 111 : if (DifOverrideCount > 0) {
1712 0 : if (!state.dataGlobal->DisplayExtraWarnings) {
1713 0 : ShowWarningError(state,
1714 0 : format("W5InitGlassParameters: {} Windows had Solar Diffusing=Yes overridden by presence of Window Shading Device.",
1715 : DifOverrideCount));
1716 : } else {
1717 0 : ShowMessage(state,
1718 0 : format("W5InitGlassParameters: {} Windows had Solar Diffusing=Yes overridden by presence of Window Shading Device.",
1719 : DifOverrideCount));
1720 : }
1721 : }
1722 111 : } // W5InitGlassParameters()
1723 :
1724 : //****************************************************************************
1725 : // WINDOW 5 Optical Calculation Subroutines
1726 : //****************************************************************************
1727 :
1728 1020 : void SystemSpectralPropertiesAtPhi(EnergyPlusData &state,
1729 : int const iquasi, // When there is no spectral data, this is the wavelength
1730 : int const ngllayer, // Number of glass layers in construction
1731 : Real64 const wlbot, // Lowest and highest wavelength considered
1732 : Real64 const wltop,
1733 : std::array<int, maxGlassLayers> const &numpt,
1734 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &wlt,
1735 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &tPhi,
1736 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &rfPhi,
1737 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &rbPhi,
1738 : std::array<Real64, nume> &stPhi,
1739 : std::array<Real64, nume> &srfPhi,
1740 : std::array<Real64, nume> &srbPhi,
1741 : Array2D<Real64> &saPhi)
1742 : {
1743 :
1744 : // SUBROUTINE INFORMATION:
1745 : // AUTHOR Adapted by F.Winkelmann from WINDOW 5
1746 : // subroutine opcalc
1747 : // DATE WRITTEN August 1999
1748 : // MODIFIED na
1749 : // RE-ENGINEERED na
1750 :
1751 : // PURPOSE OF THIS SUBROUTINE:
1752 : // For a particular angle of incidence, calculates system properties
1753 : // for a multi-layer glazing for each wavelength in the solar spectrum.
1754 : // Handles the special case of one or more layers that do not have spectral data.
1755 :
1756 : // Returns, for a particular angle of incidence:
1757 : // stPhi transmissivity of system at each wavelength in swl
1758 : // srfPhi front reflectance of system at each wavelength in swl
1759 : // srbPhi back reflectance of system at each wavelength in swl
1760 : // sabsPhi absorptance by layer at each wavelength in swl
1761 :
1762 1020 : Array1D<Real64> sabsPhi(5); // System solar absorptance in each glass layer for
1763 : // particular angle of incidence
1764 :
1765 : // transmittance at angle of incidence
1766 1020 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> tadjPhi = {0.0};
1767 : // front reflectance at angle of incidence
1768 1020 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rfadjPhi = {0.0};
1769 : // back reflectance at angle of incidence
1770 1020 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbadjPhi = {0.0};
1771 :
1772 1020 : auto const &wm = state.dataWindowManager;
1773 : // For each glass layer find tPhi, rfPhi, and rbPhi at each wavelength
1774 :
1775 2310 : for (int in = 1; in <= ngllayer; ++in) {
1776 139320 : for (int iwl = 1; iwl <= nume; ++iwl) {
1777 138030 : Real64 wl = wm->wle[iwl - 1];
1778 138030 : if (wl < wlbot || wl > wltop) continue;
1779 : // In the following numpt is the number of spectral data points for each layer;
1780 : // numpt = 2 if there is no spectral data for a layer.
1781 109950 : if (numpt[in - 1] <= 2) {
1782 97110 : tadjPhi[in - 1][iwl - 1] = tPhi[in - 1][iquasi - 1];
1783 97110 : rfadjPhi[in - 1][iwl - 1] = rfPhi[in - 1][iquasi - 1];
1784 97110 : rbadjPhi[in - 1][iwl - 1] = rbPhi[in - 1][iquasi - 1];
1785 : } else {
1786 : // Interpolate to get properties at the solar spectrum wavelengths
1787 12840 : tadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], tPhi[in - 1], numpt[in - 1], wl);
1788 12840 : rfadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], rfPhi[in - 1], numpt[in - 1], wl);
1789 12840 : rbadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], rbPhi[in - 1], numpt[in - 1], wl);
1790 : }
1791 : }
1792 : }
1793 :
1794 : // Calculate system properties at each wavelength
1795 110160 : for (int j = 1; j <= nume; ++j) {
1796 109140 : Real64 wl = wm->wle[j - 1];
1797 109140 : if (wl < wlbot || wl > wltop) continue;
1798 :
1799 : // Set diagonal of matrix for subroutine SystemPropertiesAtLambdaAndPhi
1800 196050 : for (int i = 1; i <= ngllayer; ++i) {
1801 109950 : wm->top[i - 1][i - 1] = tadjPhi[i - 1][j - 1];
1802 109950 : wm->rfop[i - 1][i - 1] = rfadjPhi[i - 1][j - 1];
1803 109950 : wm->rbop[i - 1][i - 1] = rbadjPhi[i - 1][j - 1];
1804 : }
1805 :
1806 : // Calculate glazing system properties
1807 86100 : if (ngllayer == 1) { // Single-layer system
1808 62250 : stPhi[j - 1] = wm->top[0][0];
1809 62250 : srfPhi[j - 1] = wm->rfop[0][0];
1810 62250 : srbPhi[j - 1] = wm->rbop[0][0];
1811 62250 : sabsPhi(1) = 1.0 - stPhi[j - 1] - srfPhi[j - 1];
1812 : } else { // Multilayer system
1813 : // Get glazing system properties stPhi, etc., at this wavelength and incidence angle
1814 23850 : SystemPropertiesAtLambdaAndPhi(state, ngllayer, stPhi[j - 1], srfPhi[j - 1], srbPhi[j - 1], sabsPhi);
1815 : }
1816 :
1817 196050 : for (int i = 1; i <= ngllayer; ++i) {
1818 109950 : saPhi(i, j) = sabsPhi(i);
1819 : }
1820 :
1821 : } // End of wavelength loop
1822 1020 : } // SystemSpectralPropertiesAtPhi()
1823 :
1824 : //************************************************************************
1825 :
1826 23850 : void SystemPropertiesAtLambdaAndPhi(EnergyPlusData &state,
1827 : int const n, // Number of glass layers
1828 : Real64 &tt, // System transmittance
1829 : Real64 &rft, // System front and back reflectance
1830 : Real64 &rbt,
1831 : Array1A<Real64> aft // System absorptance of each glass layer
1832 : )
1833 : {
1834 :
1835 : // SUBROUTINE INFORMATION:
1836 : // AUTHOR Adapted by F. Winkelmann from WINDOW 5
1837 : // subroutine op
1838 : // DATE WRITTEN August 1999
1839 : // MODIFIED na
1840 : // RE-ENGINEERED na
1841 :
1842 : // PURPOSE OF THIS SUBROUTINE:
1843 : // For a given angle of incidence, finds the overall properties of
1844 : // of a series of layers at a particular wavelength
1845 :
1846 : // Argument array dimensioning
1847 23850 : aft.dim(5);
1848 :
1849 : Real64 denom; // Intermediate variables
1850 : Real64 denom1;
1851 : Real64 denom2;
1852 : Real64 t0; // Transmittance, back reflectance and front
1853 : Real64 rb0;
1854 : Real64 rf0;
1855 : // reflectance variables
1856 : Real64 af; // Front and back absorptance variables
1857 : Real64 ab;
1858 :
1859 23850 : auto &wm = state.dataWindowManager;
1860 : // Calculate perimeter elements of rt matrix
1861 47700 : for (int i = 1; i <= n - 1; ++i) {
1862 47700 : for (int j = i + 1; j <= n; ++j) {
1863 23850 : denom = 1.0 - wm->rfop[j - 1][j - 1] * wm->rbop[i - 1][j - 2];
1864 23850 : if (denom == 0.0) {
1865 148 : wm->top[j - 1][i - 1] = 0.0;
1866 148 : wm->rfop[j - 1][i - 1] = 1.0;
1867 148 : wm->rbop[i - 1][j - 1] = 1.0;
1868 : } else {
1869 23702 : wm->top[j - 1][i - 1] = wm->top[j - 2][i - 1] * wm->top[j - 1][j - 1] / denom;
1870 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;
1871 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;
1872 : }
1873 : }
1874 : }
1875 : // System properties: transmittance, front and back reflectance
1876 23850 : tt = wm->top[n - 1][0];
1877 23850 : rft = wm->rfop[n - 1][0];
1878 23850 : rbt = wm->rbop[0][n - 1];
1879 :
1880 : // Absorptance in each layer
1881 71550 : for (int j = 1; j <= n; ++j) {
1882 47700 : if (j == 1) {
1883 23850 : t0 = 1.0;
1884 23850 : rb0 = 0.0;
1885 : } else {
1886 23850 : t0 = wm->top[j - 2][0];
1887 23850 : rb0 = wm->rbop[0][j - 2];
1888 : }
1889 :
1890 47700 : if (j == n) {
1891 23850 : rf0 = 0.0;
1892 : } else {
1893 23850 : rf0 = wm->rfop[n - 1][j];
1894 : }
1895 :
1896 47700 : af = 1.0 - wm->top[j - 1][j - 1] - wm->rfop[j - 1][j - 1];
1897 47700 : ab = 1.0 - wm->top[j - 1][j - 1] - wm->rbop[j - 1][j - 1];
1898 47700 : denom1 = 1.0 - wm->rfop[n - 1][j - 1] * rb0;
1899 47700 : denom2 = 1.0 - wm->rbop[0][j - 1] * rf0;
1900 :
1901 47700 : if (denom1 == 0.0 || denom2 == 0.0) {
1902 296 : aft(j) = 0.0;
1903 : } else {
1904 47404 : aft(j) = (t0 * af) / denom1 + (wm->top[j - 1][0] * rf0 * ab) / denom2;
1905 : }
1906 : }
1907 23850 : } // SystemPropertiesAtLambdaAndPhi()
1908 :
1909 1950 : Real64 solarSpectrumAverage(EnergyPlusData const &state, gsl::span<Real64 const> p)
1910 : {
1911 1950 : Real64 num = 0.0;
1912 1950 : Real64 denom = 0.0;
1913 1950 : auto const &wm = state.dataWindowManager;
1914 :
1915 208650 : for (int i = 1; i <= nume - 1; ++i) {
1916 206700 : Real64 const esol = (wm->wle[i] - wm->wle[i - 1]) * 0.5 * (wm->e[i - 1] + wm->e[i]);
1917 206700 : num += 0.5 * (p[i - 1] + p[i]) * esol;
1918 206700 : denom += esol;
1919 : }
1920 1950 : return num / denom; // dangerous, doesn't check for zero denominator
1921 : }
1922 :
1923 1050 : Real64 visibleSpectrumAverage(EnergyPlusData const &state, gsl::span<Real64 const> p)
1924 : {
1925 : // AUTHOR Adapted by F.Winkelmann from WINDOW 5
1926 : // subroutine w4vis
1927 : // DATE WRITTEN August 1999
1928 :
1929 : // Calculates visible average of property p by weighting with solar
1930 : // spectral irradiance, e, and photopic response, y30
1931 :
1932 1050 : Real64 num = 0.0;
1933 1050 : Real64 denom = 0.0;
1934 1050 : Real64 y30new = 0.0;
1935 1050 : Real64 y30ils1 = 0.0;
1936 :
1937 1050 : auto const &wm = state.dataWindowManager;
1938 :
1939 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
1940 : // values prevented this violation from occurring in practice
1941 : // Restrict to visible range
1942 111300 : if (wm->wle[i - 1] >= 0.37 && wm->wle[i - 1] <= 0.78) {
1943 36750 : y30new = Interpolate(wm->wlt3, wm->y30, numt3, wm->wle[i - 1]);
1944 36750 : Real64 evis = wm->e[i - 2] * 0.5 * (y30new + y30ils1) * (wm->wle[i - 1] - wm->wle[i - 2]);
1945 36750 : num += 0.5 * (p[i - 1] + p[i - 2]) * evis;
1946 36750 : denom += evis;
1947 36750 : y30ils1 = y30new;
1948 : }
1949 : }
1950 1050 : return num / denom; // dangerous, doesn't check for zero denominator
1951 : }
1952 :
1953 75270 : Real64 Interpolate(gsl::span<Real64 const> x, // Array of data points for independent variable
1954 : gsl::span<Real64 const> y, // Array of data points for dependent variable
1955 : int const npts, // Number of data pairs
1956 : Real64 const xin // Given value of x
1957 : )
1958 : {
1959 :
1960 : // SUBROUTINE INFORMATION:
1961 : // AUTHOR Adapted by F.Winkelmann from WINDOW 5 subroutine interp
1962 : // DATE WRITTEN August 1999
1963 : // MODIFIED na
1964 : // RE-ENGINEERED na
1965 :
1966 : // PURPOSE OF THIS SUBROUTINE:
1967 : // Linearly interpolates between data points. Outputs yout, interpolated
1968 : // value of y corresponding to xin
1969 :
1970 4660920 : for (int i = 1; i <= npts; ++i) {
1971 4660680 : if (xin <= x[i - 1]) {
1972 75030 : if (i - 1 == 0) {
1973 2460 : return y[0];
1974 : } else {
1975 72570 : return y[i - 2] + (y[i - 1] - y[i - 2]) * (xin - x[i - 2]) / (x[i - 1] - x[i - 2]);
1976 : }
1977 : }
1978 : }
1979 :
1980 : // Past the end of the array, so return endpoint
1981 240 : return y[npts - 1];
1982 : }
1983 :
1984 : //***********************************************************************************
1985 : // Window Thermal Calculation Subroutines
1986 : //***********************************************************************************
1987 :
1988 88568 : void CalcWindowHeatBalance(EnergyPlusData &state,
1989 : int const SurfNum, // Surface number
1990 : Real64 const HextConvCoeff, // Outside air film conductance coefficient
1991 : Real64 &SurfInsideTemp, // Inside window surface temperature
1992 : Real64 &SurfOutsideTemp // Outside surface temperature (C)
1993 : )
1994 : {
1995 : // SUBROUTINE INFORMATION:
1996 : // AUTHOR S. Vidanovic
1997 : // DATE WRITTEN June 2016
1998 : // MODIFIED na
1999 : // RE-ENGINEERED na
2000 : //
2001 : // PURPOSE OF THIS SUBROUTINE:
2002 : // Subroutine to direct whether to use exterior or interior window routines
2003 88568 : auto const &wm = state.dataWindowManager;
2004 :
2005 88568 : if (state.dataGlobal->KickOffSizing || state.dataGlobal->KickOffSimulation) return;
2006 :
2007 88247 : if (wm->inExtWindowModel->isExternalLibraryModel()) {
2008 0 : CalcWindowHeatBalanceExternalRoutines(state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp);
2009 : } else {
2010 88247 : CalcWindowHeatBalanceInternalRoutines(state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp);
2011 : }
2012 : }
2013 :
2014 88247 : void CalcWindowHeatBalanceInternalRoutines(EnergyPlusData &state,
2015 : int const SurfNum, // Surface number
2016 : Real64 const HextConvCoeff, // Outside air film conductance coefficient
2017 : Real64 &SurfInsideTemp, // Inside window surface temperature
2018 : Real64 &SurfOutsideTemp // Outside surface temperature (C)
2019 : )
2020 : {
2021 :
2022 : // SUBROUTINE INFORMATION:
2023 : // AUTHOR F. Winkelmann
2024 : // DATE WRITTEN November 1999
2025 : // MODIFIED FW, July 2000 (call better solution method)
2026 : // FW, June 2001 (handle window blinds)
2027 : // FW, Dec 2002 (add between-glass shades and blinds)
2028 : // FW, Mar 2003 (extend condensation flag to airflow windows)
2029 : // CC, Jul 2003 (set the reference temperatures for inside surface heat balance
2030 : // depending on convection algorithms and/or air models used)
2031 : // FW, Sep 2003 (increment ZoneWinHeatGain only for exterior windows)
2032 : // RR, May 2006 (add exterior window screen)
2033 : // TH, Dec 2008 (add thermochromic windows)
2034 : // RE-ENGINEERED na
2035 :
2036 : // PURPOSE OF THIS SUBROUTINE:
2037 : // Sets up information needed to calculate the window thermal behavior.
2038 : // Calls SolveForWindowTemperatures, which calculates the inside and outside
2039 : // face temperature of each glass layer by solving the heat balance
2040 : // equations on each face. Also calls CalcWinFrameAndDividerTemps,
2041 : // which calculates the outside and inside face temperatures of the
2042 : // window frame and divider if either of these are present.
2043 : // The resulting inside face temperature of the inner glass pane and the
2044 : // inside surface temperatures of frame and divider are used in the zone
2045 : // heat balance calculation. The inside face temperature of an interior shade
2046 : // or blind, if present, and the natural convection air flow between the
2047 : // shade/blind and inside glass face also appear in the zone heat balance calculation.
2048 : // The logical variable NRSolution is currently set to false, which means
2049 : // that the Newton-Raphson solution method for the glass layer heat balance
2050 : // is not used (because it sometimes didn't converge for 3- and 4-pane
2051 : // constructions with one or more low-emissivity layers). Instead, a more
2052 : // robust solution method is used that successively solves linearized heat
2053 : // balance equations until convergence is reached (see SolveForWindowTemperatures).
2054 : // CalcWindowHeatBalance is called by CalcHeatBalanceInsideSurface once each
2055 : // time step for each window.
2056 :
2057 : // Using/Aliasing
2058 : using namespace DataBSDFWindow;
2059 :
2060 : // SUBROUTINE ARGUMENT DEFINITIONS:
2061 : // (temperature of innermost face) [C]
2062 :
2063 : int SurfNumAdj; // An interzone surface's number in the adjacent zone
2064 : // (sum of solid layers and gap layers)
2065 : int TotGlassLay; // Total number of glass layers in a construction
2066 : int LayPtr; // Material number for a layer
2067 : WinShadingType ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position
2068 : // REAL(r64) :: tsky ! Sky temperature [K]
2069 : int ShadeLayPtr; // Material number corresponding to a shade layer
2070 : Real64 dth1; // Temperature difference across glass layers [K]
2071 : Real64 dth2;
2072 : Real64 dth3;
2073 : Real64 dth4;
2074 : Real64 EffShBlEmiss; // Effective interior shade or blind emissivity
2075 : Real64 EffGlEmiss; // Effective inside glass emissivity when interior shade or blind
2076 : Real64 RoomHumRat; // Room air humidity ratio
2077 : Real64 RoomDewPoint; // Room air dewpoint temperature (C)
2078 : Real64 InsideGlassTemp; // Temperature of room side of innermost glass layer (C)
2079 : Real64 Tleft; // For airflow windows, temperature of the glass faces adjacent
2080 : Real64 Tright;
2081 :
2082 : Real64 SrdSurfTempAbs; // Absolute temperature of a surrounding surface
2083 : Real64 OutSrdIR; // LWR from surrounding srfs
2084 :
2085 : // New variables for thermochromic windows calc
2086 : Real64 locTCSpecTemp; // The temperature corresponding to the specified optical properties of the TC layer
2087 : Real64 locTCLayerTemp; // TC layer temperature at each time step. C
2088 :
2089 88247 : auto &s_mat = state.dataMaterial;
2090 88247 : auto &s_surf = state.dataSurface;
2091 88247 : auto &wm = state.dataWindowManager;
2092 :
2093 : Real64 SurfOutsideEmiss; // temporary for result of outside surface emissivity
2094 : Real64 Tsout; // temporary for result of outside surface temp in Kelvin
2095 :
2096 : // Shorthand references
2097 88247 : auto &surf = s_surf->Surface(SurfNum);
2098 88247 : auto &surfWin = s_surf->SurfaceWindow(SurfNum);
2099 88247 : int ConstrNum = s_surf->SurfActiveConstruction(SurfNum);
2100 88247 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(surf.Zone);
2101 :
2102 88247 : if (s_surf->SurfWinWindowModelType(SurfNum) == WindowModel::BSDF) {
2103 :
2104 0 : int temp = 0;
2105 :
2106 : // Simon: Complex fenestration state works only with tarcog
2107 0 : WindowComplexManager::CalcComplexWindowThermal(
2108 : state, SurfNum, temp, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp, SurfOutsideEmiss, DataBSDFWindow::Condition::Invalid);
2109 :
2110 0 : auto const &constr = state.dataConstruction->Construct(ConstrNum);
2111 0 : wm->ngllayer = constr.TotSolidLayers; // Simon: This is necessary to keep for frame calculations
2112 : // Simon: need to transfer surface temperatures because of frames calculation
2113 :
2114 0 : for (int i = 1; i <= 2 * constr.TotSolidLayers; ++i) {
2115 0 : wm->thetas[i - 1] = surfWin.thetaFace[i];
2116 : }
2117 0 : wm->hcout = HextConvCoeff;
2118 0 : wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
2119 0 : wm->tin = thisZoneHB.MAT + Constant::Kelvin; // Inside air temperature
2120 :
2121 : // This is code repeating and it is necessary to calculate report variables. Do not know
2122 : // how to solve this in more elegant way :(
2123 0 : if (surf.ExtWind) { // Window is exposed to wind (and possibly rain)
2124 0 : if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
2125 0 : wm->tout = s_surf->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
2126 : } else { // Dry
2127 0 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2128 : }
2129 : } else { // Window not exposed to wind
2130 0 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2131 : }
2132 :
2133 0 : wm->Ebout = Constant::StefanBoltzmann * pow_4(wm->tout);
2134 0 : wm->Outir =
2135 0 : surf.ViewFactorSkyIR * (s_surf->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(state.dataEnvrn->SkyTempKelvin) +
2136 0 : (1.0 - s_surf->SurfAirSkyRadSplit(SurfNum)) * wm->Ebout) +
2137 0 : surf.ViewFactorGroundIR * wm->Ebout;
2138 :
2139 88247 : } else if (s_surf->SurfWinWindowModelType(SurfNum) == WindowModel::EQL) {
2140 :
2141 2352 : WindowEquivalentLayer::EQLWindowSurfaceHeatBalance(
2142 : state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp, SurfOutsideEmiss, DataBSDFWindow::Condition::Invalid);
2143 2352 : wm->hcout = HextConvCoeff;
2144 : // Required for report variables calculations.
2145 2352 : if (surf.ExtWind) { // Window is exposed to wind (and possibly rain)
2146 2352 : if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
2147 0 : wm->tout = s_surf->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
2148 : } else { // Dry
2149 2352 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2150 : }
2151 : } else { // Window not exposed to wind
2152 0 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2153 : }
2154 :
2155 : } else { // regular window, not BSDF, not EQL Window
2156 : // Added for thermochromic windows
2157 85895 : auto const &constr = state.dataConstruction->Construct(ConstrNum);
2158 85895 : wm->locTCFlag = (constr.isTCWindow);
2159 :
2160 85895 : if (wm->locTCFlag) {
2161 0 : locTCSpecTemp = constr.specTemp;
2162 0 : s_surf->SurfWinSpecTemp(SurfNum) = locTCSpecTemp;
2163 : // Check to see whether needs to switch to a new TC window construction
2164 0 : locTCLayerTemp = s_surf->SurfWinTCLayerTemp(SurfNum);
2165 0 : Real64 dT0 = std::abs(locTCLayerTemp - locTCSpecTemp);
2166 0 : if (dT0 >= 1) {
2167 :
2168 : // Find the TC construction that is closed to the TCLayerTemp
2169 0 : auto const &constrTCMaster = state.dataConstruction->Construct(constr.TCMasterConstrNum);
2170 :
2171 0 : for (int iTCConstr = 1; iTCConstr <= constrTCMaster.numTCChildConstrs; ++iTCConstr) {
2172 0 : Real64 dT1 = std::abs(locTCLayerTemp - constrTCMaster.TCChildConstrs(iTCConstr).specTemp);
2173 :
2174 0 : if (dT1 < dT0) {
2175 0 : surf.Construction = s_surf->SurfActiveConstruction(SurfNum) = constrTCMaster.TCChildConstrs(iTCConstr).constrNum;
2176 0 : s_surf->SurfWinSpecTemp(SurfNum) = constrTCMaster.TCChildConstrs(iTCConstr).specTemp;
2177 0 : dT0 = dT1;
2178 : }
2179 : }
2180 : }
2181 : }
2182 : // end new TC code
2183 :
2184 85895 : TotGlassLay = constr.TotGlassLayers;
2185 85895 : wm->ngllayer = TotGlassLay;
2186 85895 : wm->nglface = 2 * wm->ngllayer;
2187 85895 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
2188 85895 : wm->tilt = surf.Tilt;
2189 85895 : wm->tiltr = wm->tilt * Constant::DegToRad;
2190 85895 : SurfNumAdj = surf.ExtBoundCond;
2191 85895 : wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum); // Room-side surface convective film conductance
2192 85895 : Real64 RefAirTemp = s_surf->Surface(SurfNum).getInsideAirTemperature(state, SurfNum);
2193 85895 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = RefAirTemp;
2194 85895 : wm->tin = RefAirTemp + Constant::Kelvin; // Inside air temperature
2195 :
2196 : // Reset hcin if necessary since too small a value sometimes causes non-convergence
2197 : // of window layer heat balance solution.
2198 85895 : if (s_surf->surfIntConv(SurfNum).model == Convect::HcInt::SetByZone) {
2199 : // may be redundant now, check is also in HeatBalanceConvectionCoeffs.cc
2200 85895 : if (wm->hcin <= state.dataHeatBal->LowHConvLimit) {
2201 : // hcin = 3.076d0 !BG this is rather high value and abrupt change. changed to set to lower limit
2202 101 : wm->hcin = state.dataHeatBal->LowHConvLimit;
2203 101 : state.dataHeatBalSurf->SurfHConvInt(SurfNum) = wm->hcin; // store for accurate reporting.
2204 : }
2205 : }
2206 :
2207 : // IR incident on window from zone surfaces and high-temp radiant sources
2208 85895 : wm->Rmir = s_surf->SurfWinIRfromParentZone(SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum);
2209 :
2210 : // Short-wave radiation (from interior and exterior solar and zone lights)
2211 : // absorbed at each face. Assumes equal split between faces of short-wave absorbed in glass layer.
2212 :
2213 195987 : for (int IGlass = 1; IGlass <= TotGlassLay; ++IGlass) {
2214 110092 : wm->AbsRadGlassFace[2 * IGlass - 2] = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, IGlass) / 2.0;
2215 110092 : wm->AbsRadGlassFace[2 * IGlass - 1] = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, IGlass) / 2.0;
2216 : }
2217 :
2218 : // IR from zone internal gains (lights, equipment and people) absorbed on zone-side face
2219 : // (assumes inside glass layer is opaque to IR, so no contribution to other layers)
2220 85895 : wm->AbsRadGlassFace[2 * TotGlassLay - 1] += state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNum);
2221 :
2222 : // Fill the layer properties needed for the thermal calculation.
2223 : // For switchable glazing it is assumed that thermal properties, such
2224 : // as surface emissivity, are the same for the unswitched and switched state,
2225 : // so the thermal properties of the unswitched state are used.
2226 : // For windows with a blind or shade it is assumed
2227 : // that the blind or shade does not affect the thermal properties of the glazing,
2228 : // so the thermal properties of the construction without the blind or shade are used.
2229 :
2230 : // The layer and face numbering are as follows (for the triple glazing case):
2231 : // Glass layers are 1,2 and 3, where 1 is the outside (outside environment facing)
2232 : // layer and 3 is the inside (room-facing) layer;
2233 : // Faces (also called surfaces) are 1,2,3,4,5 and 6, where face 1 is the
2234 : // outside (front) face of glass layer 1, face 2 is the inside (back)
2235 : // face of glass layer 1, face 3 is the outer face of glass layer 2, face 4 is the
2236 : // inner face of glass layer 2, etc.
2237 : // Gap layers are 1 and 2, where gap layer 1 is between glass layers 1 and 2
2238 : // and gap layer 2 is between glass layers 2 and 3.
2239 : // If an exterior, interior or between-glass blind or shade is in place, 7 and 8
2240 : // are the blind/shade faces, from outside to inside. If an exterior or interior
2241 : // blind/shade is in place, gap layer 3 is between the blind/shade and adjacent
2242 : // glass layer and is assumed to be air.
2243 : // Between-glass blind/shade is modeled only for double and triple glazing.
2244 : // For double glazing, gap 1 is between glass 1 and blind/shade and gap 2 is between
2245 : // blind/shade and glass 2.
2246 : // For triple glazing, the blind/shade is assumed to be between the inner two glass
2247 : // layers, i.e., between glass layers 2 and 3. In this case gap 1 is between glass 1
2248 : // and glass 2, gap 2 is between glass 2 and blind/shade, and gap 3 is between
2249 : // blind/shade and glass 3.
2250 :
2251 85895 : int IConst = surf.Construction;
2252 85895 : if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
2253 0 : IConst = s_surf->SurfWinActiveShadedConstruction(SurfNum);
2254 : }
2255 85895 : int TotLay = state.dataConstruction->Construct(IConst).TotLayers;
2256 85895 : int IGlass = 0;
2257 85895 : int IGap = 0;
2258 :
2259 : // Fill window layer properties needed for window layer heat balance calculation
2260 :
2261 220186 : for (int Lay = 1; Lay <= TotLay; ++Lay) {
2262 134291 : LayPtr = state.dataConstruction->Construct(IConst).LayerPoint(Lay);
2263 134291 : auto const *mat = s_mat->materials(LayPtr);
2264 :
2265 134291 : if (mat->group == Material::Group::Glass || mat->group == Material::Group::GlassSimple) {
2266 110092 : ++IGlass;
2267 110092 : auto const *matGlass = dynamic_cast<Material::MaterialFen const *>(mat);
2268 110092 : assert(matGlass != nullptr);
2269 110092 : wm->thick[IGlass - 1] = matGlass->Thickness;
2270 110092 : wm->scon[IGlass - 1] = matGlass->Conductivity / matGlass->Thickness;
2271 110092 : wm->emis[2 * IGlass - 2] = matGlass->AbsorpThermalFront;
2272 110092 : wm->emis[2 * IGlass - 1] = matGlass->AbsorpThermalBack;
2273 110092 : wm->tir[2 * IGlass - 2] = matGlass->TransThermal;
2274 110092 : wm->tir[2 * IGlass - 1] = matGlass->TransThermal;
2275 :
2276 134291 : } else if (mat->group == Material::Group::Shade || mat->group == Material::Group::Blind || mat->group == Material::Group::Screen) {
2277 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag))
2278 0 : ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers);
2279 0 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1);
2280 0 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
2281 0 : ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(3);
2282 0 : if (TotGlassLay == 3) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(5);
2283 : }
2284 0 : auto const *matShade = dynamic_cast<Material::MaterialFen const *>(s_mat->materials(ShadeLayPtr));
2285 0 : assert(matShade != nullptr);
2286 :
2287 0 : if (ANY_SHADE_SCREEN(ShadeFlag)) {
2288 : // Shade or screen on
2289 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
2290 : // check to make sure the user hasn't messed up the shade control values
2291 0 : if (matShade->group == Material::Group::Blind) {
2292 0 : ShowSevereError(
2293 : state,
2294 0 : format("CalcWindowHeatBalance: ShadeFlag indicates Shade but Blind=\"{}\" is being used.", matShade->Name));
2295 0 : ShowContinueError(state, "This is most likely a fault of the EMS values for shading control.");
2296 0 : ShowFatalError(state, "Preceding condition terminates program.");
2297 : }
2298 : }
2299 0 : wm->thick[TotGlassLay] = matShade->Thickness;
2300 0 : wm->scon[TotGlassLay] = matShade->Conductivity / matShade->Thickness;
2301 :
2302 0 : if (ShadeFlag == WinShadingType::ExtScreen) {
2303 0 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(matShade);
2304 0 : assert(matScreen != nullptr);
2305 0 : wm->emis[wm->nglface] = matScreen->AbsorpThermalFront;
2306 0 : wm->tir[wm->nglface] = matScreen->DfTrans;
2307 0 : wm->tir[wm->nglface + 1] = matScreen->DfTrans;
2308 : } else {
2309 0 : wm->emis[wm->nglface] = matShade->AbsorpThermal;
2310 0 : wm->tir[wm->nglface] = matShade->TransThermal;
2311 0 : wm->tir[wm->nglface + 1] = matShade->TransThermal;
2312 : }
2313 0 : wm->emis[wm->nglface + 1] = matShade->AbsorpThermal;
2314 :
2315 : } else {
2316 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
2317 : // check to make sure the user hasn't messed up the shade control values
2318 0 : if (matShade->group == Material::Group::Shade || matShade->group == Material::Group::Screen) {
2319 0 : ShowSevereError(state,
2320 0 : format("CalcWindowHeatBalance: ShadeFlag indicates Blind but Shade/Screen=\"{}\" is being used.",
2321 0 : matShade->Name));
2322 0 : ShowContinueError(state, "This is most likely a fault of the EMS values for shading control.");
2323 0 : ShowFatalError(state, "Preceding condition terminates program.");
2324 : }
2325 : }
2326 :
2327 : // Blind on
2328 0 : auto &surfShade = s_surf->surfShades(SurfNum);
2329 0 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(surfShade.blind.matNum));
2330 0 : assert(matBlind != nullptr);
2331 0 : wm->thick[TotGlassLay] = matBlind->SlatThickness;
2332 0 : wm->scon[TotGlassLay] = matBlind->SlatConductivity / matBlind->SlatThickness;
2333 :
2334 0 : wm->emis[wm->nglface] = surfShade.blind.TAR.IR.Ft.Emi;
2335 0 : wm->emis[wm->nglface + 1] = surfShade.blind.TAR.IR.Bk.Emi;
2336 0 : wm->tir[wm->nglface] = surfShade.blind.TAR.IR.Ft.Tra;
2337 0 : wm->tir[wm->nglface + 1] = surfShade.blind.TAR.IR.Bk.Tra;
2338 : }
2339 :
2340 24199 : } else if (mat->group == Material::Group::Gas || mat->group == Material::Group::GasMixture) {
2341 24196 : ++IGap;
2342 24196 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(s_mat->materials(LayPtr));
2343 24196 : assert(matGas != nullptr);
2344 24196 : wm->gaps[IGap - 1].width = matGas->Thickness;
2345 24196 : wm->gaps[IGap - 1].numGases = matGas->numGases;
2346 48392 : for (int IMix = 0; IMix < wm->gaps[IGap - 1].numGases; ++IMix) {
2347 24196 : wm->gaps[IGap - 1].gases[IMix] = matGas->gases[IMix];
2348 24196 : wm->gaps[IGap - 1].gasFracts[IMix] = matGas->gasFracts[IMix];
2349 : }
2350 : }
2351 :
2352 : } // End of loop over glass, gap and blind/shade layers in a window construction
2353 :
2354 85895 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2355 : // Interior or exterior blind, shade or screen is on.
2356 : // Fill gap between blind/shade and adjacent glass with air properties.
2357 0 : ++IGap;
2358 0 : wm->gaps[IGap - 1].width = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(ShadeLayPtr))->toGlassDist;
2359 0 : wm->gaps[IGap - 1].numGases = 1;
2360 :
2361 0 : wm->gaps[IGap - 1].gases[0] = Material::gases[(int)Material::GasType::Air];
2362 0 : wm->gaps[IGap - 1].gasFracts[0] = 1;
2363 : }
2364 :
2365 : // Exterior convection coefficient, exterior air temperature and IR radiance
2366 : // of exterior surround. Depend on whether window is interzone (in an interzone
2367 : // wall or exterior (in an exterior wall).
2368 :
2369 85895 : wm->hcout = HextConvCoeff; // Exterior convection coefficient is passed in from outer routine
2370 : // tsky = SkyTemp + TKelvin
2371 :
2372 85895 : if (SurfNumAdj > 0) { // Interzone window
2373 :
2374 0 : RefAirTemp = s_surf->Surface(SurfNumAdj).getInsideAirTemperature(state, SurfNumAdj);
2375 0 : state.dataHeatBal->SurfTempEffBulkAir(SurfNumAdj) = RefAirTemp;
2376 0 : wm->tout = RefAirTemp + Constant::Kelvin; // outside air temperature
2377 :
2378 : // Add long-wave radiation from adjacent zone absorbed by glass layer closest to the adjacent zone.
2379 0 : wm->AbsRadGlassFace[0] += state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNumAdj);
2380 :
2381 : // The IR radiance of this window's "exterior" surround is the IR radiance
2382 : // from surfaces and high-temp radiant sources in the adjacent zone
2383 :
2384 0 : wm->Outir = s_surf->SurfWinIRfromParentZone(SurfNumAdj) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNumAdj);
2385 :
2386 : } else { // Exterior window (Ext BoundCond = 0)
2387 : // Calculate LWR from surrounding surfaces if defined for an exterior window
2388 85895 : OutSrdIR = 0;
2389 85895 : if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
2390 1 : if (s_surf->Surface(SurfNum).SurfHasSurroundingSurfProperty) {
2391 1 : SrdSurfTempAbs = surf.SrdSurfTemp + Constant::Kelvin;
2392 1 : OutSrdIR = Constant::StefanBoltzmann * surf.ViewFactorSrdSurfs * pow_4(SrdSurfTempAbs);
2393 : }
2394 : }
2395 85895 : if (surf.ExtWind) { // Window is exposed to wind (and possibly rain)
2396 85895 : if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
2397 0 : wm->tout = s_surf->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
2398 : } else { // Dry
2399 85895 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2400 : }
2401 : } else { // Window not exposed to wind
2402 0 : wm->tout = s_surf->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2403 : }
2404 85895 : wm->Ebout = Constant::StefanBoltzmann * pow_4(wm->tout);
2405 85895 : wm->Outir =
2406 85895 : surf.ViewFactorSkyIR * (s_surf->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(state.dataEnvrn->SkyTempKelvin) +
2407 85895 : (1.0 - s_surf->SurfAirSkyRadSplit(SurfNum)) * wm->Ebout) +
2408 85895 : surf.ViewFactorGroundIR * wm->Ebout + OutSrdIR;
2409 : }
2410 :
2411 : // Factors used in window layer temperature solution
2412 85895 : if (wm->ngllayer >= 2) {
2413 24197 : wm->A23P = -wm->emis[2] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
2414 24197 : wm->A32P = wm->emis[1] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
2415 24197 : wm->A23 = wm->emis[1] * Constant::StefanBoltzmann * wm->A23P;
2416 : }
2417 :
2418 85895 : if (wm->ngllayer >= 3) {
2419 0 : wm->A45P = -wm->emis[4] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
2420 0 : wm->A54P = wm->emis[3] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
2421 0 : wm->A45 = wm->emis[3] * Constant::StefanBoltzmann * wm->A45P;
2422 : }
2423 :
2424 85895 : if (wm->ngllayer == 4) {
2425 0 : wm->A67P = -wm->emis[6] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
2426 0 : wm->A76P = wm->emis[5] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
2427 0 : wm->A67 = wm->emis[5] * Constant::StefanBoltzmann * wm->A67P;
2428 : }
2429 :
2430 85895 : wm->thetas = {0.0};
2431 85895 : wm->thetasPrev = {0.0};
2432 :
2433 : // Calculate window face temperatures
2434 :
2435 85895 : SolveForWindowTemperatures(state, SurfNum);
2436 :
2437 : // Temperature difference across glass layers (for debugging)
2438 :
2439 85895 : dth1 = wm->thetas[1] - wm->thetas[0];
2440 85895 : dth2 = wm->thetas[3] - wm->thetas[2];
2441 85895 : dth3 = wm->thetas[5] - wm->thetas[4];
2442 85895 : dth4 = wm->thetas[7] - wm->thetas[6];
2443 :
2444 85895 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
2445 0 : auto const &surfShade = s_surf->surfShades(SurfNum);
2446 0 : SurfInsideTemp = wm->thetas[2 * wm->ngllayer + 1] - Constant::Kelvin;
2447 0 : EffShBlEmiss = surfShade.effShadeEmi;
2448 0 : EffGlEmiss = surfShade.effGlassEmi;
2449 :
2450 0 : s_surf->SurfWinEffInsSurfTemp(SurfNum) =
2451 0 : (EffShBlEmiss * SurfInsideTemp + EffGlEmiss * (wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin)) /
2452 0 : (EffShBlEmiss + EffGlEmiss);
2453 : } else {
2454 85895 : SurfInsideTemp = wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin;
2455 : }
2456 85895 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2457 0 : SurfOutsideTemp = wm->thetas[2 * wm->ngllayer] - Constant::Kelvin; // this index looks suspicious (CR 8202)
2458 : // SurfOutsideEmiss = emis(1) ! this index should be coordinated with previous line
2459 0 : SurfOutsideEmiss = wm->emis[2 * wm->ngllayer]; // fix for CR 8202
2460 : } else {
2461 85895 : SurfOutsideEmiss = wm->emis[0];
2462 85895 : SurfOutsideTemp = wm->thetas[0] - Constant::Kelvin;
2463 : }
2464 :
2465 : // Save temperatures for use next time step
2466 :
2467 306079 : for (int k = 1; k <= wm->nglfacep; ++k) {
2468 220184 : surfWin.thetaFace[k] = wm->thetas[k - 1];
2469 : }
2470 :
2471 : // Added TH 12/23/2008 for thermochromic windows to save the current TC layer temperature
2472 85895 : if (wm->locTCFlag) {
2473 0 : s_surf->SurfWinTCLayerTemp(SurfNum) =
2474 0 : (wm->thetas[2 * constr.TCGlassNum - 2] + wm->thetas[2 * constr.TCGlassNum - 1]) / 2 - Constant::Kelvin; // degree C
2475 : }
2476 : } // regular window, not BSDF, not EQL
2477 :
2478 : // Set condensation flag to 1 if condensation expected to occur on the innermost glass face,
2479 : // or, for airflow windows, on either or the two glass faces in the airflow gap
2480 88247 : if (!state.dataConstruction->Construct(surf.Construction).WindowTypeEQL) {
2481 85895 : InsideGlassTemp = wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin;
2482 85895 : RoomHumRat = thisZoneHB.airHumRat;
2483 85895 : RoomDewPoint = Psychrometrics::PsyTdpFnWPb(state, RoomHumRat, state.dataEnvrn->OutBaroPress);
2484 85895 : s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 0;
2485 85895 : if (InsideGlassTemp < RoomDewPoint) s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
2486 : // If airflow window, is there condensation on either glass face of the airflow gap?
2487 85895 : if (s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
2488 0 : Tleft = wm->thetas[2 * wm->ngllayer - 3] - Constant::Kelvin;
2489 0 : Tright = wm->thetas[2 * wm->ngllayer - 2] - Constant::Kelvin;
2490 0 : if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
2491 0 : if (Tleft < RoomDewPoint || Tright < RoomDewPoint) s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
2492 0 : } else if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Outdoor) {
2493 0 : if (Tleft < state.dataEnvrn->OutDewPointTemp || Tright < state.dataEnvrn->OutDewPointTemp)
2494 0 : s_surf->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
2495 : }
2496 : }
2497 :
2498 : // Do frame and divider calculation
2499 85895 : if (s_surf->SurfWinFrameArea(SurfNum) > 0.0 || s_surf->SurfWinDividerArea(SurfNum) > 0.0)
2500 9 : CalcWinFrameAndDividerTemps(state, SurfNum, wm->tout, wm->tin, wm->hcout, wm->hcin, wm->Outir, ConstrNum);
2501 85895 : if (s_surf->SurfWinFrameArea(SurfNum) > 0.0) {
2502 9 : s_surf->SurfWinInsideFrameCondensationFlag(SurfNum) = 0;
2503 9 : if (s_surf->SurfWinFrameTempIn(SurfNum) < RoomDewPoint) s_surf->SurfWinInsideFrameCondensationFlag(SurfNum) = 1;
2504 : }
2505 85895 : if (s_surf->SurfWinDividerArea(SurfNum) > 0.0) {
2506 9 : s_surf->SurfWinInsideDividerCondensationFlag(SurfNum) = 0;
2507 9 : if (s_surf->SurfWinDividerTempIn(SurfNum) < RoomDewPoint) s_surf->SurfWinInsideDividerCondensationFlag(SurfNum) = 1;
2508 : }
2509 : }
2510 : // update exterior environment surface heat loss reporting
2511 88247 : Tsout = SurfOutsideTemp + Constant::Kelvin;
2512 88247 : state.dataHeatBalSurf->SurfQdotConvOutPerArea(SurfNum) = -wm->hcout * (Tsout - wm->tout);
2513 :
2514 88247 : Real64 const Tsout_4(pow_4(Tsout)); // Tuned To reduce pow calls and redundancies
2515 88247 : Real64 const Tout_4(pow_4(wm->tout));
2516 88247 : Real64 const emiss_sigma_product(SurfOutsideEmiss * Constant::StefanBoltzmann);
2517 88247 : Real64 rad_out_lw_srd_per_area = 0;
2518 :
2519 88247 : if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
2520 1 : if (surf.SurfHasSurroundingSurfProperty) {
2521 : // update SurfHSrdSurfExt if the windows has exterior shade or blind
2522 1 : state.dataHeatBalSurf->SurfHSrdSurfExt(SurfNum) =
2523 1 : Convect::SurroundingSurfacesRadCoeffAverage(state, SurfNum, Tsout, SurfOutsideEmiss);
2524 1 : rad_out_lw_srd_per_area = state.dataHeatBalSurf->SurfHSrdSurfExt(SurfNum) * (surf.SrdSurfTemp - SurfOutsideTemp);
2525 : }
2526 : }
2527 :
2528 : Real64 const rad_out_air_per_area =
2529 88247 : -emiss_sigma_product * (1.0 - s_surf->SurfAirSkyRadSplit(SurfNum)) * surf.ViewFactorSkyIR * (Tsout_4 - Tout_4);
2530 88247 : Real64 const rad_out_ground_per_area = -emiss_sigma_product * surf.ViewFactorGroundIR * (Tsout_4 - Tout_4);
2531 : Real64 const rad_out_sky_per_area =
2532 88247 : -emiss_sigma_product * s_surf->SurfAirSkyRadSplit(SurfNum) * surf.ViewFactorSkyIR * (Tsout_4 - pow_4(state.dataEnvrn->SkyTempKelvin));
2533 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;
2534 :
2535 88247 : state.dataHeatBalSurf->SurfHAirExt(SurfNum) = rad_out_air_per_area / (Tsout - wm->tout);
2536 88247 : state.dataHeatBalSurf->SurfQRadLWOutSrdSurfs(SurfNum) = rad_out_lw_srd_per_area;
2537 88247 : state.dataHeatBalSurf->SurfQdotRadOutRepPerArea(SurfNum) = rad_out_per_area;
2538 88247 : } // CalcWindowHeatBalanceInternalRoutines()
2539 :
2540 : //****************************************************************************
2541 :
2542 : //****************************************************************************
2543 :
2544 596 : void GetHeatBalanceEqCoefMatrixSimple(EnergyPlusData &state,
2545 : int const nglasslayer, // Number of glass layers
2546 : Array1D<Real64> const &hr, // Radiative conductance (W/m2-K)
2547 : Array1A<Real64> &hgap, // Gap gas conductive conductance (W/m2-K)
2548 : Array2D<Real64> &Aface, // Coefficient in equation Aface*thetas = Bface
2549 : Array1D<Real64> &Bface // Coefficient in equation Aface*thetas = Bface
2550 : )
2551 : {
2552 : Real64 gr; // Grashof number of gas in a gap
2553 : Real64 con; // Gap gas conductivity
2554 : Real64 pr; // Gap gas Prandtl number
2555 : Real64 nu; // Gap gas Nusselt number
2556 :
2557 596 : auto const &wm = state.dataWindowManager;
2558 :
2559 596 : if (nglasslayer == 1) {
2560 508 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2561 508 : Bface(2) = wm->Rmir * wm->emis[1] + wm->hcin * wm->tin + wm->AbsRadGlassFace[1];
2562 :
2563 508 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2564 508 : Aface(2, 1) = -wm->scon[0];
2565 508 : Aface(1, 2) = -wm->scon[0];
2566 508 : Aface(2, 2) = hr(2) + wm->scon[0] + wm->hcin;
2567 :
2568 88 : } else if (nglasslayer == 2) {
2569 88 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2570 88 : NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2571 88 : hgap(1) = con / wm->gaps[0].width * nu;
2572 :
2573 88 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2574 88 : Bface(2) = wm->AbsRadGlassFace[1];
2575 88 : Bface(3) = wm->AbsRadGlassFace[2];
2576 88 : Bface(4) = wm->Rmir * wm->emis[3] + wm->hcin * wm->tin + wm->AbsRadGlassFace[3];
2577 :
2578 88 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2579 88 : Aface(2, 1) = -wm->scon[0];
2580 :
2581 88 : Aface(1, 2) = -wm->scon[0];
2582 88 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2583 88 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2584 :
2585 88 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2586 88 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2587 88 : Aface(4, 3) = -wm->scon[1];
2588 :
2589 88 : Aface(3, 4) = -wm->scon[1];
2590 88 : Aface(4, 4) = hr(4) + wm->scon[1] + wm->hcin;
2591 :
2592 0 : } else if (nglasslayer == 3) {
2593 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2594 0 : NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2595 0 : hgap(1) = con / wm->gaps[0].width * nu;
2596 :
2597 0 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
2598 0 : NusseltNumber(state, 0, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
2599 0 : hgap(2) = con / wm->gaps[1].width * nu;
2600 :
2601 0 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2602 0 : Bface(2) = wm->AbsRadGlassFace[1];
2603 0 : Bface(3) = wm->AbsRadGlassFace[2];
2604 0 : Bface(4) = wm->AbsRadGlassFace[3];
2605 0 : Bface(5) = wm->AbsRadGlassFace[4];
2606 0 : Bface(6) = wm->Rmir * wm->emis[5] + wm->hcin * wm->tin + wm->AbsRadGlassFace[5];
2607 :
2608 0 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2609 0 : Aface(2, 1) = -wm->scon[0];
2610 :
2611 0 : Aface(1, 2) = -wm->scon[0];
2612 0 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2613 0 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2614 :
2615 0 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2616 0 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2617 0 : Aface(4, 3) = -wm->scon[1];
2618 :
2619 0 : Aface(3, 4) = -wm->scon[1];
2620 0 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
2621 0 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
2622 :
2623 0 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
2624 0 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
2625 0 : Aface(6, 5) = -wm->scon[2];
2626 :
2627 0 : Aface(5, 6) = -wm->scon[2];
2628 0 : Aface(6, 6) = hr(6) + wm->scon[2] + wm->hcin;
2629 :
2630 0 : } else if (nglasslayer == 4) {
2631 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2632 0 : NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2633 0 : hgap(1) = con / wm->gaps[0].width * nu;
2634 :
2635 0 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
2636 0 : NusseltNumber(state, 0, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
2637 0 : hgap(2) = con / wm->gaps[1].width * nu;
2638 :
2639 0 : WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
2640 0 : NusseltNumber(state, 0, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
2641 0 : hgap(3) = con / wm->gaps[2].width * nu;
2642 :
2643 0 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2644 0 : Bface(2) = wm->AbsRadGlassFace[1];
2645 0 : Bface(3) = wm->AbsRadGlassFace[2];
2646 0 : Bface(4) = wm->AbsRadGlassFace[3];
2647 0 : Bface(5) = wm->AbsRadGlassFace[4];
2648 0 : Bface(6) = wm->AbsRadGlassFace[5];
2649 0 : Bface(7) = wm->AbsRadGlassFace[6];
2650 0 : Bface(8) = wm->Rmir * wm->emis[7] + wm->hcin * wm->tin + wm->AbsRadGlassFace[7];
2651 :
2652 0 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2653 0 : Aface(2, 1) = -wm->scon[0];
2654 :
2655 0 : Aface(1, 2) = -wm->scon[0];
2656 0 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2657 0 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2658 :
2659 0 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2660 0 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2661 0 : Aface(4, 3) = -wm->scon[1];
2662 :
2663 0 : Aface(3, 4) = -wm->scon[1];
2664 0 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
2665 0 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
2666 :
2667 0 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
2668 0 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
2669 0 : Aface(6, 5) = -wm->scon[2];
2670 :
2671 0 : Aface(5, 6) = -wm->scon[2];
2672 0 : Aface(6, 6) = wm->scon[2] + hgap(3) - wm->A67P * hr(6);
2673 0 : Aface(7, 6) = -hgap(3) - wm->A76P * hr(7);
2674 :
2675 0 : Aface(6, 7) = -hgap(3) + wm->A67P * hr(6);
2676 0 : Aface(7, 7) = hgap(3) + wm->scon[3] + wm->A76P * hr(7);
2677 0 : Aface(8, 7) = -wm->scon[3];
2678 :
2679 0 : Aface(7, 8) = -wm->scon[3];
2680 0 : Aface(8, 8) = hr(8) + wm->scon[3] + wm->hcin;
2681 : }
2682 596 : } // GetHeatBalanceEqCoefMatrixSimple()
2683 :
2684 149363 : void GetHeatBalanceEqCoefMatrix(EnergyPlusData &state,
2685 : int const SurfNum,
2686 : int const nglasslayer,
2687 : WinShadingType const ShadeFlag,
2688 : Real64 const sconsh,
2689 : Real64 const TauShIR,
2690 : Real64 const EpsShIR1,
2691 : Real64 const EpsShIR2,
2692 : Real64 const RhoShIR1,
2693 : Real64 const RhoShIR2,
2694 : Real64 const ShGlReflFacIR,
2695 : Real64 const RhoGlIR1,
2696 : Real64 const RhoGlIR2,
2697 : Real64 const hcv, // Convection coefficient from gap glass or shade/blind to gap air (W/m2-K)
2698 : Real64 const TGapNew, // Current-iteration average air temp in airflow gap (K)
2699 : Real64 const TAirflowGapNew, // Average air temp in airflow gap between glass panes (K)
2700 : Real64 const hcvAirflowGap, // Convection coefficient from airflow gap glass to airflow gap air (W/m2-K)
2701 : Array1A<Real64> const &hcvBG, // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
2702 : Array1A<Real64> const &TGapNewBG,
2703 : Array1A<Real64> const &AbsRadShadeFace,
2704 : Array1D<Real64> const &hr,
2705 : Array2D<Real64> &Aface,
2706 : Array1D<Real64> &Bface)
2707 : {
2708 149363 : auto &wm = state.dataWindowManager;
2709 :
2710 : Real64 gr; // Grashof number of gas in a gap
2711 : Real64 con; // Gap gas conductivity
2712 : Real64 pr; // Gap gas Prandtl number
2713 : Real64 nu; // Gap gas Nusselt number
2714 :
2715 : Real64 FacRhoIR25; // Intermediate variable
2716 : Real64 FacRhoIR63; // Intermediate variable
2717 : Real64 RhoIRfp; // Intermediate variable
2718 : Real64 RhoIRbp; // Intermediate variable
2719 : Real64 FacRhoIR2fp; // Intermediate variable
2720 : Real64 FacRhoIR3bp; // Intermediate variable
2721 : Real64 FacRhoIR2fpRhoIR63; // Intermediate variable
2722 : Real64 FacRhoIR3bpRhoIR25; // Intermediate variable
2723 : Real64 FacRhoIR47; // Intermediate variable
2724 : Real64 FacRhoIR85; // Intermediate variable
2725 : Real64 FacRhoIR4fp; // Intermediate variable
2726 : Real64 FacRhoIR5bp; // Intermediate variable
2727 : Real64 FacRhoIR4fpRhoIR85; // Intermediate variable
2728 : Real64 FacRhoIR5bpRhoIR47; // Intermediate variable
2729 :
2730 149363 : Array1D<Real64> hgap(maxGlassLayers); // Gap gas conductance (W/m2-K)
2731 :
2732 149363 : auto &s_surf = state.dataSurface;
2733 :
2734 149363 : auto const &surfWin = s_surf->SurfaceWindow(SurfNum);
2735 :
2736 149363 : if (nglasslayer == 1) {
2737 109093 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2738 109093 : Bface(2) = wm->Rmir * wm->emis[1] + wm->hcin * wm->tin + wm->AbsRadGlassFace[1];
2739 :
2740 109093 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2741 109093 : Aface(2, 1) = -wm->scon[0];
2742 109093 : Aface(1, 2) = -wm->scon[0];
2743 109093 : Aface(2, 2) = hr(2) + wm->scon[0] + wm->hcin;
2744 :
2745 109093 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
2746 : // interior shade, single pane
2747 : // || ||
2748 : // outside 1||2 3||4
2749 : // || ||
2750 : // gl bl/sh/sc
2751 0 : Bface(2) = wm->Rmir * wm->emis[1] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[1];
2752 0 : Bface(3) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
2753 0 : Bface(4) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
2754 :
2755 0 : Aface(2, 2) = hr(2) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[0] + hcv;
2756 0 : Aface(3, 2) = -wm->emis[1] * hr(3) / ShGlReflFacIR;
2757 0 : Aface(2, 3) = -hr(2) * EpsShIR1 / ShGlReflFacIR;
2758 0 : Aface(3, 3) = hr(3) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
2759 0 : Aface(4, 3) = -sconsh;
2760 0 : Aface(3, 4) = -sconsh;
2761 0 : Aface(4, 4) = hr(4) + sconsh + wm->hcin;
2762 : }
2763 :
2764 109093 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2765 : // exterior shade, single pane
2766 : // || ||
2767 : // outside 3||4 1||2
2768 : // || ||
2769 : // bl/sh/sc gl
2770 0 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
2771 0 : Bface(3) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
2772 0 : Bface(4) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
2773 :
2774 0 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
2775 0 : Aface(4, 1) = -wm->emis[0] * hr(4) / ShGlReflFacIR;
2776 0 : Aface(3, 3) = hr(3) + sconsh + wm->hcout;
2777 0 : Aface(4, 3) = -sconsh;
2778 0 : Aface(1, 4) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
2779 0 : Aface(3, 4) = -sconsh;
2780 0 : Aface(4, 4) = hr(4) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
2781 : }
2782 :
2783 40270 : } else if (nglasslayer == 2) {
2784 40270 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2785 40270 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2786 40270 : hgap(1) = con / wm->gaps[0].width * nu;
2787 40270 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
2788 0 : wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
2789 0 : hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
2790 : }
2791 :
2792 40270 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2793 40270 : Bface(2) = wm->AbsRadGlassFace[1];
2794 40270 : Bface(3) = wm->AbsRadGlassFace[2];
2795 40270 : Bface(4) = wm->Rmir * wm->emis[3] + wm->hcin * wm->tin + wm->AbsRadGlassFace[3];
2796 :
2797 40270 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2798 40270 : Aface(2, 1) = -wm->scon[0];
2799 :
2800 40270 : Aface(1, 2) = -wm->scon[0];
2801 40270 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2802 40270 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2803 :
2804 40270 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2805 40270 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2806 40270 : Aface(4, 3) = -wm->scon[1];
2807 :
2808 40270 : Aface(3, 4) = -wm->scon[1];
2809 40270 : Aface(4, 4) = hr(4) + wm->scon[1] + wm->hcin;
2810 :
2811 40270 : if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
2812 0 : Bface(2) = wm->AbsRadGlassFace[1] + hcvAirflowGap * TAirflowGapNew;
2813 0 : Bface(3) = wm->AbsRadGlassFace[2] + hcvAirflowGap * TAirflowGapNew;
2814 0 : Aface(2, 2) = wm->scon[0] + hcvAirflowGap - wm->A23P * hr(2);
2815 0 : Aface(3, 2) = -wm->A32P * hr(3);
2816 0 : Aface(2, 3) = wm->A23P * hr(2);
2817 0 : Aface(3, 3) = hcvAirflowGap + wm->scon[1] + wm->A32P * hr(3);
2818 : }
2819 :
2820 40270 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
2821 0 : Bface(4) = wm->Rmir * wm->emis[3] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[3];
2822 0 : Bface(5) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
2823 0 : Bface(6) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
2824 :
2825 0 : Aface(4, 4) = hr(4) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[1] + hcv;
2826 0 : Aface(5, 4) = -wm->emis[3] * hr(5) / ShGlReflFacIR;
2827 0 : Aface(4, 5) = -hr(4) * EpsShIR1 / ShGlReflFacIR;
2828 0 : Aface(5, 5) = hr(5) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
2829 0 : Aface(6, 5) = -sconsh;
2830 0 : Aface(5, 6) = -sconsh;
2831 0 : Aface(6, 6) = hr(6) + sconsh + wm->hcin;
2832 : }
2833 :
2834 40270 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2835 0 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
2836 0 : Bface(5) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
2837 0 : Bface(6) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
2838 :
2839 0 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
2840 0 : Aface(6, 1) = -wm->emis[0] * hr(6) / ShGlReflFacIR;
2841 0 : Aface(5, 5) = hr(5) + sconsh + wm->hcout;
2842 0 : Aface(6, 5) = -sconsh;
2843 0 : Aface(1, 6) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
2844 0 : Aface(5, 6) = -sconsh;
2845 0 : Aface(6, 6) = hr(6) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
2846 : }
2847 :
2848 40270 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
2849 0 : Array1D<Real64> RhoIR(6); // Face IR reflectance
2850 :
2851 0 : for (int i = 1; i <= 6; ++i) {
2852 0 : RhoIR(i) = max(0.0, 1.0 - wm->tir[i - 1] - wm->emis[i - 1]);
2853 : }
2854 0 : FacRhoIR25 = 1.0 - RhoIR(2) * RhoIR(5);
2855 0 : FacRhoIR63 = 1.0 - RhoIR(6) * RhoIR(3);
2856 0 : Real64 const tir_5_squared(pow_2(wm->tir[4]));
2857 0 : RhoIRfp = RhoIR(5) + tir_5_squared * RhoIR(3) / FacRhoIR63;
2858 0 : RhoIRbp = RhoIR(6) + tir_5_squared * RhoIR(2) / FacRhoIR25;
2859 0 : FacRhoIR2fp = 1.0 - RhoIRfp * RhoIR(2);
2860 0 : FacRhoIR3bp = 1.0 - RhoIRbp * RhoIR(3);
2861 0 : FacRhoIR2fpRhoIR63 = FacRhoIR2fp * FacRhoIR63;
2862 0 : FacRhoIR3bpRhoIR25 = FacRhoIR3bp * FacRhoIR25;
2863 0 : Aface(2, 2) = wm->scon[0] + hcvBG(1) + hr(2) * (1 - RhoIRfp * (wm->emis[1] + RhoIR(2))) / FacRhoIR2fp;
2864 0 : Aface(3, 2) = -wm->emis[1] * hr(3) * wm->tir[4] / FacRhoIR2fpRhoIR63;
2865 0 : Aface(5, 2) = -wm->emis[1] * hr(5) / FacRhoIR2fp;
2866 0 : Aface(6, 2) = -wm->emis[1] * hr(6) * RhoIR(3) * wm->tir[4] / FacRhoIR2fpRhoIR63;
2867 0 : Bface(2) = hcvBG(1) * TGapNewBG(1) + wm->AbsRadGlassFace[1];
2868 0 : Aface(2, 3) = -wm->emis[2] * hr(2) * wm->tir[4] / FacRhoIR3bpRhoIR25;
2869 0 : Aface(3, 3) = wm->scon[1] + hcvBG(2) + hr(3) * (1 - RhoIRbp * (wm->emis[2] + RhoIR(3))) / FacRhoIR3bp;
2870 0 : Aface(5, 3) = -wm->emis[2] * hr(5) * RhoIR(2) * wm->tir[4] / FacRhoIR3bpRhoIR25;
2871 0 : Aface(6, 3) = -wm->emis[2] * hr(6) / FacRhoIR3bp;
2872 0 : Bface(3) = hcvBG(2) * TGapNewBG(2) + wm->AbsRadGlassFace[2];
2873 0 : Aface(2, 5) = -wm->emis[4] * hr(2) / FacRhoIR2fp;
2874 0 : Aface(3, 5) = -hr(3) * wm->tir[4] * RhoIR(2) * wm->emis[4] / FacRhoIR2fpRhoIR63;
2875 0 : Aface(5, 5) = sconsh + hcvBG(1) + hr(5) * (1 - RhoIR(2) * wm->emis[4] / FacRhoIR2fp);
2876 0 : Aface(6, 5) = -sconsh - hr(6) * RhoIR(2) * wm->tir[4] * RhoIR(3) * wm->emis[4] / FacRhoIR2fpRhoIR63;
2877 0 : Bface(5) = hcvBG(1) * TGapNewBG(1) + AbsRadShadeFace(1);
2878 0 : Aface(2, 6) = -hr(2) * wm->tir[4] * RhoIR(3) * wm->emis[5] / FacRhoIR3bpRhoIR25;
2879 0 : Aface(3, 6) = -wm->emis[5] * hr(3) / FacRhoIR3bp;
2880 0 : Aface(5, 6) = -sconsh - hr(5) * RhoIR(3) * wm->tir[4] * RhoIR(2) * wm->emis[5] / FacRhoIR3bpRhoIR25;
2881 0 : Aface(6, 6) = sconsh + hcvBG(2) + hr(6) * (1 - RhoIR(3) * wm->emis[5] / FacRhoIR3bp);
2882 0 : Bface(6) = hcvBG(2) * TGapNewBG(2) + AbsRadShadeFace(2);
2883 0 : }
2884 :
2885 0 : } else if (nglasslayer == 3) {
2886 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2887 0 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2888 0 : hgap(1) = con / wm->gaps[0].width * nu;
2889 0 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
2890 0 : wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
2891 0 : hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
2892 : }
2893 :
2894 0 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
2895 0 : NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
2896 0 : hgap(2) = con / wm->gaps[1].width * nu;
2897 0 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
2898 0 : wm->hrgap[1] = 0.5 * std::abs(wm->A45) * pow_3(wm->thetas[3] + wm->thetas[4]);
2899 0 : hgap(2) = hgap(2) * surfWin.edgeGlassCorrFac + wm->hrgap[1] * (surfWin.edgeGlassCorrFac - 1.0);
2900 : }
2901 :
2902 0 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2903 0 : Bface(2) = wm->AbsRadGlassFace[1];
2904 0 : Bface(3) = wm->AbsRadGlassFace[2];
2905 0 : Bface(4) = wm->AbsRadGlassFace[3];
2906 0 : Bface(5) = wm->AbsRadGlassFace[4];
2907 0 : Bface(6) = wm->Rmir * wm->emis[5] + wm->hcin * wm->tin + wm->AbsRadGlassFace[5];
2908 :
2909 0 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2910 0 : Aface(2, 1) = -wm->scon[0];
2911 :
2912 0 : Aface(1, 2) = -wm->scon[0];
2913 0 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2914 0 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2915 :
2916 0 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2917 0 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2918 0 : Aface(4, 3) = -wm->scon[1];
2919 :
2920 0 : Aface(3, 4) = -wm->scon[1];
2921 0 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
2922 0 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
2923 :
2924 0 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
2925 0 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
2926 0 : Aface(6, 5) = -wm->scon[2];
2927 :
2928 0 : Aface(5, 6) = -wm->scon[2];
2929 0 : Aface(6, 6) = hr(6) + wm->scon[2] + wm->hcin;
2930 :
2931 0 : if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
2932 0 : Bface(4) = wm->AbsRadGlassFace[3] + hcvAirflowGap * TAirflowGapNew;
2933 0 : Bface(5) = wm->AbsRadGlassFace[4] + hcvAirflowGap * TAirflowGapNew;
2934 0 : Aface(4, 4) = wm->scon[1] + hcvAirflowGap - wm->A45P * hr(4);
2935 0 : Aface(5, 4) = -wm->A54P * hr(5);
2936 0 : Aface(4, 5) = wm->A45P * hr(4);
2937 0 : Aface(5, 5) = hcvAirflowGap + wm->scon[2] + wm->A54P * hr(5);
2938 : }
2939 :
2940 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
2941 0 : Bface(6) = wm->Rmir * wm->emis[5] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[5];
2942 0 : Bface(7) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
2943 0 : Bface(8) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
2944 :
2945 0 : Aface(6, 6) = hr(6) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[2] + hcv;
2946 0 : Aface(7, 6) = -wm->emis[5] * hr(7) / ShGlReflFacIR;
2947 0 : Aface(6, 7) = -hr(6) * EpsShIR1 / ShGlReflFacIR;
2948 0 : Aface(7, 7) = hr(7) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
2949 0 : Aface(8, 7) = -sconsh;
2950 0 : Aface(7, 8) = -sconsh;
2951 0 : Aface(8, 8) = hr(8) + sconsh + wm->hcin;
2952 0 : } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2953 0 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
2954 0 : Bface(7) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
2955 0 : Bface(8) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
2956 :
2957 0 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
2958 0 : Aface(8, 1) = -wm->emis[0] * hr(8) / ShGlReflFacIR;
2959 0 : Aface(7, 7) = hr(7) + sconsh + wm->hcout;
2960 0 : Aface(8, 7) = -sconsh;
2961 0 : Aface(1, 8) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
2962 0 : Aface(7, 8) = -sconsh;
2963 0 : Aface(8, 8) = hr(8) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
2964 0 : } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
2965 0 : Array1D<Real64> RhoIR(8); // Face IR reflectance
2966 0 : for (int i = 1; i <= 8; ++i) {
2967 0 : RhoIR(i) = max(0.0, 1.0 - wm->tir[i - 1] - wm->emis[i - 1]);
2968 : }
2969 0 : FacRhoIR47 = 1 - RhoIR(4) * RhoIR(7);
2970 0 : FacRhoIR85 = 1 - RhoIR(8) * RhoIR(5);
2971 0 : Real64 const tir_7_squared(pow_2(wm->tir[6]));
2972 0 : RhoIRfp = RhoIR(7) + tir_7_squared * RhoIR(5) / FacRhoIR85;
2973 0 : RhoIRbp = RhoIR(8) + tir_7_squared * RhoIR(4) / FacRhoIR47;
2974 0 : FacRhoIR4fp = 1 - RhoIRfp * RhoIR(4);
2975 0 : FacRhoIR5bp = 1 - RhoIRbp * RhoIR(5);
2976 0 : FacRhoIR4fpRhoIR85 = FacRhoIR4fp * FacRhoIR85;
2977 0 : FacRhoIR5bpRhoIR47 = FacRhoIR5bp * FacRhoIR47;
2978 0 : Aface(4, 4) = wm->scon[1] + hcvBG(1) + hr(4) * (1 - RhoIRfp * (wm->emis[3] + RhoIR(4))) / FacRhoIR4fp;
2979 0 : Aface(5, 4) = -wm->emis[3] * hr(5) * wm->tir[6] / FacRhoIR4fpRhoIR85;
2980 0 : Aface(7, 4) = -wm->emis[3] * hr(7) / FacRhoIR4fp;
2981 0 : Aface(8, 4) = -wm->emis[3] * hr(8) * RhoIR(5) * wm->tir[6] / FacRhoIR4fpRhoIR85;
2982 0 : Bface(4) = hcvBG(1) * TGapNewBG(1) + wm->AbsRadGlassFace[3];
2983 0 : Aface(4, 5) = -wm->emis[4] * hr(4) * wm->tir[6] / FacRhoIR5bpRhoIR47;
2984 0 : Aface(5, 5) = wm->scon[2] + hcvBG(2) + hr(5) * (1 - RhoIRbp * (wm->emis[4] + RhoIR(5))) / FacRhoIR5bp;
2985 0 : Aface(7, 5) = -wm->emis[4] * hr(7) * RhoIR(4) * wm->tir[6] / FacRhoIR5bpRhoIR47;
2986 0 : Aface(8, 5) = -wm->emis[4] * hr(8) / FacRhoIR5bp;
2987 0 : Bface(5) = hcvBG(2) * TGapNewBG(2) + wm->AbsRadGlassFace[4];
2988 0 : Aface(4, 7) = -wm->emis[6] * hr(4) / FacRhoIR4fp;
2989 0 : Aface(5, 7) = -hr(5) * wm->tir[6] * RhoIR(4) * wm->emis[6] / FacRhoIR4fpRhoIR85;
2990 0 : Aface(7, 7) = sconsh + hcvBG(1) + hr(7) * (1 - RhoIR(4) * wm->emis[6] / FacRhoIR4fp);
2991 0 : Aface(8, 7) = -sconsh - hr(8) * RhoIR(4) * wm->tir[6] * RhoIR(5) * wm->emis[6] / FacRhoIR4fpRhoIR85;
2992 0 : Bface(7) = hcvBG(1) * TGapNewBG(1) + AbsRadShadeFace(1);
2993 0 : Aface(4, 8) = -hr(4) * wm->tir[6] * RhoIR(5) * wm->emis[7] / FacRhoIR5bpRhoIR47;
2994 0 : Aface(5, 8) = -wm->emis[7] * hr(5) / FacRhoIR5bp;
2995 0 : Aface(7, 8) = -sconsh - hr(7) * RhoIR(5) * wm->tir[6] * RhoIR(4) * wm->emis[7] / FacRhoIR5bpRhoIR47;
2996 0 : Aface(8, 8) = sconsh + hcvBG(2) + hr(8) * (1 - RhoIR(5) * wm->emis[7] / FacRhoIR5bp);
2997 0 : Bface(8) = hcvBG(2) * TGapNewBG(2) + AbsRadShadeFace(2);
2998 0 : }
2999 :
3000 0 : } else if (nglasslayer == 4) {
3001 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
3002 0 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
3003 0 : hgap(1) = con / wm->gaps[0].width * nu;
3004 0 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3005 0 : wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
3006 0 : hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
3007 : }
3008 :
3009 0 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
3010 0 : NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
3011 0 : hgap(2) = con / wm->gaps[1].width * nu;
3012 0 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3013 0 : wm->hrgap[1] = 0.5 * std::abs(wm->A45) * pow_3(wm->thetas[3] + wm->thetas[4]);
3014 0 : hgap(2) = hgap(2) * surfWin.edgeGlassCorrFac + wm->hrgap[1] * (surfWin.edgeGlassCorrFac - 1.0);
3015 : }
3016 :
3017 0 : WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
3018 0 : NusseltNumber(state, SurfNum, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
3019 0 : hgap(3) = con / wm->gaps[2].width * nu;
3020 0 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3021 0 : wm->hrgap[2] = 0.5 * std::abs(wm->A67) * pow_3(wm->thetas[5] + wm->thetas[6]);
3022 0 : hgap(3) = hgap(3) * surfWin.edgeGlassCorrFac + wm->hrgap[2] * (surfWin.edgeGlassCorrFac - 1.0);
3023 : }
3024 0 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
3025 0 : Bface(2) = wm->AbsRadGlassFace[1];
3026 0 : Bface(3) = wm->AbsRadGlassFace[2];
3027 0 : Bface(4) = wm->AbsRadGlassFace[3];
3028 0 : Bface(5) = wm->AbsRadGlassFace[4];
3029 0 : Bface(6) = wm->AbsRadGlassFace[5];
3030 0 : Bface(7) = wm->AbsRadGlassFace[6];
3031 0 : Bface(8) = wm->Rmir * wm->emis[7] + wm->hcin * wm->tin + wm->AbsRadGlassFace[7];
3032 :
3033 0 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
3034 0 : Aface(2, 1) = -wm->scon[0];
3035 :
3036 0 : Aface(1, 2) = -wm->scon[0];
3037 0 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
3038 0 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
3039 :
3040 0 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
3041 0 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
3042 0 : Aface(4, 3) = -wm->scon[1];
3043 :
3044 0 : Aface(3, 4) = -wm->scon[1];
3045 0 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
3046 0 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
3047 :
3048 0 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
3049 0 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
3050 0 : Aface(6, 5) = -wm->scon[2];
3051 :
3052 0 : Aface(5, 6) = -wm->scon[2];
3053 0 : Aface(6, 6) = wm->scon[2] + hgap(3) - wm->A67P * hr(6);
3054 0 : Aface(7, 6) = -hgap(3) - wm->A76P * hr(7);
3055 :
3056 0 : Aface(6, 7) = -hgap(3) + wm->A67P * hr(6);
3057 0 : Aface(7, 7) = hgap(3) + wm->scon[3] + wm->A76P * hr(7);
3058 0 : Aface(8, 7) = -wm->scon[3];
3059 :
3060 0 : Aface(7, 8) = -wm->scon[3];
3061 0 : Aface(8, 8) = hr(8) + wm->scon[3] + wm->hcin;
3062 :
3063 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3064 0 : Bface(8) = wm->Rmir * wm->emis[7] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[7];
3065 0 : Bface(9) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
3066 0 : Bface(10) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
3067 :
3068 0 : Aface(8, 8) = hr(8) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[3] + hcv;
3069 0 : Aface(9, 8) = -wm->emis[7] * hr(9) / ShGlReflFacIR;
3070 0 : Aface(8, 9) = -hr(8) * EpsShIR1 / ShGlReflFacIR;
3071 0 : Aface(9, 9) = hr(9) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
3072 0 : Aface(10, 9) = -sconsh;
3073 0 : Aface(9, 10) = -sconsh;
3074 0 : Aface(10, 10) = hr(10) + sconsh + wm->hcin;
3075 : }
3076 :
3077 0 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
3078 0 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
3079 0 : Bface(9) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
3080 0 : Bface(10) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
3081 :
3082 0 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
3083 0 : Aface(10, 1) = -wm->emis[0] * hr(10) / ShGlReflFacIR;
3084 0 : Aface(9, 9) = hr(9) + sconsh + wm->hcout;
3085 0 : Aface(10, 9) = -sconsh;
3086 0 : Aface(1, 10) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
3087 0 : Aface(9, 10) = -sconsh;
3088 0 : Aface(10, 10) = hr(10) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
3089 : }
3090 :
3091 : } else {
3092 0 : ShowFatalError(state, format("SolveForWindowTemperatures: Invalid number of Glass Layers={}, up to 4 allowed.", wm->ngllayer));
3093 : }
3094 149363 : } // GetHeatBalanceEqCoefMatrix()
3095 :
3096 85895 : void SolveForWindowTemperatures(EnergyPlusData &state, int const SurfNum) // Surface number
3097 : {
3098 :
3099 : // SUBROUTINE INFORMATION:
3100 : // AUTHOR F. Winkelmann
3101 : // DATE WRITTEN July 2000
3102 : // MODIFIED Oct 2000, FW: modify edge-of-glass correction to account
3103 : // for gap radiative conductance affects
3104 : // Feb 2001, FW: add interior or exterior shade to layer
3105 : // heat balance calculation.
3106 : // Mar 2001, FW: relax error tolerance if MaxIterations reached.
3107 : // Jun 2001, FW: add interior or exterior blind
3108 : // Nov 2002, FW: add relaxation on face temperatures
3109 : // to improve convergence for multipane cases where outer pane
3110 : // has high solar absorptance: temp --> 0.5*(temp + previous temp);
3111 : // also, increase MaxIterations from 50 to 100.
3112 : // Dec 2002, FW: add between-glass shade/blind for double and triple glazing.
3113 : // Mar 2003, FW: remove redundant relaxation on radiative conductances
3114 : // Mar 2003, FW: increase convergence tolerance from 0.01 to 0.02 to enhance
3115 : // convergence in difficult cases.
3116 : // June 2003, FW: correct the expression for convective gain to zone air
3117 : // from airflow windows with airflow destination = InsideAir. Previously
3118 : // convective gain of air as it passed through gap was used, which is correct
3119 : // for airflow source = InsideAir but incorrect for airflow source = OutsideAir.
3120 : // Save SurfaceWindow%TAirflowGapOutlet for use in calculating convective heat
3121 : // gain to return air when airflow source = InsideAir, destination = ReturnAir.
3122 : // Dec 2003, FW: enhance converge for difficult cases by increasing relaxation
3123 : // in layer surface temperatures for iterations > MaxIterations/4
3124 : // May 2006, RR: add exterior window screen
3125 : // January 2009, BG: inserted call to recalc inside face convection inside iteration loop
3126 : // per ISO 15099 Section 8.3.2.2
3127 : // RE-ENGINEERED na
3128 :
3129 : // PURPOSE OF THIS SUBROUTINE:
3130 : // Evaluates the coefficients Aface and Bface in the system of linear
3131 : // algebraic equations
3132 : // Sum [Aface(i,j)*thetas(j)] = Bface(i), i = 1,nglfacep, j=1,nglfacep
3133 : // where
3134 : // nglface = number of glass faces (= 2 * number of glass layers), or, if shade or blind is present,
3135 : // nglgacep = number of glass faces + 2
3136 : // thetas(j) = temperature of face j
3137 : // If an interior, exterior or between-glass shade or blind, or exterior screen is present
3138 : // the face numbering is as follows:
3139 : // 1 to 2*nglface are glass faces, from outside to inside;
3140 : // 2*nglface+1 and 2*nglface+2 are the shade or blind faces, from outside to inside
3141 : // For example, the following diagram shows the face number for an exterior shade, screen or blind
3142 : // on double glazing:
3143 : // || || ||
3144 : // 5||6 1||2 3||4
3145 : // || || ||
3146 : // bl/sh/sc gl gl
3147 :
3148 : // And for a between-glass shade/blind in triple glazing:
3149 : // || || || ||
3150 : // 1||2 3||4 7||8 5||6
3151 : // || || || ||
3152 : // gl gl bl/sh gl
3153 :
3154 : // METHODOLOGY EMPLOYED:
3155 : // The Aface and Bface coefficients are determined by the equations for
3156 : // heat balance at the glass and shade/blind faces. The system of linear equations is solved
3157 : // by LU decomposition.
3158 :
3159 85895 : constexpr int MaxIterations(100); // Maximum allowed number of iterations (increased 9/01 from 15 to 50,
3160 : // increased 11/02 from 50 to 100)
3161 85895 : constexpr Real64 errtemptol(0.02); // Tolerance on errtemp for convergence (increased from 0.01, 3/4/03)
3162 :
3163 : int ZoneNum; // Zone number corresponding to SurfNum
3164 : int d; // +1 if number of row interchanges is even,
3165 : // -1 if odd (in LU decomposition
3166 :
3167 85895 : auto &wm = state.dataWindowManager;
3168 :
3169 85895 : int iter = 0; // Iteration number
3170 85895 : Real64 errtemp = 0.0; // Absolute value of sum of face temperature differences between iterations, divided by number of faces
3171 85895 : Real64 VGap = 0.0; // Air velocity in gap between glass and shade/blind (m/s)
3172 85895 : Real64 VAirflowGap = 0.0; // Air velocity in airflow gap between glass panes (m/s)
3173 85895 : Real64 VGapPrev = 0.0; // Value of VGap from previous iteration
3174 85895 : Real64 TGapNew = 0.0; // Average air temp in gap between glass and shade/blind (K)
3175 85895 : Real64 TAirflowGapNew = 0.0; // Average air temp in airflow gap between glass panes (K)
3176 85895 : Real64 TGapOutlet = 0.0; // Temperature of air leaving gap between glass and shade/blind (K)
3177 85895 : Real64 TAirflowGapOutlet = 0.0; // Temperature of air leaving airflow gap between glass panes (K)
3178 85895 : Real64 TAirflowGapOutletC = 0.0; // Temperature of air leaving airflow gap between glass panes (C)
3179 85895 : Real64 hcv = 0.0; // Convection coefficient from gap glass or shade/blind to gap air (W/m2-K)
3180 85895 : Real64 hcvAirflowGap = 0.0; // Convection coefficient from airflow gap glass to airflow gap air (W/m2-K)
3181 85895 : Real64 hcvPrev = 0.0; // Value of hcv from previous iteration
3182 85895 : Real64 ConvHeatFlowForced = 0.0; // Convective heat flow from forced airflow gap (W)
3183 85895 : Real64 ShGlReflFacIR = 0.0; // Factor for long-wave inter-reflection between shade/blind and adjacent glass
3184 85895 : Real64 RhoGlIR1 = 0.0; // Long-wave reflectance of glass surface facing shade/blind; 1=exterior shade/blind,
3185 85895 : Real64 RhoGlIR2 = 0.0;
3186 : // 2=exterior shade/blind
3187 85895 : Real64 EpsShIR1 = 0.0; // Long-wave emissivity of shade/blind surface facing glass; 1=interior shade/blind,
3188 85895 : Real64 EpsShIR2 = 0.0;
3189 : // 2=interior shade/blind
3190 85895 : Real64 RhoShIR1 = 0.0; // Long-wave reflectance of shade/blind surface facing glass; 1=interior shade/blind,
3191 85895 : Real64 RhoShIR2 = 0.0;
3192 : // 2=exterior shade/blind
3193 85895 : Real64 TauShIR = 0.0; // Long-wave transmittance of isolated shade/blind
3194 85895 : Real64 sconsh = 0.0; // shade/blind conductance (W/m2-K)
3195 :
3196 : // radiation from lights and zone equipment absorbed by faces of shade/blind (W/m2)
3197 85895 : Real64 ShadeArea = 0.0; // shade/blind area (m2)
3198 : // Real64 CondHeatGainGlass = 0.0; // Conduction through inner glass layer, outside to inside (W)
3199 : // Real64 CondHeatGainShade = 0.0; // Conduction through shade/blind, outside to inside (W)
3200 : // shade/blind is present. Zero if shade/blind has zero IR transmittance (W)
3201 : // Real64 IncidentSolar = 0.0; // Solar incident on outside of window (W)
3202 85895 : Real64 TotAirflowGap = 0.0; // Total volumetric airflow through window gap (m3/s)
3203 85895 : Real64 CpAirOutlet = 0.0; // Heat capacity of air from window gap (J/kg-K)
3204 85895 : Real64 CpAirZone = 0.0; // Heat capacity of zone air (J/kg-K)
3205 85895 : Real64 InletAirHumRat = 0.0; // Humidity ratio of air from window gap entering fan
3206 :
3207 85895 : Array1D<Real64> hr = Array1D<Real64>(2 * maxGlassLayers); // Radiative conductance (W/m2-K)
3208 85895 : Array1D<Real64> AbsRadShadeFace(2); // Solar radiation, short-wave radiation from lights, and long-wave
3209 85895 : Array1D<Real64> TGapNewBG(2); // For between-glass shade/blind, average gas temp in gaps on either
3210 : // side of shade/blind (K)
3211 85895 : Array1D<Real64> hcvBG(2); // For between-glass shade/blind, convection coefficient from gap glass or
3212 : // shade/blind to gap gas on either side of shade/blind (W/m2-K)
3213 :
3214 85895 : Array2D<Real64> Aface(2 * maxGlassLayers, 2 * maxGlassLayers); // Coefficient in equation Aface*thetas = Bface
3215 85895 : Array1D<Real64> Bface(2 * maxGlassLayers); // Coefficient in equation Aface*thetas = Bface
3216 85895 : Array1D_int indx(2 * maxGlassLayers); // Vector of row permutations in LU decomposition
3217 :
3218 85895 : auto &s_surf = state.dataSurface;
3219 :
3220 85895 : wm->nglfacep = wm->nglface;
3221 85895 : WinShadingType ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
3222 85895 : ZoneNum = s_surf->Surface(SurfNum).Zone;
3223 85895 : AbsRadShadeFace = 0.0;
3224 :
3225 85895 : if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
3226 0 : wm->nglfacep = wm->nglface + 2;
3227 0 : AbsRadShadeFace(1) = DataSurfaces::AbsFrontSide(state, SurfNum);
3228 0 : AbsRadShadeFace(2) = DataSurfaces::AbsBackSide(state, SurfNum);
3229 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) AbsRadShadeFace(2) += s_surf->SurfWinIntLWAbsByShade(SurfNum);
3230 0 : sconsh = wm->scon[wm->ngllayer];
3231 0 : TauShIR = wm->tir[wm->nglface];
3232 0 : EpsShIR1 = wm->emis[wm->nglface];
3233 0 : EpsShIR2 = wm->emis[wm->nglface + 1];
3234 0 : RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1);
3235 0 : RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2);
3236 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3237 0 : RhoGlIR2 = 1.0 - wm->emis[2 * wm->ngllayer - 1];
3238 0 : ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1;
3239 0 : } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
3240 0 : RhoGlIR1 = 1.0 - wm->emis[0];
3241 0 : ShGlReflFacIR = 1.0 - RhoGlIR1 * RhoShIR2;
3242 : }
3243 : } // End of check if shade or blind is on
3244 :
3245 : // Initialize face temperatures.
3246 :
3247 85895 : StartingWindowTemps(state, SurfNum, AbsRadShadeFace);
3248 :
3249 85895 : hcvPrev = 0.0;
3250 85895 : VGapPrev = 0.0;
3251 :
3252 : // Calculate radiative conductances
3253 :
3254 85895 : errtemp = errtemptol * 2.0;
3255 :
3256 235258 : while (iter < MaxIterations && errtemp > errtemptol) {
3257 :
3258 528629 : for (int i = 1; i <= wm->nglfacep; ++i) {
3259 379266 : hr(i) = wm->emis[i - 1] * Constant::StefanBoltzmann * pow_3(wm->thetas[i - 1]);
3260 : // Following line is redundant since thetas is being relaxed;
3261 : // removed by FCW, 3/4/03
3262 : //! fw if ( iter >= 1 ) hr(i) = 0.5*(hrprev(i)+hr(i))
3263 : }
3264 :
3265 : // call for new interior film coeff (since it is temperature dependent) if using Detailed inside coef model
3266 149363 : if (((s_surf->surfIntConv(SurfNum).model == Convect::HcInt::SetByZone) &&
3267 169205 : (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo == Convect::HcInt::ASHRAETARP)) ||
3268 19842 : (s_surf->surfIntConv(SurfNum).model == Convect::HcInt::ASHRAETARP)) {
3269 : // coef model is "detailed" and not prescribed by user
3270 : // need to find inside face index, varies with shade/blind etc.
3271 : int InsideFaceIndex; // intermediate variable for index of inside face in thetas
3272 129521 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3273 0 : InsideFaceIndex = wm->nglfacep;
3274 : } else {
3275 129521 : InsideFaceIndex = wm->nglface;
3276 : }
3277 129521 : Convect::CalcISO15099WindowIntConvCoeff(
3278 129521 : state, SurfNum, wm->thetas[InsideFaceIndex - 1] - Constant::Kelvin, wm->tin - Constant::Kelvin);
3279 129521 : wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
3280 : }
3281 :
3282 149363 : Aface = 0.0;
3283 149363 : Bface = 0.0;
3284 :
3285 : // If interior or exterior shade or blind is present, get heat transfer
3286 : // coefficient from glass and shade/blind to gap between glass and shade/blind,
3287 : // effective gap air temperature, velocity of air in gap and gap outlet temperature.
3288 :
3289 149363 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag) || ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3290 0 : ExtOrIntShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNew, TGapOutlet, hcv, s_surf->SurfWinConvHeatFlowNatural(SurfNum));
3291 0 : if (iter >= 1) {
3292 0 : hcv = 0.5 * (hcvPrev + hcv);
3293 0 : VGap = 0.5 * (VGapPrev + VGap);
3294 : }
3295 0 : hcvPrev = hcv;
3296 0 : VGapPrev = VGap;
3297 : }
3298 :
3299 149363 : TAirflowGapOutlet = 0.0;
3300 : // If between-glass shade or blind is not present and this is an airflow window
3301 : // (i.e., with forced airflow in the gap for double glass or in the inner gap for triple glass)
3302 : // get glass-to-air forced convection heat transfer coefficient, average gap air temperature, and
3303 : // convective heat flow from gap.
3304 :
3305 149363 : if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
3306 0 : BetweenGlassForcedFlow(state, SurfNum, iter, VAirflowGap, TAirflowGapNew, TAirflowGapOutlet, hcvAirflowGap, ConvHeatFlowForced);
3307 : }
3308 :
3309 : // If between-glass shade or blind is present, get convective heat transfer
3310 : // coefficients from glass and shade/blind to the two gaps on either side of the shade/matBlind->
3311 : // Also get average gas temperature in the two gaps, and, for airflow window, the sum of the
3312 : // convective heat flows from the gaps.
3313 :
3314 149363 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
3315 0 : if (s_surf->SurfWinAirflowThisTS(SurfNum) == 0.0) { // Natural convection in gaps
3316 0 : BetweenGlassShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNewBG, hcvBG);
3317 : } else { // Forced convection in gaps
3318 0 : BetweenGlassShadeForcedFlow(state, SurfNum, iter, VGap, TGapNewBG, TAirflowGapOutlet, hcvBG, ConvHeatFlowForced);
3319 : }
3320 : }
3321 :
3322 149363 : ++iter;
3323 :
3324 : // Calculations based on number of glass layers
3325 298726 : GetHeatBalanceEqCoefMatrix(state,
3326 : SurfNum,
3327 149363 : wm->ngllayer,
3328 : ShadeFlag,
3329 : sconsh,
3330 : TauShIR,
3331 : EpsShIR1,
3332 : EpsShIR2,
3333 : RhoShIR1,
3334 : RhoShIR2,
3335 : ShGlReflFacIR,
3336 : RhoGlIR1,
3337 : RhoGlIR2,
3338 : hcv,
3339 : TGapNew,
3340 : TAirflowGapNew,
3341 : hcvAirflowGap,
3342 : hcvBG,
3343 : TGapNewBG,
3344 : AbsRadShadeFace,
3345 : hr,
3346 : Aface,
3347 : Bface);
3348 149363 : LUdecomposition(state, Aface, wm->nglfacep, indx, d); // Note that these routines change Aface;
3349 149363 : LUsolution(state, Aface, wm->nglfacep, indx, Bface); // face temperatures are returned in Bface
3350 :
3351 528629 : for (int i = 1; i <= wm->nglfacep; ++i) {
3352 379266 : wm->thetasPrev[i - 1] = wm->thetas[i - 1];
3353 379266 : if (iter < MaxIterations / 4) {
3354 379266 : wm->thetas[i - 1] = 0.5 * wm->thetas[i - 1] + 0.5 * Bface(i);
3355 : } else {
3356 0 : wm->thetas[i - 1] = 0.75 * wm->thetas[i - 1] + 0.25 * Bface(i);
3357 : }
3358 : }
3359 :
3360 149363 : errtemp = 0.0;
3361 528629 : for (int i = 1; i <= wm->nglfacep; ++i) {
3362 379266 : errtemp += std::abs(wm->thetas[i - 1] - wm->thetasPrev[i - 1]);
3363 : }
3364 149363 : errtemp /= wm->nglfacep;
3365 : }
3366 :
3367 85895 : s_surf->SurfWinWindowCalcIterationsRep(SurfNum) = iter;
3368 :
3369 : // We have reached iteration limit or we have converged. If we have reached the
3370 : // iteration limit the following test relaxes the convergence tolerance.
3371 : // If we have converged (errtemp <= errtemptol) the following test has not effect.
3372 :
3373 85895 : if (errtemp < 10 * errtemptol) {
3374 :
3375 : // Window heat balance solution has converged.
3376 :
3377 : // For interior shade, add convective gain from glass/shade gap air flow to zone convective gain;
3378 : // For all cases, get total window heat gain for reporting. See CalcWinFrameAndDividerTemps for
3379 : // contribution of frame and divider.
3380 : // IncidentSolar = s_surf->Surface(SurfNum).Area * state.dataHeatBal->SurfQRadSWOutIncident(SurfNum);
3381 85895 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3382 : // Interior shade or blind
3383 : // Window heat gain from glazing and shade/blind to zone. Consists of transmitted solar, convection
3384 : // from air exiting gap, convection from zone-side of shade/blind, net IR to zone from shade and net IR to
3385 : // zone from the glass adjacent to the shade/blind (zero if shade/blind IR transmittance is zero).
3386 : // Following assumes glazed area = window area (i.e., dividers ignored) in calculating
3387 : // IR to zone from glass when interior shade/blind is present.
3388 0 : ShadeArea = s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum);
3389 : // CondHeatGainShade = ShadeArea * sconsh *
3390 : // (wm->thetas(wm->nglfacep - 1) -
3391 : // wm->thetas[wm->nglfacep-1]);
3392 0 : s_surf->SurfWinGainIRShadeToZoneRep(SurfNum) =
3393 0 : ShadeArea * EpsShIR2 * (Constant::StefanBoltzmann * pow_4(wm->thetas[wm->nglfacep - 1]) - wm->Rmir) +
3394 0 : EpsShIR1 * (Constant::StefanBoltzmann * pow_4(wm->thetas[wm->nglfacep - 2]) - wm->Rmir) * RhoGlIR2 * TauShIR / ShGlReflFacIR;
3395 0 : s_surf->SurfWinGainIRGlazToZoneRep(SurfNum) = ShadeArea * (wm->emis[2 * wm->ngllayer - 1] * TauShIR / ShGlReflFacIR) *
3396 0 : (Constant::StefanBoltzmann * pow_4(wm->thetas[2 * wm->ngllayer - 1]) - wm->Rmir);
3397 0 : s_surf->SurfWinGainConvShadeToZoneRep(SurfNum) = ShadeArea * wm->hcin * (wm->thetas[wm->nglfacep - 1] - wm->tin);
3398 0 : s_surf->SurfWinHeatGain(SurfNum) = s_surf->SurfWinTransSolar(SurfNum) + s_surf->SurfWinConvHeatFlowNatural(SurfNum) +
3399 0 : s_surf->SurfWinGainConvShadeToZoneRep(SurfNum) + s_surf->SurfWinGainIRGlazToZoneRep(SurfNum) +
3400 0 : s_surf->SurfWinGainIRShadeToZoneRep(SurfNum);
3401 : } else {
3402 : // Interior shade or blind not present; innermost layer is glass
3403 : // CondHeatGainGlass = s_surf->Surface(SurfNum).Area * wm->scon(wm->ngllayer) *
3404 : // (wm->thetas(2 * wm->ngllayer - 1) -
3405 : // wm->thetas[2 * wm->ngllayer - 1]);
3406 171790 : s_surf->SurfWinGainIRGlazToZoneRep(SurfNum) = s_surf->Surface(SurfNum).Area * wm->emis[2 * wm->ngllayer - 1] *
3407 85895 : (Constant::StefanBoltzmann * pow_4(wm->thetas[2 * wm->ngllayer - 1]) - wm->Rmir);
3408 85895 : s_surf->SurfWinGainConvGlazToZoneRep(SurfNum) =
3409 85895 : s_surf->Surface(SurfNum).Area * wm->hcin * (wm->thetas[2 * wm->ngllayer - 1] - wm->tin);
3410 85895 : s_surf->SurfWinHeatGain(SurfNum) =
3411 85895 : s_surf->SurfWinTransSolar(SurfNum) + s_surf->SurfWinGainConvGlazToZoneRep(SurfNum) + s_surf->SurfWinGainIRGlazToZoneRep(SurfNum);
3412 : }
3413 :
3414 : // Add convective heat gain from airflow window
3415 : // Note: effect of fan heat on gap outlet temperature is neglected since fan power (based
3416 : // on pressure drop through the gap) is extremely small
3417 :
3418 85895 : s_surf->SurfWinGapConvHtFlowRep(SurfNum) = 0.0;
3419 85895 : s_surf->SurfWinGapConvHtFlowRepEnergy(SurfNum) = 0.0;
3420 85895 : TotAirflowGap = s_surf->SurfWinAirflowThisTS(SurfNum) * s_surf->Surface(SurfNum).Width;
3421 85895 : TAirflowGapOutletC = TAirflowGapOutlet - Constant::Kelvin;
3422 85895 : s_surf->SurfWinTAirflowGapOutlet(SurfNum) = TAirflowGapOutletC;
3423 85895 : if (s_surf->SurfWinAirflowThisTS(SurfNum) > 0.0) {
3424 0 : s_surf->SurfWinGapConvHtFlowRep(SurfNum) = ConvHeatFlowForced;
3425 0 : s_surf->SurfWinGapConvHtFlowRepEnergy(SurfNum) = s_surf->SurfWinGapConvHtFlowRep(SurfNum) * state.dataGlobal->TimeStepZoneSec;
3426 : // Add heat from gap airflow to zone air if destination is inside air; save the heat gain to return
3427 : // air in case it needs to be sent to the zone (due to no return air determined in HVAC simulation)
3428 0 : if (s_surf->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Indoor ||
3429 0 : s_surf->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Return) {
3430 0 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
3431 0 : if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
3432 0 : InletAirHumRat = thisZoneHB.airHumRat;
3433 : } else { // AirflowSource = outside air
3434 0 : InletAirHumRat = state.dataEnvrn->OutHumRat;
3435 : }
3436 0 : Real64 ZoneTemp = thisZoneHB.MAT; // this should be Tin (account for different reference temps)
3437 0 : CpAirOutlet = Psychrometrics::PsyCpAirFnW(InletAirHumRat);
3438 0 : CpAirZone = Psychrometrics::PsyCpAirFnW(thisZoneHB.airHumRat);
3439 0 : s_surf->SurfWinRetHeatGainToZoneAir(SurfNum) = TotAirflowGap * (CpAirOutlet * (TAirflowGapOutletC)-CpAirZone * ZoneTemp);
3440 0 : if (s_surf->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Indoor) {
3441 0 : s_surf->SurfWinHeatGain(SurfNum) += s_surf->SurfWinRetHeatGainToZoneAir(SurfNum);
3442 : }
3443 : }
3444 : // For AirflowDestination = ReturnAir in a controlled (i.e., conditioned) zone with return air, see CalcZoneLeavingConditions
3445 : // for calculation of modification of return-air temperature due to airflow from window gaps into return air.
3446 : }
3447 :
3448 : // Correct WinHeatGain for interior diffuse shortwave (solar and shortwave from lights) transmitted
3449 : // back out window
3450 85895 : int const ConstrNum = s_surf->SurfActiveConstruction(SurfNum);
3451 85895 : int const ConstrNumSh = s_surf->SurfWinActiveShadedConstruction(SurfNum);
3452 :
3453 85895 : Real64 reflDiff = 0.0; // Diffuse shortwave back reflectance
3454 85895 : if (NOT_SHADED(ShadeFlag)) {
3455 85895 : reflDiff = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack;
3456 0 : } else if (ANY_SHADE_SCREEN(ShadeFlag)) {
3457 0 : reflDiff = state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack;
3458 0 : } else if (ANY_BLIND(ShadeFlag)) {
3459 0 : auto const &surfShade = s_surf->surfShades(SurfNum);
3460 0 : auto const &constrSh = state.dataConstruction->Construct(ConstrNumSh);
3461 0 : reflDiff = Interp(constrSh.blindTARs[surfShade.blind.slatAngIdxLo].Sol.Bk.Df.Ref,
3462 0 : constrSh.blindTARs[surfShade.blind.slatAngIdxHi].Sol.Bk.Df.Ref,
3463 0 : surfShade.blind.slatAngInterpFac);
3464 0 : } else if (ShadeFlag == WinShadingType::SwitchableGlazing) {
3465 0 : reflDiff = InterpSw(s_surf->SurfWinSwitchingFactor(SurfNum),
3466 0 : state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack,
3467 0 : state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack);
3468 : }
3469 : // shouldn't this be + outward flowing fraction of absorbed SW? -- do not know whose comment this is? LKL (9/2012)
3470 85895 : s_surf->SurfWinLossSWZoneToOutWinRep(SurfNum) =
3471 85895 : state.dataHeatBal->EnclSolQSWRad(s_surf->Surface(SurfNum).SolarEnclIndex) * s_surf->Surface(SurfNum).Area * (1 - reflDiff) +
3472 85895 : state.dataHeatBalSurf->SurfWinInitialBeamSolInTrans(SurfNum);
3473 171790 : s_surf->SurfWinHeatGain(SurfNum) -= (s_surf->SurfWinLossSWZoneToOutWinRep(SurfNum) +
3474 85895 : state.dataHeatBalSurf->SurfWinInitialDifSolInTrans(SurfNum) * s_surf->Surface(SurfNum).Area);
3475 :
3476 85895 : if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
3477 0 : s_surf->SurfWinShadingAbsorbedSolar(SurfNum) =
3478 0 : (s_surf->SurfWinExtBeamAbsByShade(SurfNum) + s_surf->SurfWinExtDiffAbsByShade(SurfNum)) *
3479 0 : (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum));
3480 0 : s_surf->SurfWinShadingAbsorbedSolarEnergy(SurfNum) = s_surf->SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec;
3481 : }
3482 85895 : if (state.dataEnvrn->SunIsUp) {
3483 :
3484 42964 : s_surf->SurfWinSysSolTransmittance(SurfNum) =
3485 42964 : s_surf->SurfWinTransSolar(SurfNum) /
3486 42964 : (state.dataHeatBal->SurfQRadSWOutIncident(SurfNum) * (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum)) +
3487 : 0.0001);
3488 42964 : s_surf->SurfWinSysSolAbsorptance(SurfNum) =
3489 42964 : (state.dataHeatBal->SurfWinQRadSWwinAbsTot(SurfNum) + s_surf->SurfWinShadingAbsorbedSolar(SurfNum)) /
3490 42964 : (state.dataHeatBal->SurfQRadSWOutIncident(SurfNum) * (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum)) +
3491 : 0.0001);
3492 42964 : s_surf->SurfWinSysSolReflectance(SurfNum) =
3493 42964 : 1.0 - s_surf->SurfWinSysSolTransmittance(SurfNum) - s_surf->SurfWinSysSolAbsorptance(SurfNum);
3494 : } else {
3495 42931 : s_surf->SurfWinSysSolTransmittance(SurfNum) = 0.0;
3496 42931 : s_surf->SurfWinSysSolAbsorptance(SurfNum) = 0.0;
3497 42931 : s_surf->SurfWinSysSolReflectance(SurfNum) = 0.0;
3498 : }
3499 :
3500 : // Save hcv for use in divider calc with interior or exterior shade (see CalcWinFrameAndDividerTemps)
3501 85895 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) s_surf->SurfWinConvCoeffWithShade(SurfNum) = hcv;
3502 : } else {
3503 : // No convergence after MaxIterations even with relaxed error tolerance
3504 0 : ShowSevereError(state, format("Convergence error in SolveForWindowTemperatures for window {}", s_surf->Surface(SurfNum).Name));
3505 0 : ShowContinueErrorTimeStamp(state, "");
3506 :
3507 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3508 : // report out temperatures
3509 0 : for (int i = 1; i <= wm->nglfacep; ++i) {
3510 0 : ShowContinueError(state,
3511 0 : format("Glazing face index = {} ; new temperature ={:.4R}C ; previous temperature = {:.4R}C",
3512 : i,
3513 0 : wm->thetas[i - 1] - Constant::Kelvin,
3514 0 : wm->thetasPrev[i - 1] - Constant::Kelvin));
3515 : }
3516 : }
3517 :
3518 0 : ShowFatalError(
3519 : state,
3520 0 : format("Program halted because of convergence error in SolveForWindowTemperatures for window {}", s_surf->Surface(SurfNum).Name));
3521 : }
3522 85895 : } // SolveForWindowTemperatures()
3523 :
3524 : //****************************************************************************
3525 :
3526 0 : void ExtOrIntShadeNaturalFlow(EnergyPlusData &state,
3527 : int const SurfNum, // Surface number
3528 : int const iter, // Iteration number for glass heat balance calculation
3529 : Real64 &VGap, // Air velocity in glass-shade/blind gap (m/s)
3530 : Real64 &TGapNew, // Current-iteration average air temp in glass-shade/blind gap (K)
3531 : Real64 &TGapOutlet, // Temperature of air leaving glass-shade/blind gap at top for upward
3532 : Real64 &hcv, // Convection coefficient from gap glass or shade to gap air (W/m2-K)
3533 : Real64 &QConvGap // Convective heat gain from glass-shade/blind gap for interior shade (W)
3534 : )
3535 : {
3536 :
3537 : // SUBROUTINE INFORMATION:
3538 : // AUTHOR F. Winkelmann
3539 : // DATE WRITTEN December 2000
3540 : // MODIFIED June 2001: add window blinds
3541 : // May 2006 (RR): add exterior window screens
3542 : // RE-ENGINEERED na
3543 :
3544 : // PURPOSE OF THIS SUBROUTINE:
3545 : // Called by SolveForWindowTemperatures for windows that have an interior
3546 : // or exterior blind or shade in place.
3547 : // Solves for air flow in gap between glass and shade/blind.
3548 : // Finds temperature of gap air and coefficient for convective heat transfer
3549 : // from glass to gap air and shade/blind to gap air.
3550 :
3551 : // METHODOLOGY EMPLOYED:
3552 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
3553 : // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
3554 :
3555 : // SUBROUTINE ARGUMENT DEFINITIONS:
3556 : // air flow or bottom for downward air flow (K)
3557 :
3558 : int ConstrNumSh; // Shaded construction number
3559 : int MatNumSh; // Material number of shade/blind layer
3560 : int nglassfaces; // Number of glass faces in construction
3561 : Real64 TGapInlet; // Temperature of air entering glass-shade/blind gap at bottom for upward
3562 : // air flow or top for downward air flow (K)
3563 : Real64 TGlassFace; // Temperature of glass surface facing glass-shade/blind gap (K)
3564 : Real64 TShadeFace; // Temperature of shade surface facing glass-shade/blind gap (K)
3565 : Real64 hGapStill; // Still-air glass-shade/blind gap conduction/convection coeff (W/m2-K)
3566 : Real64 TGapOld; // Previous-iteration average air temp in glass-shade/blind gap (K)
3567 : Real64 GapHeight; // Vertical length of glass-shade/blind gap (m)
3568 : Real64 GapDepth; // Distance from shade to glass (m)
3569 : Real64 RhoAir; // Density of glass-shade/blind gap air at a temperature of TGapOld (kg/m3)
3570 : Real64 RhoTRef; // Density of glass-shade/blind air at reference temp = KelvinConv (kg/m3)
3571 : Real64 ViscAir; // Viscosity of glass-shade/blind gap air at a temperature of TGapOld (kg/m3)
3572 : Real64 AGap; // Cross sectional area of glass-shade/blind gap (m2); for vertical window, this
3573 : // is in horizontal plane normal to window.
3574 : Real64 ATopGap; // Area of the top and bottom openings (m2)
3575 : Real64 ABotGap;
3576 : Real64 ALeftGap; // Area of the left and right openings (m2)
3577 : Real64 ARightGap;
3578 : Real64 AHolesGap; // Area of the holes in the shade (assumed homogeneously
3579 : // distributed) (m2)
3580 : Real64 ATopLRH; // Intermediate variables
3581 : Real64 ABotLRH;
3582 : Real64 AEqInlet; // Equivalent inlet and outlet opening areas (m2)
3583 : Real64 AEqOutlet;
3584 : Real64 Zinlet; // Inlet and outlet pressure loss factors
3585 : Real64 Zoutlet;
3586 : Real64 AVGap; // Coeff. of VGap**2 term in pressure balance equation
3587 : Real64 BVGap; // Coeff. of VGap term in pressure balance equation
3588 : Real64 CVGap; // VGap-independent term in pressure balance equation
3589 : Real64 GapHeightChar; // Characteristic height of the gap air temperature profile (m)
3590 : Real64 TAve; // Average of TGlass and TShade (K)
3591 : // REAL(r64) :: AirProps(8) ! Air properties
3592 : int TotGaps; // Glass/glass gaps + glass-shade/blind gap
3593 : Real64 con; // Gap conductivity and derivative
3594 : Real64 gr; // glass-shade/blind gap Grashof number
3595 : Real64 pr; // glass-shade/blind gap Prandtl number
3596 : Real64 nu; // glass-shade/blind gap Nusselt number
3597 : WinShadingType ShadeFlag; // Shading flag
3598 :
3599 0 : auto &s_mat = state.dataMaterial;
3600 0 : auto &s_surf = state.dataSurface;
3601 0 : auto &wm = state.dataWindowManager;
3602 :
3603 0 : auto &surf = s_surf->Surface(SurfNum);
3604 :
3605 : // Air properties
3606 : // Dens dDens/dT Con dCon/dT Vis dVis/dT Prandtl dPrandtl/dT
3607 : // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72, 1.8d-3 /
3608 :
3609 0 : ConstrNumSh = s_surf->SurfWinActiveShadedConstruction(SurfNum);
3610 0 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
3611 0 : nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
3612 0 : TotGaps = state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
3613 :
3614 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { // Interior shade or blind
3615 0 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(nglassfaces);
3616 0 : TGapInlet = wm->tin;
3617 0 : TGlassFace = wm->thetas[nglassfaces - 1];
3618 0 : TShadeFace = wm->thetas[nglassfaces];
3619 : } else { // Exterior shade, screen or blind
3620 0 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1);
3621 0 : TGapInlet = wm->tout;
3622 0 : TGlassFace = wm->thetas[0];
3623 0 : TShadeFace = wm->thetas[nglassfaces + 1];
3624 : }
3625 0 : TAve = 0.5 * (TGlassFace + TShadeFace);
3626 :
3627 0 : if (iter == 0) {
3628 0 : TGapOld = 0.5 * (TAve + TGapInlet);
3629 : } else {
3630 0 : TGapOld = TGapNew;
3631 : }
3632 :
3633 : // Conductance of gap between glass and shade assuming gap is sealed
3634 0 : WindowGasConductance(state, TGlassFace, TShadeFace, TotGaps, con, pr, gr);
3635 0 : NusseltNumber(state, SurfNum, TGlassFace, TShadeFace, TotGaps, gr, pr, nu);
3636 0 : hGapStill = con / wm->gaps[TotGaps - 1].width * nu;
3637 :
3638 : // For near-horizontal windows (i.e., no more than 5 deg from horizontal) assume
3639 : // there is no air flow thru gap
3640 :
3641 0 : if (std::abs(surf.SinTilt) < 0.0872) {
3642 0 : VGap = 0.0;
3643 0 : hcv = 2.0 * hGapStill;
3644 0 : QConvGap = 0.0;
3645 0 : TGapNew = TAve;
3646 0 : TGapOutlet = TAve;
3647 0 : return;
3648 : }
3649 :
3650 0 : GapHeight = surf.Height;
3651 :
3652 0 : auto const *matShadingDevice = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(MatNumSh));
3653 0 : assert(matShadingDevice != nullptr);
3654 :
3655 0 : GapDepth = matShadingDevice->toGlassDist;
3656 0 : AGap = GapDepth * surf.Width;
3657 0 : ATopGap = matShadingDevice->topOpeningMult * AGap;
3658 0 : ABotGap = matShadingDevice->bottomOpeningMult * AGap;
3659 0 : ALeftGap = matShadingDevice->leftOpeningMult * GapHeight * GapDepth;
3660 0 : ARightGap = matShadingDevice->rightOpeningMult * GapHeight * GapDepth;
3661 : // For blinds, airFlowPermeability depends on slat angle which is a property of the surface, not the material
3662 0 : if (matShadingDevice->group == Material::Group::Blind) {
3663 0 : AHolesGap = s_surf->surfShades(SurfNum).blind.airFlowPermeability * GapHeight * surf.Width;
3664 : } else {
3665 0 : AHolesGap = matShadingDevice->airFlowPermeability * GapHeight * surf.Width;
3666 : }
3667 :
3668 0 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapOld - Constant::Kelvin);
3669 0 : ViscAir = wm->AirProps[4] + wm->AirProps[5] * (TGapOld - Constant::Kelvin);
3670 : // The factor 12 in the next line is based on the solution of steady laminar flow between fixed
3671 : // parallel plates given in Sec. 6.9.1 of Fundamentals of Fluid Mechanics, Munson/Young/Okishi, Third Edition
3672 : // Update, John Wiley & Sons, 1998; ISO 15099 has 8 for this factor, which is for flow through a tube.
3673 0 : BVGap = 12.0 * ViscAir * GapHeight / pow_2(GapDepth);
3674 : // Adding 0.000001 and 0.000002 in the following gives ATopLRH = ABotLRH =
3675 : // 0.25*(ALeftGap + ARightGap + AHolesGap) when ABotGap = ATopGap = 0.0 (shade/blind sealed at
3676 : // bottom and top but possibly open at left side, right side and/or in-shade/blind)
3677 0 : ATopLRH = 0.5 * ((ATopGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
3678 0 : ABotLRH = 0.5 * ((ABotGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
3679 0 : if (TGapOld > TGapInlet) {
3680 0 : AEqInlet = ABotGap + ATopLRH;
3681 0 : AEqOutlet = ATopGap + ABotLRH;
3682 : } else {
3683 0 : AEqOutlet = ABotGap + ATopLRH;
3684 0 : AEqInlet = ATopGap + ABotLRH;
3685 : }
3686 : // Adding 0.000001 in the following gives very large value of Zinlet for AEqInlet = 0 and
3687 : // very large value of Zoutlet for AEqInlet = 0; this gives VGap close to zero, as required
3688 : // when there is no inlet and/or outlet for air. This then reduces to the
3689 : // case of a completely sealed shade, in which hcv = 2*hGapStill and QConvGap = 0.
3690 0 : Zinlet = pow_2(AGap / (0.6 * AEqInlet + 0.000001) - 1.0);
3691 0 : Zoutlet = pow_2(AGap / (0.6 * AEqOutlet + 0.000001) - 1.0);
3692 0 : AVGap = 0.5 * RhoAir * (1 + Zinlet + Zoutlet);
3693 0 : RhoTRef = wm->AirProps[0] * Constant::Kelvin;
3694 0 : CVGap = RhoTRef * 9.81 * GapHeight * s_surf->Surface(SurfNum).SinTilt * (TGapOld - TGapInlet) / (TGapOld * TGapInlet);
3695 :
3696 : // Solution of quadratic equation in VGap
3697 0 : VGap = (std::sqrt(pow_2(BVGap) + std::abs(4.0 * AVGap * CVGap)) - BVGap) / (2.0 * AVGap);
3698 0 : hcv = 2.0 * hGapStill + 4.0 * VGap;
3699 0 : GapHeightChar = RhoAir * 1008.0 * GapDepth * VGap / (2.0 * hcv);
3700 : // The following avoids divide by zero and exponential underflow
3701 0 : if (GapHeightChar == 0.0) {
3702 0 : TGapOutlet = TAve;
3703 0 : } else if ((GapHeight / GapHeightChar) > 15.0) {
3704 0 : TGapOutlet = TAve;
3705 : } else {
3706 0 : TGapOutlet = TAve - (TAve - TGapInlet) * std::exp(-GapHeight / GapHeightChar);
3707 : }
3708 0 : TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet);
3709 :
3710 : // Convective heat flow from gap to room air for interior shade or blind
3711 0 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3712 0 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapNew - Constant::Kelvin);
3713 0 : QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet);
3714 : // Exclude convection to gap due to divider, if present; divider convection handled
3715 : // separately in CalcWinFrameAndDividerTemps
3716 0 : QConvGap *= 0.5 * (1.0 + s_surf->Surface(SurfNum).Area / (s_surf->Surface(SurfNum).Area + s_surf->SurfWinDividerArea(SurfNum)));
3717 : }
3718 : }
3719 :
3720 : //****************************************************************************
3721 :
3722 0 : void BetweenGlassShadeNaturalFlow(EnergyPlusData &state,
3723 : int const SurfNum, // Surface number
3724 : int const iter, // Iteration number for glass heat balance calculation
3725 : Real64 &VGap, // Gas velocity in gaps (m/s)
3726 : Array1A<Real64> TGapNew, // Current-iteration average gas temp in gaps (K)
3727 : Array1A<Real64> hcv // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
3728 : )
3729 : {
3730 :
3731 : // SUBROUTINE INFORMATION:
3732 : // AUTHOR F. Winkelmann
3733 : // DATE WRITTEN December 2002
3734 : // MODIFIED na
3735 : // RE-ENGINEERED na
3736 :
3737 : // PURPOSE OF THIS SUBROUTINE:
3738 : // Called by SolveForWindowTemperatures for windows that have a
3739 : // between-glass shade or blind in place.
3740 : // Solves for gas flow in the two gaps on either side of shade/blind.
3741 : // Finds average temperature of gas in the two gaps, and the coefficient
3742 : // for convective heat transfer from glass to gap gas and shade/blind to gap gas
3743 : // for the two gaps. The two gaps are assumed to have the same depth so that the
3744 : // gas velocity due to natural convection is the same in the two gaps.
3745 : // The Between-glass shade/blind is between the two glass layers of double glazing
3746 : // or between the two inner glass layers of triple glazing. The quadruple glazing
3747 : // case is not considered.
3748 :
3749 : // METHODOLOGY EMPLOYED:
3750 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
3751 : // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
3752 :
3753 : // Argument array dimensioning
3754 0 : TGapNew.dim(2);
3755 0 : hcv.dim(2);
3756 :
3757 : int ConstrNumSh; // Shaded construction number
3758 : int MatNumSh; // Material number of shade/blind layer
3759 : // In the following, "gaps" refer to the gaps on either side of the shade/blind
3760 0 : Array1D<Real64> TGlassFace(2); // Temperature of glass surfaces facing gaps (K)
3761 0 : Array1D<Real64> TShadeFace(2); // Temperature of shade surfaces facing gaps (K)
3762 0 : Array1D<Real64> hGapStill(2); // Still-air conduction/convection coeffs for the gaps (W/m2-K)
3763 0 : Array1D<Real64> TGapOld(2); // Previous-iteration average gas temp in gaps (K)
3764 : Real64 GapHeight; // Vertical length of glass-shade/blind gap (m)
3765 : Real64 GapDepth; // Distance from shade/blind to glass; assumed same for both gaps (m)
3766 0 : Array1D<Real64> RhoGas(2); // Density of gap gas at a temperature of TGapOld (kg/m3)
3767 : Real64 RhoTRef; // Density of gap gas at reference temp = KelvinConvK (kg/m3)
3768 0 : Array1D<Real64> ViscGas(2); // Viscosity of gap gas at a temperature of TGapOld (kg/m3)
3769 : Real64 RhoGasZero; // Gas density at KelvinConvK
3770 : Real64 ViscGasZero; // Gas viscosity at KelvinConvK (not used)
3771 : Real64 AGap; // Cross sectional area of gaps (m2); for vertical window, this
3772 : // is in horizontal plane normal to window.
3773 : Real64 ATopGap; // Area of the top and bottom openings of shade/blind (m2)
3774 : Real64 ABotGap;
3775 : Real64 ALeftGap; // Area of the left and right openings of shade/blind (m2)
3776 : Real64 ARightGap;
3777 : Real64 AHolesGap; // Area of the holes in the shade/blind (assumed homogeneously
3778 : // distributed) (m2)
3779 : Real64 ATopLRH; // Intermediate variables
3780 : Real64 ABotLRH;
3781 : Real64 AEqInlet; // Equivalent inlet and outlet opening areas (m2)
3782 : Real64 AEqOutlet;
3783 : Real64 Zinlet; // Inlet and outlet pressure loss factors
3784 : Real64 Zoutlet;
3785 : Real64 AVGap; // Coeff. of VGap**2 term in pressure balance equation
3786 : Real64 BVGap; // Coeff. of VGap term in pressure balance equation
3787 : Real64 CVGap; // VGap-independent term in pressure balance equation
3788 0 : Array1D<Real64> GapHeightChar(2); // Characteristic height of the gap gas temperature profile (m)
3789 0 : Array1D<Real64> EpsChar(2); // EXP(-GapHeight/GapHeightChar(IGap))
3790 0 : Array1D<Real64> TAve(2); // Average of TGlass and TShade for the gaps (K)
3791 : Real64 con; // Gap gas conductivity and derivative
3792 : Real64 gr; // Gap gas Grashof number
3793 : Real64 pr; // Gap gas Prandtl number
3794 : Real64 nu; // Gap gas Nusselt number
3795 : WinShadingType ShadeFlag; // Shading flag
3796 : int IGapInc; // Gap increment (0 or 1)
3797 :
3798 0 : auto &wm = state.dataWindowManager;
3799 0 : auto &s_mat = state.dataMaterial;
3800 0 : auto &s_surf = state.dataSurface;
3801 :
3802 0 : auto &surf = s_surf->Surface(SurfNum);
3803 :
3804 0 : ConstrNumSh = surf.activeShadedConstruction;
3805 0 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
3806 :
3807 0 : if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double glazing
3808 0 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(3);
3809 0 : IGapInc = 0;
3810 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3811 0 : TGlassFace(IGap) = wm->thetas[IGap];
3812 0 : TShadeFace(IGap) = wm->thetas[IGap + 3];
3813 : }
3814 : } else { // Triple glazing
3815 0 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(5);
3816 0 : IGapInc = 1;
3817 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3818 0 : TGlassFace(IGap) = wm->thetas[IGap + 2];
3819 0 : TShadeFace(IGap) = wm->thetas[IGap + 5];
3820 : }
3821 : }
3822 :
3823 0 : auto const *matShadingDevice = dynamic_cast<Material::MaterialShadingDevice const *>(s_mat->materials(MatNumSh));
3824 :
3825 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3826 0 : TAve(IGap) = 0.5 * (TGlassFace(IGap) + TShadeFace(IGap));
3827 0 : if (iter == 0) {
3828 0 : TGapOld(IGap) = TAve(IGap);
3829 : } else {
3830 0 : TGapOld(IGap) = TGapNew(IGap);
3831 : }
3832 : // Conductance of gaps on either side of shade/blind assuming gaps are sealed
3833 0 : WindowGasConductance(state, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, con, pr, gr);
3834 0 : NusseltNumber(state, SurfNum, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, gr, pr, nu);
3835 0 : hGapStill(IGap) = con / wm->gaps[IGap + IGapInc - 1].width * nu;
3836 : }
3837 :
3838 : // For near-horizontal windows (i.e., no more than 5 deg from horizontal) assume
3839 : // there is no air flow thru gap
3840 :
3841 0 : if (std::abs(s_surf->Surface(SurfNum).SinTilt) < 0.0872) {
3842 0 : VGap = 0.0;
3843 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3844 0 : hcv(IGap) = 2.0 * hGapStill(IGap);
3845 0 : TGapNew(IGap) = TAve(IGap);
3846 : }
3847 0 : return;
3848 : }
3849 :
3850 0 : GapHeight = s_surf->Surface(SurfNum).Height;
3851 0 : GapDepth = wm->gaps[IGapInc].width;
3852 0 : AGap = GapDepth * s_surf->Surface(SurfNum).Width;
3853 :
3854 0 : ATopGap = matShadingDevice->topOpeningMult * AGap;
3855 0 : ABotGap = matShadingDevice->bottomOpeningMult * AGap;
3856 0 : ALeftGap = matShadingDevice->leftOpeningMult * GapHeight * GapDepth;
3857 0 : ARightGap = matShadingDevice->rightOpeningMult * GapHeight * GapDepth;
3858 : // For blinds, airFlowPermeability depends on slat angle which is a property of the surface, not the material
3859 0 : if (matShadingDevice->group == Material::Group::Blind) {
3860 0 : AHolesGap = s_surf->surfShades(SurfNum).blind.airFlowPermeability * GapHeight * surf.Width;
3861 : } else {
3862 0 : AHolesGap = matShadingDevice->airFlowPermeability * GapHeight * surf.Width;
3863 : }
3864 :
3865 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3866 0 : WindowGasPropertiesAtTemp(state, TGapOld(IGap), IGap + IGapInc, RhoGas(IGap), ViscGas(IGap));
3867 : }
3868 :
3869 0 : BVGap = 12.0 * (ViscGas(1) + ViscGas(2)) * GapHeight / pow_2(GapDepth);
3870 : // Adding 0.000001 and 0.000002 in the following gives ATopLRH = ABotLRH =
3871 : // 0.25*(ALeftGap + ARightGap + AHolesGap) when ABotGap = ATopGap = 0.0 (shade/blind sealed at
3872 : // bottom and top but possibly open at left side, right side and/or in shade/blind)
3873 0 : ATopLRH = 0.5 * ((ATopGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
3874 0 : ABotLRH = 0.5 * ((ABotGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
3875 0 : AEqInlet = ABotGap + ATopLRH;
3876 0 : AEqOutlet = ATopGap + ABotLRH;
3877 :
3878 : // Adding 0.000001 in the following gives very large value of Zinlet for AEqInlet = 0 and
3879 : // very large value of Zoutlet for AEqInlet = 0; this gives VGap close to zero, as required
3880 : // when there is no inlet and/or outlet for air. This then reduces to the
3881 : // case of a completely sealed shade, in which hcv = 2*hGapStill and QConvGap = 0.
3882 0 : Zinlet = pow_2(AGap / (0.6 * AEqInlet + 0.000001) - 1.0);
3883 0 : Zoutlet = pow_2(AGap / (0.6 * AEqOutlet + 0.000001) - 1.0);
3884 0 : AVGap = 0.5 * (RhoGas(1) + RhoGas(2)) * (1.0 + Zinlet + Zoutlet);
3885 0 : WindowGasPropertiesAtTemp(state, Constant::Kelvin, 1 + IGapInc, RhoGasZero, ViscGasZero);
3886 0 : RhoTRef = RhoGasZero * Constant::Kelvin;
3887 0 : CVGap = RhoTRef * 9.81 * GapHeight * s_surf->Surface(SurfNum).SinTilt * (TGapOld(1) - TGapOld(2)) / (TGapOld(1) * TGapOld(2));
3888 :
3889 : // Solution of quadratic equation in VGap
3890 :
3891 0 : VGap = (std::sqrt(pow_2(BVGap) + std::abs(4 * AVGap * CVGap)) - BVGap) / (2 * AVGap);
3892 :
3893 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
3894 0 : hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
3895 0 : GapHeightChar(IGap) = RhoGas(IGap) * 1008.0 * GapDepth * VGap / (2.0 * hcv(IGap));
3896 : // The following avoids divide by zero and exponential underflow
3897 0 : if (GapHeightChar(IGap) == 0.0) {
3898 0 : EpsChar(IGap) = 0.0;
3899 0 : } else if ((GapHeight / GapHeightChar(IGap)) > 15.0) {
3900 0 : EpsChar(IGap) = 0.0;
3901 : } else {
3902 0 : EpsChar(IGap) = std::exp(-GapHeight / GapHeightChar(IGap));
3903 : }
3904 : }
3905 :
3906 0 : TGapNew(1) =
3907 0 : TAve(1) - (TAve(1) - TAve(2)) * (GapHeightChar(1) / GapHeight) * (1 - EpsChar(1)) * (1 - EpsChar(2)) / (1 - EpsChar(1) * EpsChar(2));
3908 :
3909 0 : TGapNew(2) =
3910 0 : TAve(2) - (TAve(2) - TAve(1)) * (GapHeightChar(2) / GapHeight) * (1 - EpsChar(1)) * (1 - EpsChar(2)) / (1 - EpsChar(1) * EpsChar(2));
3911 0 : }
3912 :
3913 : //****************************************************************************
3914 :
3915 0 : void BetweenGlassForcedFlow(EnergyPlusData &state,
3916 : int const SurfNum, // Surface number
3917 : int const iter, // Iteration number for glass heat balance calculation
3918 : Real64 &VGap, // Air velocity in airflow gap (m/s)
3919 : Real64 &TGapNew, // Current-iteration average air temp in airflow gap (K)
3920 : Real64 &TGapOutlet, // Temperature of air leaving glass-shade/blind gap at top for upward
3921 : Real64 &hcv, // Convection coefficient from gap glass faces to gap air (W/m2-K)
3922 : Real64 &QConvGap // Convective heat gain from air flow gap (W)
3923 : )
3924 : {
3925 :
3926 : // SUBROUTINE INFORMATION:
3927 : // AUTHOR F. Winkelmann
3928 : // DATE WRITTEN February 2003
3929 : // MODIFIED na
3930 : // RE-ENGINEERED na
3931 :
3932 : // PURPOSE OF THIS SUBROUTINE:
3933 : // Called by SolveForWindowTemperatures for "airflow windows",i.e., windows
3934 : // with forced airflow in one of the gaps between layers of glass. Based on
3935 : // the velocity of airflow through gap, finds effective temperature of gap air,
3936 : // convective heat transfer coefficient from glass to gap air,
3937 : // the gap outlet temperature, and the outlet convective heat flow.
3938 :
3939 : // Called only for double and triple glazing. For triple glazing the airflow
3940 : // is assumed to be between the inner two layers of glass (glass layers 2 and 3).
3941 :
3942 : // METHODOLOGY EMPLOYED:
3943 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
3944 : // Detailed Calculations"
3945 :
3946 : // Locals
3947 : // SUBROUTINE ARGUMENT DEFINITIONS:
3948 : // air flow or bottom for downward air flow (K)
3949 :
3950 : int ConstrNum; // Construction number of surface
3951 : int NGlass; // Number of glass layers in construction
3952 : int GapNum; // Number of airflow gap
3953 : Real64 TGapInlet; // Temperature of air entering glass-shade/blind gap at bottom for upward
3954 : // air flow or top for downward air flow (K)
3955 : Real64 TGlassFace1; // Temperature of left-hand glass surface facing airflow gap (K)
3956 : Real64 TGlassFace2; // Temperature of right-hand glass surface facing airflow gap (K)
3957 : Real64 hGapStill; // Still-air gap conduction/convection coeff (W/m2-K)
3958 : Real64 TGapOld; // Previous-iteration average air temp in airflow gap (K)
3959 : Real64 GapHeight; // Vertical length of airflow gap (m)
3960 : Real64 GapDepth; // Thickness of airflow gap (m)
3961 : Real64 RhoAir; // Density of airflow gap air at a temperature of TGapOld (kg/m3)
3962 : Real64 AGap; // Cross sectional area of airflow gap (m2); for vertical window, this
3963 : // is in horizontal plane normal to window.
3964 : Real64 GapHeightChar; // Characteristic height of the airflow gap air temperature profile (m)
3965 : Real64 TAve; // Average of TGlassFace1 and TGlassFace2 (K)
3966 : // REAL(r64) :: AirProps(8) ! Air properties
3967 : Real64 con; // Gap conductivity and derivative
3968 : Real64 gr; // Gap air Grashof number
3969 : Real64 pr; // Gap air Prandtl number
3970 : Real64 nu; // Gap air Nusselt number
3971 :
3972 : // Air properties
3973 : // Dens dDens/dT Con dCon/dT Vis dVis/dT Prandtl dPrandtl/dT
3974 : // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72, 1.8d-3 /
3975 :
3976 0 : auto &s_mat = state.dataMaterial;
3977 0 : auto &s_surf = state.dataSurface;
3978 0 : auto const &wm = state.dataWindowManager;
3979 :
3980 0 : auto const &surf = s_surf->Surface(SurfNum);
3981 :
3982 0 : ConstrNum = surf.Construction;
3983 0 : NGlass = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
3984 0 : TGlassFace1 = wm->thetas[2 * NGlass - 3];
3985 0 : TGlassFace2 = wm->thetas[2 * NGlass - 2];
3986 0 : GapNum = NGlass - 1;
3987 0 : TAve = 0.5 * (TGlassFace1 + TGlassFace2);
3988 :
3989 0 : if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
3990 0 : TGapInlet = wm->tin; // Source is inside air
3991 : } else {
3992 0 : TGapInlet = wm->tout; // Source is outside air
3993 : }
3994 :
3995 0 : if (iter == 0) {
3996 0 : TGapOld = 0.5 * (TAve + TGapInlet);
3997 : } else {
3998 0 : TGapOld = TGapNew;
3999 : }
4000 :
4001 : // Conductance of gap assuming it is sealed
4002 0 : WindowGasConductance(state, TGlassFace1, TGlassFace2, GapNum, con, pr, gr);
4003 0 : NusseltNumber(state, SurfNum, TGlassFace1, TGlassFace2, GapNum, gr, pr, nu);
4004 0 : hGapStill = con / wm->gaps[GapNum - 1].width * nu;
4005 0 : GapHeight = surf.Height;
4006 0 : GapDepth = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(2 * NGlass - 2))->Thickness;
4007 0 : AGap = GapDepth * surf.Width;
4008 0 : VGap = s_surf->SurfWinAirflowThisTS(SurfNum) / GapDepth;
4009 0 : hcv = 2.0 * hGapStill + 4.0 * VGap;
4010 0 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapOld - Constant::Kelvin);
4011 0 : GapHeightChar = RhoAir * 1008.0 * GapDepth * VGap / (2.0 * hcv);
4012 : // The following avoids divide by zero and exponential underflow
4013 0 : if (GapHeightChar == 0.0) {
4014 0 : TGapOutlet = TAve;
4015 0 : } else if ((GapHeight / GapHeightChar) > 15.0) {
4016 0 : TGapOutlet = TAve;
4017 : } else {
4018 0 : TGapOutlet = TAve - (TAve - TGapInlet) * std::exp(-GapHeight / GapHeightChar);
4019 : }
4020 0 : TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet);
4021 : // Convective heat flow from gap [W]
4022 0 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapNew - Constant::Kelvin);
4023 0 : QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet);
4024 0 : } // BetweenGlassForcedFlow()
4025 :
4026 : //****************************************************************************
4027 :
4028 0 : void BetweenGlassShadeForcedFlow(EnergyPlusData &state,
4029 : int const SurfNum, // Surface number
4030 : int const iter, // Iteration number for glass heat balance calculation
4031 : Real64 &VGap, // Air velocity in each gap (m/s)
4032 : Array1A<Real64> TGapNew, // Current-iteration average gas temp in gaps (K)
4033 : Real64 &TGapOutletAve, // Average of TGapOutlet(1) and TGapOutlet(2) (K)
4034 : Array1A<Real64> hcv, // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
4035 : Real64 &QConvTot // Sum of convective heat flow from gaps (W)
4036 : )
4037 : {
4038 :
4039 : // SUBROUTINE INFORMATION:
4040 : // AUTHOR F. Winkelmann
4041 : // DATE WRITTEN February 2003
4042 : // MODIFIED na
4043 : // RE-ENGINEERED na
4044 :
4045 : // PURPOSE OF THIS SUBROUTINE:
4046 : // Called by SolveForWindowTemperatures for airflow windows with a
4047 : // between-glass shade or blind over which fan-forced air flows.
4048 : // Based on the air flow velocity (which is assumed to be the same in the
4049 : // gaps on either side of the shade/blind), finds, for each gap: the average
4050 : // air temperature, the shade/blind or glass surface to air convective heat
4051 : // transfer coefficient, the gap outlet temperature, and the outlet convective heat flow.
4052 :
4053 : // Called only for double and triple glazing. For triple glazing the airflow
4054 : // is assumed to be between the inner two layers of glass (glass layers 2 and 3),
4055 : // between which the shade/blind is located.
4056 :
4057 : // METHODOLOGY EMPLOYED:
4058 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
4059 : // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
4060 :
4061 : // Argument array dimensioning
4062 0 : TGapNew.dim(2);
4063 0 : hcv.dim(2);
4064 :
4065 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4066 : int ConstrNumSh; // Shaded construction number
4067 : // In the following, "gaps" refer to the gaps on either side of the shade/blind
4068 0 : Array1D<Real64> TGlassFace(2); // Temperature of glass surfaces facing gaps (K)
4069 0 : Array1D<Real64> TShadeFace(2); // Temperature of shade surfaces facing gaps (K)
4070 0 : Array1D<Real64> hGapStill(2); // Still-air conduction/convection coeffs for the gaps (W/m2-K)
4071 0 : Array1D<Real64> TGapOld(2); // Previous-iteration average gas temp in gaps (K)
4072 : Real64 GapHeight; // Vertical length of glass-shade/blind gap (m)
4073 : Real64 GapDepth; // Distance from shade/blind to glass; assumed same for both gaps (m)
4074 0 : Array1D<Real64> RhoAir(2); // Density of gap air (kg/m3)
4075 : Real64 AGap; // Cross sectional area of each gap (m2); for vertical window, this
4076 : // is in horizontal plane normal to window.
4077 : Real64 TGapInlet; // Gap inlet air temperature (K)
4078 0 : Array1D<Real64> TGapOutlet(2); // Gap outlet air temperature (K)
4079 0 : Array1D<Real64> QConvGap(2); // Convective heat flow from each gap (W)
4080 0 : Array1D<Real64> GapHeightChar(2); // Characteristic height of the gap air temperature profile (m)
4081 0 : Array1D<Real64> TAve(2); // Average of TGlass and TShade for the gaps (K)
4082 : Real64 con; // Gap air conductivity and derivative
4083 : Real64 gr; // Gap air Grashof number
4084 : Real64 pr; // Gap air Prandtl number
4085 : Real64 nu; // Gap air Nusselt number
4086 : WinShadingType ShadeFlag; // Shading flag
4087 : int IGapInc; // Gap increment; =0, double glass, =1, triple glass
4088 : // REAL(r64) :: AirProps(8) ! Air properties
4089 :
4090 0 : auto &s_surf = state.dataSurface;
4091 0 : auto const &wm = state.dataWindowManager;
4092 :
4093 : // Air properties
4094 : // Dens dDens/dT Con dCon/dT Vis dVis/dT Prandtl dPrandtl/dT
4095 : // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72, 1.8d-3 /
4096 :
4097 0 : ConstrNumSh = s_surf->Surface(SurfNum).activeShadedConstruction;
4098 0 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
4099 :
4100 0 : if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double glazing
4101 0 : IGapInc = 0;
4102 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
4103 0 : TGlassFace(IGap) = wm->thetas[IGap];
4104 0 : TShadeFace(IGap) = wm->thetas[IGap + 3];
4105 : }
4106 : } else { // Triple glazing
4107 0 : IGapInc = 1;
4108 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
4109 0 : TGlassFace(IGap) = wm->thetas[IGap + 2];
4110 0 : TShadeFace(IGap) = wm->thetas[IGap + 5];
4111 : }
4112 : }
4113 :
4114 0 : if (s_surf->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
4115 0 : TGapInlet = wm->tin;
4116 : } else {
4117 0 : TGapInlet = wm->tout;
4118 : }
4119 :
4120 0 : GapHeight = s_surf->Surface(SurfNum).Height;
4121 0 : GapDepth = wm->gaps[IGapInc].width;
4122 0 : AGap = GapDepth * s_surf->Surface(SurfNum).Width;
4123 : // Factor of 2 below assumes gaps on either side of shade/blind have same depth
4124 0 : VGap = s_surf->SurfWinAirflowThisTS(SurfNum) / (2.0 * GapDepth);
4125 :
4126 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
4127 0 : TAve(IGap) = 0.5 * (TGlassFace(IGap) + TShadeFace(IGap));
4128 0 : if (iter == 0) {
4129 0 : TGapOld(IGap) = TAve(IGap);
4130 : } else {
4131 0 : TGapOld(IGap) = TGapNew(IGap);
4132 : }
4133 : // Conductance of gaps on either side of shade/blind assuming gaps are sealed
4134 0 : WindowGasConductance(state, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, con, pr, gr);
4135 0 : NusseltNumber(state, SurfNum, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, gr, pr, nu);
4136 0 : hGapStill(IGap) = con / wm->gaps[IGap + IGapInc - 1].width * nu;
4137 : // Shade/blind or glass surface to air convection coefficient
4138 0 : hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
4139 0 : RhoAir(IGap) = wm->AirProps[0] + wm->AirProps[1] * (TGapOld(IGap) - Constant::Kelvin);
4140 0 : hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
4141 0 : GapHeightChar(IGap) = RhoAir(IGap) * 1008.0 * GapDepth * VGap / (2.0 * hcv(IGap));
4142 : // The following avoids divide by zero and exponential underflow
4143 0 : if (GapHeightChar(IGap) == 0.0) {
4144 0 : TGapOutlet(IGap) = TAve(IGap);
4145 0 : } else if ((GapHeight / GapHeightChar(IGap)) > 15.0) {
4146 0 : TGapOutlet(IGap) = TAve(IGap);
4147 : } else {
4148 0 : TGapOutlet(IGap) = TAve(IGap) - (TAve(IGap) - TGapInlet) * std::exp(-GapHeight / GapHeightChar(IGap));
4149 : }
4150 0 : TGapNew(IGap) = TAve(IGap) - (GapHeightChar(IGap) / GapHeight) * (TGapOutlet(IGap) - TGapInlet);
4151 : // Convective heat flow from gap [W]
4152 0 : RhoAir(IGap) = wm->AirProps[0] + wm->AirProps[1] * (TGapNew(IGap) - Constant::Kelvin);
4153 0 : QConvGap(IGap) = RhoAir(IGap) * AGap * VGap * 1008.0 * (TGapOutlet(IGap) - TGapInlet);
4154 : }
4155 :
4156 0 : QConvTot = QConvGap(1) + QConvGap(2);
4157 0 : TGapOutletAve = 0.5 * (TGapOutlet(1) + TGapOutlet(2));
4158 0 : } // BetweenGlassShadeForcedFlow()
4159 :
4160 : //****************************************************************************
4161 :
4162 204621 : void LUdecomposition(EnergyPlusData &state,
4163 : Array2<Real64> &ajac, // As input: matrix to be decomposed;
4164 : int const n, // Dimension of matrix
4165 : Array1D_int &indx, // Vector of row permutations
4166 : int &d // +1 if even number of row interchange is even, -1
4167 : )
4168 : {
4169 :
4170 : // SUBROUTINE INFORMATION:
4171 : // AUTHOR F. Winkelmann, adapted from Numerical Recipes
4172 : // DATE WRITTEN February 2000
4173 :
4174 : // PURPOSE OF THIS SUBROUTINE:
4175 : // Performs LU decomposition of a matrix.
4176 :
4177 : // SUBROUTINE ARGUMENT DEFINITIONS:
4178 : // as output: decomposed matrix
4179 : // if odd
4180 :
4181 : int imax; // Temporary variable
4182 : // as output: decomposed matrix
4183 :
4184 204621 : assert(n <= 10); // vv sizing
4185 204621 : std::array<Real64, 10> vv = {0.0}; // Stores the implicit scaling of each row
4186 :
4187 204621 : d = 1;
4188 803903 : for (int i = 1; i <= n; ++i) {
4189 599282 : Real64 aamax = 0.0;
4190 2558006 : for (int j = 1; j <= n; ++j) {
4191 1958724 : if (std::abs(ajac(j, i)) > aamax) aamax = std::abs(ajac(j, i));
4192 : }
4193 599282 : if (aamax == 0.0) ShowFatalError(state, "Singular matrix in LUdecomposition, window calculations");
4194 599282 : vv[i - 1] = 1.0 / aamax;
4195 : }
4196 803903 : for (int j = 1; j <= n; ++j) {
4197 1279003 : for (int i = 1; i <= j - 1; ++i) {
4198 679721 : Real64 sum = ajac(j, i);
4199 1059801 : for (int k = 1; k <= i - 1; ++k) {
4200 380080 : sum -= ajac(k, i) * ajac(j, k);
4201 : }
4202 679721 : ajac(j, i) = sum;
4203 : }
4204 599282 : Real64 aamax = 0.0;
4205 1878285 : for (int i = j; i <= n; ++i) {
4206 1279003 : Real64 sum = ajac(j, i);
4207 2338804 : for (int k = 1; k <= j - 1; ++k) {
4208 1059801 : sum -= ajac(k, i) * ajac(j, k);
4209 : }
4210 1279003 : ajac(j, i) = sum;
4211 1279003 : Real64 dum = vv[i - 1] * std::abs(sum);
4212 1279003 : if (dum >= aamax) {
4213 599282 : imax = i;
4214 599282 : aamax = dum;
4215 : }
4216 : }
4217 599282 : if (j != imax) {
4218 0 : for (int k = 1; k <= n; ++k) {
4219 0 : Real64 dum = ajac(k, imax);
4220 0 : ajac(k, imax) = ajac(k, j);
4221 0 : ajac(k, j) = dum;
4222 : }
4223 0 : d = -d;
4224 0 : vv[imax - 1] = vv[j - 1];
4225 : }
4226 599282 : indx(j) = imax;
4227 599282 : if (ajac(j, j) == 0.0) ajac(j, j) = Constant::rTinyValue;
4228 599282 : if (j != n) {
4229 394661 : Real64 dum = 1.0 / ajac(j, j);
4230 1074382 : for (int i = j + 1; i <= n; ++i) {
4231 679721 : ajac(j, i) *= dum;
4232 : }
4233 : }
4234 : }
4235 204621 : } // LUdecomposition()
4236 :
4237 : //**************************************************************************
4238 :
4239 368607 : void LUsolution([[maybe_unused]] EnergyPlusData &state,
4240 : Array2<Real64> const &a, // Matrix and vector in a.x = b;
4241 : int const n, // Dimension of a and b
4242 : Array1D_int const &indx, // Vector of row permutations
4243 : Array1D<Real64> &b // Matrix and vector in a.x = b;
4244 : )
4245 : {
4246 :
4247 : // SUBROUTINE INFORMATION:
4248 : // AUTHOR F. Winkelmann, adapted from Numerical Recipes
4249 : // DATE WRITTEN February 2000
4250 : // MODIFIED na
4251 : // RE-ENGINEERED na
4252 :
4253 : // PURPOSE OF THIS SUBROUTINE:
4254 : // Solves set of linear equations a.x = b
4255 :
4256 : // Locals
4257 : // SUBROUTINE ARGUMENT DEFINITIONS:
4258 : // b is also output as the solution, x
4259 : // b is also output as the solution, x
4260 :
4261 : Real64 sum; // Summation variable
4262 :
4263 368607 : int ii = 0;
4264 1623833 : for (int i = 1; i <= n; ++i) {
4265 1255226 : int ll = indx(i);
4266 1255226 : sum = b(ll);
4267 1255226 : b(ll) = b(i);
4268 1255226 : if (ii != 0) {
4269 1456962 : for (int j = ii; j <= i - 1; ++j) {
4270 898333 : sum -= a(j, i) * b(j);
4271 : }
4272 696597 : } else if (sum != 0.0) {
4273 368607 : ii = i;
4274 : }
4275 1255226 : b(i) = sum;
4276 : }
4277 1623833 : for (int i = n; i >= 1; --i) {
4278 1255226 : sum = b(i);
4279 2918863 : for (int j = i + 1; j <= n; ++j) {
4280 1663637 : sum -= a(j, i) * b(j);
4281 : }
4282 1255226 : b(i) = sum / a(i, i);
4283 : }
4284 368607 : } // LUsolution()
4285 :
4286 : //******************************************************************************
4287 :
4288 40358 : void WindowGasConductance(EnergyPlusData &state,
4289 : Real64 const tleft, // Temperature of gap surface closest to outside (K)
4290 : Real64 const tright, // Temperature of gap surface closest to zone (K)
4291 : int const IGap, // Gap number
4292 : Real64 &con, // Gap gas conductance (W/m2-K)
4293 : Real64 &pr, // Gap gas Prandtl number
4294 : Real64 &gr // Gap gas Grashof number
4295 : )
4296 : {
4297 :
4298 : // SUBROUTINE INFORMATION:
4299 : // AUTHOR Adapted by Fred Winkelmann from Window5 subroutine gasses
4300 : // DATE WRITTEN September 2001
4301 : // MODIFIED na
4302 : // RE-ENGINEERED na
4303 :
4304 : // PURPOSE OF THIS SUBROUTINE:
4305 : // Find the coefficient of convective/conductive heat transfer in the gas-filled gap
4306 : // between isothermal solid layers. The gap may be filled with a single gas or a gas mixture.
4307 :
4308 : // METHODOLOGY EMPLOYED:
4309 : // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
4310 : // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
4311 : // The equation numbers below correspond to those in the standard.
4312 :
4313 : // REFERENCES:
4314 : // Window5 source code; ISO 15099
4315 :
4316 40358 : constexpr Real64 pres(1.0e5); // Gap gas pressure (Pa)
4317 40358 : constexpr Real64 gaslaw(8314.51); // Molar gas constant (J/kMol-K)
4318 40358 : Real64 const two_sqrt_2(2.0 * std::sqrt(2.0));
4319 :
4320 : int NMix; // Number of gases in a mixture
4321 : Real64 molmix; // Molecular weight of mixture
4322 :
4323 40358 : auto &wm = state.dataWindowManager;
4324 :
4325 : Real64 kpmix; // Monotonic thermal conductivity of mixture
4326 : Real64 kdpmix;
4327 : Real64 kmix; // For accumulating conductance of gas mixture
4328 : Real64 mumix; // For accumulating viscosity of gas mixture
4329 40358 : Real64 visc(0.0); // Dynamic viscosity of mixture at tmean (g/m-s)
4330 40358 : Real64 cp(0.0); // Specific heat of mixture at tmean (J/m3-K)
4331 40358 : Real64 dens(0.0); // Density of mixture at tmean (kg/m3)
4332 : Real64 cpmixm; // Gives cp when divided by molmix
4333 : Real64 phimup; // Numerator factor
4334 : Real64 downer; // Denominator factor
4335 : Real64 psiup; // Numerator factor
4336 : Real64 psiterm; // Factor
4337 : Real64 phikup; // Numerator factor
4338 : Real64 rhomix; // Density of gas mixture (kg/m3)
4339 :
4340 40358 : std::array<Real64, 10> mukpdwn = {0.0}; // Denominator term
4341 40358 : std::array<Real64, 10> kpdown = {0.0}; // Denominator terms
4342 40358 : std::array<Real64, 10> kdpdown = {0.0};
4343 : // Conductivity term accounting for additional energy moved by the diffusional transport of internal energy in polyatomic gases.
4344 40358 : std::array<Real64, 10> kdblprm = {0.0};
4345 40358 : std::array<Real64, 10> frct = {0.0}; // Fraction of each gas in a mixture
4346 40358 : std::array<Real64, 10> kprime = {0.0}; // Monotonic thermal conductivity
4347 :
4348 40358 : std::array<Real64, 10> fvis = {0.0}; // Viscosity of each gas in a mixture (g/m-s)
4349 40358 : std::array<Real64, 10> fcon = {0.0}; // Conductance of each gas in a mixture (W/m2-K)
4350 40358 : std::array<Real64, 10> fdens = {0.0}; // Density of each gas in a mixture (kg/m3)
4351 40358 : std::array<Real64, 10> fcp = {0.0}; // Specific heat of each gas in a mixture (J/m3-K)
4352 :
4353 : // Autodesk:Logic Either assert NMix>0 or handle NMix<=0 in logic so that con and locals guar. initialized before use
4354 40358 : NMix = wm->gaps[IGap - 1].numGases;
4355 :
4356 80716 : for (int IMix = 0; IMix < NMix; ++IMix) {
4357 40358 : frct[IMix] = wm->gaps[IGap - 1].gasFracts[IMix];
4358 : }
4359 :
4360 40358 : Real64 const tmean(0.5 * (tleft + tright)); // Average gap gas temperature (K)
4361 40358 : Real64 const tmean_2(pow_2(tmean));
4362 :
4363 40358 : auto const &wmgas0 = wm->gaps[IGap - 1].gases[0];
4364 40358 : fcon[0] = wmgas0.con.c0 + wmgas0.con.c1 * tmean + wmgas0.con.c2 * tmean_2;
4365 40358 : fvis[0] = wmgas0.vis.c0 + wmgas0.vis.c1 * tmean + wmgas0.vis.c2 * tmean_2;
4366 40358 : fcp[0] = wmgas0.cp.c0 + wmgas0.cp.c1 * tmean + wmgas0.cp.c2 * tmean_2;
4367 40358 : fdens[0] = pres * wmgas0.wght / (gaslaw * tmean); // Density using ideal gas law:
4368 : // rho=(presure*molecweight)/(gasconst*tmean)
4369 :
4370 40358 : if (NMix == 1) { // Single gas
4371 40358 : con = fcon[0];
4372 40358 : visc = fvis[0];
4373 40358 : cp = fcp[0];
4374 40358 : dens = fdens[0];
4375 0 : } else if (NMix > 1) { // Multiple gases; calculate mixture properties
4376 0 : molmix = frct[0] * wmgas0.wght; // initialize eq. 56
4377 0 : cpmixm = molmix * fcp[0]; // initialize eq. 58
4378 0 : kprime[0] = 3.75 * (gaslaw / wmgas0.wght) * fvis[0]; // eq. 67
4379 0 : kdblprm[0] = fcon[0] - kprime[0]; // eq. 67
4380 :
4381 : // Initialize summations for eqns 60-66
4382 0 : mumix = 0.0;
4383 0 : kpmix = 0.0;
4384 0 : kdpmix = 0.0;
4385 0 : mukpdwn[0] = 1.0;
4386 0 : kpdown[0] = 1.0;
4387 0 : kdpdown[0] = 1.0;
4388 :
4389 : // Calculate properties of mixture constituents
4390 0 : for (int i = 2; i <= NMix; ++i) {
4391 0 : auto const &wmgas = wm->gaps[IGap - 1].gases[i - 1];
4392 :
4393 0 : fcon[i - 1] = wmgas.con.c0 + wmgas.con.c1 * tmean + wmgas.con.c2 * tmean_2;
4394 0 : fvis[i - 1] = wmgas.vis.c0 + wmgas.vis.c1 * tmean + wmgas.vis.c2 * tmean_2;
4395 0 : fcp[i - 1] = wmgas.cp.c0 + wmgas.cp.c1 * tmean + wmgas.cp.c2 * tmean_2;
4396 0 : molmix += frct[i - 1] * wmgas.wght; // eq. 56
4397 0 : cpmixm += frct[i - 1] * fcp[i - 1] * wmgas.wght; // eq. 58-59
4398 0 : kprime[i - 1] = 3.75 * gaslaw / wmgas.wght * fvis[i - 1]; // eq. 67
4399 0 : kdblprm[i - 1] = fcon[i - 1] - kprime[i - 1]; // eq. 68
4400 0 : mukpdwn[i - 1] = 1.0; // initialize denominator of eq. 60
4401 0 : kpdown[i - 1] = 1.0; // initialize denominator of eq. 63
4402 0 : kdpdown[i - 1] = 1.0; // initialize denominator of eq. 65
4403 : }
4404 :
4405 0 : for (int i = 1; i <= NMix; ++i) {
4406 0 : auto const &wmgasI = wm->gaps[IGap - 1].gases[i - 1];
4407 :
4408 0 : for (int j = 1; j <= NMix; ++j) {
4409 0 : auto const &wmgasJ = wm->gaps[IGap - 1].gases[j - 1];
4410 :
4411 : // numerator of equation 61
4412 0 : phimup = pow_2(1.0 + std::sqrt(fvis[i - 1] / fvis[j - 1]) * root_4(wmgasJ.wght / wmgasI.wght));
4413 : // denominator of eq. 61, 64 and 66
4414 0 : downer = two_sqrt_2 * std::sqrt(1 + (wmgasI.wght / wmgasJ.wght));
4415 : // calculate the denominator of eq. 60
4416 0 : if (i != j) mukpdwn[i - 1] += phimup / downer * frct[j - 1] / frct[i - 1];
4417 : // numerator of eq. 64; psiterm is the multiplied term in brackets
4418 0 : psiup = pow_2(1.0 + std::sqrt(kprime[i - 1] / kprime[j - 1]) * root_4(wmgasI.wght / wmgasJ.wght));
4419 0 : psiterm = 1.0 + 2.41 * (wmgasI.wght - wmgasJ.wght) * (wmgasI.wght - 0.142 * wmgasJ.wght) / pow_2(wmgasI.wght + wmgasJ.wght);
4420 : // using the common denominator, downer, calculate the denominator for eq. 63
4421 0 : if (i != j) kpdown[i - 1] += psiup * (psiterm / downer) * (frct[j - 1] / frct[i - 1]);
4422 : // calculate the numerator of eq. 66
4423 0 : phikup = pow_2(1.0 + std::sqrt(kprime[i - 1] / kprime[j - 1]) * root_4(wmgasI.wght / wmgasJ.wght));
4424 : // using the common denominator, downer, calculate the denominator for eq. 65
4425 0 : if (i != j) kdpdown[i - 1] += (phikup / downer) * (frct[j - 1] / frct[i - 1]);
4426 : }
4427 0 : mumix += fvis[i - 1] / mukpdwn[i - 1]; // eq. 60
4428 0 : kpmix += kprime[i - 1] / kpdown[i - 1]; // eq. 63
4429 0 : kdpmix += kdblprm[i - 1] / kdpdown[i - 1]; // eq. 65
4430 : }
4431 :
4432 : // Calculate the density of the mixture assuming an ideal gas
4433 0 : rhomix = pres * molmix / (gaslaw * tmean); // eq. 57
4434 0 : kmix = kpmix + kdpmix; // eq. 68-a
4435 :
4436 : // Final mixture properties
4437 0 : visc = mumix;
4438 0 : con = kmix;
4439 0 : dens = rhomix;
4440 0 : cp = cpmixm / molmix;
4441 :
4442 : } else {
4443 0 : assert(false);
4444 : } // End of check if single or multiple gases in gap
4445 :
4446 40358 : pr = cp * visc / con;
4447 40358 : gr = 9.807 * pow_3(wm->gaps[IGap - 1].width) * std::abs(tleft - tright) * pow_2(dens) / (tmean * pow_2(visc));
4448 40358 : } // WindowGasConductance()
4449 :
4450 : //******************************************************************************
4451 :
4452 0 : void WindowGasPropertiesAtTemp(EnergyPlusData const &state,
4453 : Real64 const tmean, // Temperature of gas in gap (K)
4454 : int const IGap, // Gap number
4455 : Real64 &dens, // Gap gas density at tmean (kg/m3)
4456 : Real64 &visc // Gap gas dynamic viscosity at tmean (g/m-s)
4457 : )
4458 : {
4459 :
4460 : // SUBROUTINE INFORMATION:
4461 : // AUTHOR F. Winkelmann
4462 : // DATE WRITTEN December 2002
4463 : // MODIFIED na
4464 : // RE-ENGINEERED na
4465 :
4466 : // PURPOSE OF THIS SUBROUTINE:
4467 : // Finds the density and viscosity of the gas in a gap at a particular temperature.
4468 : // The gap may be filled with a single gas or a gas mixture.
4469 : // Based on Subroutine WindowGasConductance.
4470 :
4471 : // METHODOLOGY EMPLOYED:
4472 : // See Subr. WindowGasConductance
4473 :
4474 : // REFERENCES:
4475 : // See Subr. WindowGasConductance
4476 :
4477 0 : Real64 constexpr pres(1.0e5); // Gap gas pressure (Pa)
4478 0 : Real64 constexpr gaslaw(8314.51); // Molar gas constant (J/kMol-K)
4479 0 : Real64 const two_sqrt_2(2.0 * std::sqrt(2.0));
4480 :
4481 : int NMix; // Number of gases in a mixture
4482 : Real64 molmix; // Molecular weight of mixture
4483 0 : Array1D<Real64> mukpdwn(10); // Denominator term
4484 : Real64 mumix; // For accumulating viscosity of gas mixture
4485 : Real64 phimup; // Numerator factor
4486 : Real64 downer; // Denominator factor
4487 : Real64 rhomix; // Density of gas mixture (kg/m3)
4488 0 : Array1D<Real64> frct(10); // Fraction of each gas in a mixture
4489 0 : Array1D<Real64> fvis(10); // Viscosity of each gas in a mixture (g/m-s)
4490 0 : Array1D<Real64> fdens(10); // Density of each gas in a mixture (kg/m3)
4491 :
4492 0 : auto const &wm = state.dataWindowManager;
4493 :
4494 0 : NMix = wm->gaps[IGap - 1].numGases;
4495 :
4496 0 : for (int IMix = 1; IMix <= NMix; ++IMix) {
4497 0 : frct(IMix) = wm->gaps[IGap - 1].gasFracts[IMix - 1];
4498 : }
4499 :
4500 0 : Real64 const tmean_2(pow_2(tmean));
4501 0 : auto const &wmgas0 = wm->gaps[IGap - 1].gases[0];
4502 0 : fvis(1) = wmgas0.vis.c0 + wmgas0.vis.c1 * tmean + wmgas0.vis.c2 * tmean_2;
4503 0 : fdens(1) = pres * wmgas0.wght / (gaslaw * tmean); // Density using ideal gas law:
4504 : // rho=(presure*molecweight)/(gasconst*tmean)
4505 0 : if (NMix == 1) { // Single gas
4506 0 : visc = fvis(1);
4507 0 : dens = fdens(1);
4508 : } else { // Multiple gases; calculate mixture properties
4509 0 : molmix = frct(1) * wmgas0.wght; // initialize eq. 56
4510 :
4511 : // Initialize summations for eqns 60-66
4512 0 : mumix = 0.0;
4513 0 : mukpdwn(1) = 1.0;
4514 :
4515 : // Calculate properties of mixture constituents
4516 0 : for (int i = 2; i <= NMix; ++i) {
4517 0 : auto const &wmgas = wm->gaps[IGap - 1].gases[i - 1];
4518 0 : fvis(i) = wmgas.vis.c0 + wmgas.vis.c1 * tmean + wmgas.vis.c2 * tmean_2;
4519 0 : fdens(i) = pres * wmgas.wght / (gaslaw * tmean);
4520 0 : molmix += frct(i) * wmgas.wght; // eq. 56
4521 0 : mukpdwn(i) = 1.0; // initialize denominator of eq. 60
4522 : }
4523 :
4524 0 : for (int i = 1; i <= NMix; ++i) {
4525 0 : auto const &wmgasI = wm->gaps[IGap - 1].gases[i - 1];
4526 0 : for (int j = 1; j <= NMix; ++j) {
4527 0 : auto const &wmgasJ = wm->gaps[IGap - 1].gases[j - 1];
4528 : // numerator of equation 61
4529 0 : phimup = pow_2(1.0 + std::sqrt(fvis(i) / fvis(j)) * root_4(wmgasJ.wght / wmgasI.wght));
4530 : // denominator of eq. 61, 64 and 66
4531 0 : downer = two_sqrt_2 * std::sqrt(1 + (wmgasI.wght / wmgasJ.wght));
4532 : // calculate the denominator of eq. 60
4533 0 : if (i != j) mukpdwn(i) += phimup / downer * frct(j) / frct(i);
4534 : }
4535 0 : mumix += fvis(i) / mukpdwn(i); // eq. 60
4536 : }
4537 :
4538 : // Calculate the density of the mixture assuming an ideal gas
4539 0 : rhomix = pres * molmix / (gaslaw * tmean); // eq. 57
4540 :
4541 : // Final mixture properties
4542 0 : visc = mumix;
4543 0 : dens = rhomix;
4544 :
4545 : } // End of check if single or multiple gases in gap
4546 0 : } // WindowGasPropertiesAtTemp()
4547 :
4548 : //********************************************************************************
4549 :
4550 85895 : void StartingWindowTemps(EnergyPlusData &state,
4551 : int const SurfNum, // Surface number
4552 : Array1A<Real64> AbsRadShade // Short-wave radiation absorbed by shade/blind faces
4553 : )
4554 : {
4555 :
4556 : // SUBROUTINE INFORMATION:
4557 : // AUTHOR F. Winkelmann
4558 : // DATE WRITTEN January 2000
4559 : // MODIFIED March 2003, FW: add rough calc of increase above ambient of
4560 : // initial shade/blind temperature when shade/blind deployed
4561 : // after having been off.
4562 : // Jan 2004, FW: take into account whether storm window was added
4563 : // or removed in the current time step.
4564 : // RE-ENGINEERED na
4565 :
4566 : // PURPOSE OF THIS SUBROUTINE:
4567 : // Initializes face temperature distribution prior to iteration
4568 :
4569 : // Argument array dimensioning
4570 85895 : AbsRadShade.dim(2);
4571 :
4572 85895 : constexpr Real64 hrad(5.3); // Typical radiative conductance (W/m2-K)
4573 85895 : constexpr Real64 resgap(0.21); // Typical gap resistance (m2-K/W)
4574 :
4575 : WinShadingType ShadeFlag; // Shading flag
4576 85895 : Array1D<Real64> rguess(11); // Combined radiative/convective resistance (m2-K/W) of
4577 : // inside or outside air film, or gap
4578 : Real64 restot; // Total window resistance including outside
4579 : // and inside air films (m2-K/W)
4580 : Real64 temdiff; // Inside/outside air temperature difference (K)
4581 : Real64 ressum; // Resistance sum (m2-K/W)
4582 : int StormWinFlagPrevDay; // Previous time step value (day) of storm window flag
4583 : int StormWinFlagThisDay; // Current time step value (day) of storm window flag
4584 : // current time step value, nglface, if storm window was
4585 : // added or removed during the current time step).
4586 :
4587 85895 : auto &s_surf = state.dataSurface;
4588 85895 : auto const &wm = state.dataWindowManager;
4589 :
4590 85895 : StormWinFlagPrevDay = s_surf->SurfWinStormWinFlagPrevDay(SurfNum);
4591 85895 : StormWinFlagThisDay = s_surf->SurfWinStormWinFlag(SurfNum);
4592 :
4593 85895 : if (state.dataGlobal->BeginEnvrnFlag || (StormWinFlagThisDay != StormWinFlagPrevDay)) {
4594 :
4595 : // Guess values of glass face temperatures based on a simple resistance-network solution
4596 : // that (1) ignores short- and long-wave radiation (from lights and zone equipment) absorbed
4597 : // by the glass faces, and (2) assumes zero glass resistance. Absorbed solar is also ignored
4598 : // since the tests on BeginEnvrnFlag and storm window transition can be true only at midnight.
4599 : // Interaction with shade or blind, if one of these is present, is ignored. See below for
4600 : // separate calculation of shade/blind temperature.
4601 :
4602 122 : rguess(1) = 1.0 / (wm->hcout + hrad);
4603 122 : rguess(wm->nglface + 1) = 1.0 / (wm->hcin + hrad);
4604 :
4605 281 : for (int i = 2; i <= wm->nglface; i += 2) {
4606 159 : rguess(i) = 1.0 / wm->scon[i / 2 - 1];
4607 159 : if (i < wm->nglface) rguess(i + 1) = resgap;
4608 : }
4609 :
4610 122 : restot = 0.0;
4611 562 : for (int i = 1; i <= wm->nglface + 1; ++i) {
4612 440 : restot += rguess(i);
4613 : }
4614 :
4615 122 : temdiff = wm->tin - wm->tout;
4616 122 : if (std::abs(temdiff) < 0.5) temdiff = 2.0;
4617 :
4618 122 : ressum = 0.0;
4619 440 : for (int i = 1; i <= wm->nglface; ++i) {
4620 318 : ressum += rguess(i);
4621 318 : wm->thetas[i - 1] = (ressum / restot) * temdiff + wm->tout;
4622 : }
4623 :
4624 : } else {
4625 : // Use previous time step values
4626 305639 : for (int i = 1; i <= wm->nglface; ++i) {
4627 219866 : wm->thetas[i - 1] = s_surf->SurfaceWindow(SurfNum).thetaFace[i];
4628 : }
4629 : }
4630 :
4631 : // Initialize face temperatures of shade or blind, if present
4632 :
4633 85895 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
4634 85895 : if (ANY_INTERIOR_SHADE_BLIND(s_surf->SurfWinExtIntShadePrevTS(SurfNum)) ||
4635 85895 : s_surf->SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtShade ||
4636 257685 : s_surf->SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtBlind ||
4637 85895 : ANY_BETWEENGLASS_SHADE_BLIND(s_surf->SurfWinExtIntShadePrevTS(SurfNum))) {
4638 : // Shade or blind is on during the previous TS; use previous-TS values of shade/blind face temps.
4639 : // Note that if shade or blind is NOT on in the current TS the following two
4640 : // temperature values, although calculated here, are not used. The shade/blind face numbers
4641 : // during the previous time step depend on whether a storm window glass layer was added to
4642 : // or removed from the window during the current time step.
4643 0 : int nglfacePrevDay = wm->nglface;
4644 0 : if (StormWinFlagPrevDay == 0 && StormWinFlagThisDay == 1) nglfacePrevDay = wm->nglface - 2;
4645 0 : if (StormWinFlagPrevDay == 1 && StormWinFlagThisDay == 0) nglfacePrevDay = wm->nglface + 2;
4646 0 : wm->thetas[wm->nglface] = s_surf->SurfaceWindow(SurfNum).thetaFace[nglfacePrevDay + 1];
4647 0 : wm->thetas[wm->nglface + 1] = s_surf->SurfaceWindow(SurfNum).thetaFace[nglfacePrevDay + 2];
4648 : } else {
4649 : // No shade or blind previous time step; guess starting values of shade/blind
4650 : // taking into account short- and long-wave radiation (from solar, lights and zone equipment)
4651 : // absorbed by shade/blind faces. Face temps are assumed to be the same and
4652 : // equal to shade/blind temp. For interior shade/blind, air temp on either side is
4653 : // assumed to be the same and equal to tin; for exterior blind it is assumed to be
4654 : // equal to tout. For between-glass shade/blind it is assumed to be equal to the
4655 : // average temperature of the adjacent glass faces.
4656 :
4657 85895 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
4658 0 : wm->thetas[wm->nglface] = wm->tin + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (wm->hcin + hrad));
4659 0 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4660 85895 : } else if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind) {
4661 0 : wm->thetas[wm->nglface] = wm->tout + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (wm->hcout + hrad));
4662 0 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4663 85895 : } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
4664 : // Between-glass shade/blind allowed only for double and triple glazing.
4665 : // The factor 16.0 below is based on a combined convective/radiative heat transfer
4666 : // coefficient on either side of the shade/blind of 8.0 W/m2-K -- about 1.4 Btu/h-ft2-F.
4667 0 : if (wm->nglface == 4) { // double glazing
4668 0 : wm->thetas[wm->nglface] = 0.5 * (wm->thetas[1] + wm->thetas[2]) + (AbsRadShade(1) + AbsRadShade(2)) / 16.0;
4669 0 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4670 : } else { // triple glazing
4671 0 : wm->thetas[wm->nglface] = 0.5 * (wm->thetas[3] + wm->thetas[4]) + (AbsRadShade(1) + AbsRadShade(2)) / 16.0;
4672 0 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4673 : }
4674 : }
4675 : }
4676 85895 : } // StartingWindowTemps()
4677 :
4678 : //****************************************************************************
4679 :
4680 40358 : void NusseltNumber(EnergyPlusData &state,
4681 : int const SurfNum, // Surface number
4682 : Real64 const tso, // Temperature of gap surface closest to outside (K)
4683 : Real64 const tsi, // Temperature of gap surface closest to zone (K)
4684 : int const IGap, // Gap number
4685 : Real64 const gr, // Gap gas Grashof number
4686 : Real64 const pr, // Gap gas Prandtl number
4687 : Real64 &gnu // Gap gas Nusselt number
4688 : )
4689 : {
4690 :
4691 : // SUBROUTINE INFORMATION:
4692 : // AUTHOR Adapted by Fred Winkelmann from Window5 subroutine nusselt
4693 : // DATE WRITTEN September 2001
4694 : // MODIFIED na
4695 : // RE-ENGINEERED na
4696 :
4697 : // PURPOSE OF THIS SUBROUTINE:
4698 : // Finds the Nusselt number for gas-filled gaps between isothermal solid layers.
4699 : // The gap may be filled with a single gas or a gas mixture.
4700 :
4701 : // METHODOLOGY EMPLOYED:
4702 : // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
4703 : // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
4704 : // The equation numbers below correspond to those in the standard.
4705 :
4706 : // REFERENCES:
4707 : // Window5 source code; ISO 15099
4708 :
4709 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4710 : Real64 asp; // Aspect ratio: window height to gap width
4711 : Real64 ra; // Rayleigh number
4712 : Real64 gnu901; // Nusselt number temporary variables for
4713 : Real64 gnu902;
4714 : Real64 gnu90;
4715 : Real64 gnu601;
4716 : Real64 gnu602; // different tilt and Ra ranges
4717 : Real64 gnu60;
4718 : Real64 gnu601a;
4719 : Real64 gnua;
4720 : Real64 gnub;
4721 : Real64 cra; // Temporary variables
4722 : Real64 a;
4723 : Real64 b;
4724 : Real64 g;
4725 : Real64 ang;
4726 :
4727 40358 : auto const &wm = state.dataWindowManager;
4728 :
4729 40358 : if (SurfNum > 0) {
4730 40270 : auto const &s_surf = state.dataSurface;
4731 40270 : asp = s_surf->Surface(SurfNum).Height / wm->gaps[IGap - 1].width;
4732 : } else { // SurfNum = 0 when NusseltNumber is called from CalcNominalWindowCond, which applies to a
4733 : // particular construction. So window height is not known and we assume 5 ft (1.524 m)
4734 88 : asp = 1.524 / wm->gaps[IGap - 1].width;
4735 : }
4736 :
4737 40358 : wm->tiltr = wm->tilt * Constant::DegToRad;
4738 40358 : ra = gr * pr;
4739 : //! fw if (ra > 2.0e6): error that outside range of Rayleigh number?
4740 :
4741 40358 : if (ra <= 1.0e4) gnu901 = 1.0 + 1.7596678e-10 * std::pow(ra, 2.2984755); // eq. 51
4742 40358 : if (ra > 1.0e4 && ra <= 5.0e4) gnu901 = 0.028154 * std::pow(ra, 0.4134); // eq. 50
4743 40358 : if (ra > 5.0e4) gnu901 = 0.0673838 * std::pow(ra, 1.0 / 3.0); // eq. 49
4744 :
4745 40358 : gnu902 = 0.242 * std::pow(ra / asp, 0.272); // eq. 52
4746 40358 : gnu90 = max(gnu901, gnu902);
4747 :
4748 40358 : if (tso > tsi) { // window heated from above
4749 18283 : gnu = 1.0 + (gnu90 - 1.0) * std::sin(wm->tiltr); // eq. 53
4750 : } else { // window heated from below
4751 22075 : if (wm->tilt >= 60.0) {
4752 22069 : if (ra >= 0.001) {
4753 22069 : g = 0.5 * std::pow(1.0 + std::pow(ra / 3160.0, 20.6), -0.1); // eq. 47
4754 : } else {
4755 0 : g = 0.5;
4756 : }
4757 22069 : gnu601a = 1.0 + pow_7(0.0936 * std::pow(ra, 0.314) / (1.0 + g)); // eq. 45
4758 22069 : gnu601 = std::pow(gnu601a, 0.142857);
4759 :
4760 : // For any aspect ratio
4761 22069 : gnu602 = (0.104 + 0.175 / asp) * std::pow(ra, 0.283); // eq. 46
4762 22069 : gnu60 = max(gnu601, gnu602);
4763 :
4764 : // linear interpolation for layers inclined at angles between 60 and 90 deg
4765 22069 : gnu = ((90.0 - wm->tilt) * gnu60 + (wm->tilt - 60.0) * gnu90) / 30.0;
4766 : }
4767 22075 : if (wm->tilt < 60.0) { // eq. 42
4768 6 : cra = ra * std::cos(wm->tiltr);
4769 6 : a = 1.0 - 1708.0 / cra;
4770 6 : b = std::pow(cra / 5830.0, 0.33333) - 1.0;
4771 6 : gnua = (std::abs(a) + a) / 2.0;
4772 6 : gnub = (std::abs(b) + b) / 2.0;
4773 6 : ang = 1708.0 * std::pow(std::sin(1.8 * wm->tiltr), 1.6);
4774 6 : gnu = 1.0 + 1.44 * gnua * (1.0 - ang / cra) + gnub;
4775 : }
4776 : }
4777 40358 : } // NusseltNumber()
4778 :
4779 : //*******************************************************************************************************
4780 :
4781 22932 : void TransAndReflAtPhi(Real64 const cs, // Cosine of incidence angle
4782 : Real64 const tf0, // Transmittance at zero incidence angle
4783 : Real64 const rf0, // Front reflectance at zero incidence angle
4784 : Real64 const rb0, // Back reflectance at zero incidence angle
4785 : Real64 &tfp, // Transmittance at cs
4786 : Real64 &rfp, // Front reflectance at cs
4787 : Real64 &rbp, // Back reflectance at cs
4788 : bool const SimpleGlazingSystem, // .TRUE. if simple block model being used
4789 : Real64 const SimpleGlazingSHGC, // SHGC value to use in alternate model for simple glazing system
4790 : Real64 const SimpleGlazingU // U-factor value to use in alternate model for simple glazing system
4791 : )
4792 : {
4793 :
4794 : // SUBROUTINE INFORMATION:
4795 : // AUTHOR F. Winkelmann
4796 : // DATE WRITTEN January 2000
4797 : // MODIFIED 5 June 2003, FCW: modify to correspond to WINDOW 4 and WINDOW 5.
4798 : // Original routine was based on the method in E.U. Finlayson et al,
4799 : // "WINDOW 4.0: Documentation of Calculation Procedures," LBL-33943,
4800 : // July 1993, which is not used in either WINDOW 4 or WINDOW 5.
4801 : // The current routine is based on ASHRAE Handbook of Fundamentals,
4802 : // 2001, pp. 30.20-23, "Optical Properties of Single Glazing Layers."
4803 : // Original routine underpredicted transmittance at angles of
4804 : // incidence > 60 degrees.
4805 : // June 2009. Brent Griffith. add simple window correlation
4806 : // newer model from LBNL windows group 5/15/2009
4807 : // RE-ENGINEERED na
4808 :
4809 : // PURPOSE OF THIS SUBROUTINE:
4810 : // For a single glazing layer, calculate transmittance and reflectance at an arbitrary
4811 : // angle of incidence given transmittance and reflectance at zero incidence angle.
4812 :
4813 : // REFERENCES:
4814 : // ASHRAE Handbook of Fundamentals, 2001, pp. 30.20-23,
4815 : // "Optical Properties of Single Glazing Layers."
4816 :
4817 : Real64 tfp1; // Transmittance at cs for each polarization
4818 : Real64 tfp2;
4819 : Real64 rfp1; // Front reflectance at cs for each polarization
4820 : Real64 rfp2;
4821 : Real64 rbp1; // Back reflectance at cs for each polarization
4822 : Real64 rbp2;
4823 : Real64 betaf; // Intermediate variables
4824 : Real64 betab;
4825 : Real64 r0f;
4826 : Real64 r0b;
4827 : Real64 abf;
4828 : Real64 abb;
4829 : Real64 ngf; // Front and back index of refraction
4830 : Real64 ngb;
4831 : Real64 cgf; // Intermediate variables
4832 : Real64 cgb;
4833 : Real64 rpf1; // Front and back air/glass interface reflectivity
4834 : Real64 rpb1;
4835 : Real64 tpf1;
4836 : Real64 tpb1;
4837 : // and transmittivity for first polarization
4838 : Real64 rpf2; // Front and back air/glass interface reflectivity
4839 : Real64 rpb2;
4840 : Real64 tpf2;
4841 : Real64 tpb2;
4842 : // and transmittivity for second polarization
4843 : Real64 tcl; // Transmittance and reflectance for clear glass
4844 : Real64 rcl;
4845 : Real64 tbnz; // Transmittance and reflectance for bronze glass
4846 : Real64 rbnz;
4847 : Real64 expmabfdivcgf;
4848 : Real64 expm2abfdivcgf;
4849 : Real64 expmabbdivcgb;
4850 :
4851 : Real64 testval; // temporary value for calculations
4852 : Real64 tmp1; // temporary value for calculations
4853 : Real64 tmp2; // temporary value for calculations
4854 : Real64 tmp3; // temporary value for calculations
4855 : Real64 tmp4; // temporary value for calculations
4856 : Real64 tmp5; // temporary value for calculations
4857 : Real64 tmp6; // temporary value for calculations
4858 : Real64 tmp7; // temporary value for calculations
4859 : Real64 tmp8; // temporary value for calculations
4860 : Real64 tmp9; // temporary value for calculations
4861 :
4862 22932 : if (SimpleGlazingSystem) { // use alternate angular dependence model for block model of simple glazing input
4863 :
4864 491 : Real64 const cs_2(pow_2(cs));
4865 491 : Real64 const cs_3(pow_3(cs));
4866 491 : Real64 const cs_4(pow_4(cs));
4867 491 : Real64 TransCurveA = 0.00 + 3.36 * cs - 3.85 * cs_2 + 1.49 * cs_3 + 0.01 * cs_4;
4868 491 : Real64 TransCurveB = 0.00 + 2.83 * cs - 2.42 * cs_2 + 0.04 * cs_3 + 0.55 * cs_4;
4869 491 : Real64 TransCurveC = 0.00 + 2.45 * cs - 1.58 * cs_2 - 0.64 * cs_3 + 0.77 * cs_4;
4870 491 : Real64 TransCurveD = 0.00 + 2.85 * cs - 2.58 * cs_2 + 0.40 * cs_3 + 0.35 * cs_4;
4871 491 : Real64 TransCurveE = 0.00 + 1.51 * cs + 2.49 * cs_2 - 5.87 * cs_3 + 2.88 * cs_4;
4872 491 : Real64 TransCurveF = 0.00 + 1.21 * cs + 3.14 * cs_2 - 6.37 * cs_3 + 3.03 * cs_4;
4873 491 : Real64 TransCurveG = 0.00 + 1.09 * cs + 3.54 * cs_2 - 6.84 * cs_3 + 3.23 * cs_4;
4874 491 : Real64 TransCurveH = 0.00 + 0.98 * cs + 3.83 * cs_2 - 7.13 * cs_3 + 3.33 * cs_4;
4875 491 : Real64 TransCurveI = 0.00 + 0.79 * cs + 3.93 * cs_2 - 6.86 * cs_3 + 3.15 * cs_4;
4876 491 : Real64 TransCurveJ = 0.00 + 0.08 * cs + 6.02 * cs_2 - 8.84 * cs_3 + 3.74 * cs_4;
4877 491 : Real64 TransCurveFGHI = (TransCurveF + TransCurveG + TransCurveH + TransCurveI) / 4.0;
4878 491 : Real64 TransCurveFH = (TransCurveF + TransCurveH) / 2.0;
4879 491 : Real64 TransCurveBDCD = (TransCurveB + TransCurveD + TransCurveC + TransCurveD) / 4.0;
4880 :
4881 491 : Real64 ReflectCurveA = 1.00 - 0.70 * cs + 2.57 * cs_2 - 3.20 * cs_3 + 1.33 * cs_4 - TransCurveA;
4882 491 : Real64 ReflectCurveB = 1.00 - 1.87 * cs + 6.50 * cs_2 - 7.86 * cs_3 + 3.23 * cs_4 - TransCurveB;
4883 491 : Real64 ReflectCurveC = 1.00 - 2.52 * cs + 8.40 * cs_2 - 9.86 * cs_3 + 3.99 * cs_4 - TransCurveC;
4884 491 : Real64 ReflectCurveD = 1.00 - 1.85 * cs + 6.40 * cs_2 - 7.64 * cs_3 + 3.11 * cs_4 - TransCurveD;
4885 491 : Real64 ReflectCurveE = 1.00 - 1.57 * cs + 5.60 * cs_2 - 6.82 * cs_3 + 2.80 * cs_4 - TransCurveE;
4886 491 : Real64 ReflectCurveF = 1.00 - 3.15 * cs + 10.98 * cs_2 - 13.14 * cs_3 + 5.32 * cs_4 - TransCurveF;
4887 491 : Real64 ReflectCurveG = 1.00 - 3.25 * cs + 11.32 * cs_2 - 13.54 * cs_3 + 5.49 * cs_4 - TransCurveG;
4888 491 : Real64 ReflectCurveH = 1.00 - 3.39 * cs + 11.70 * cs_2 - 13.94 * cs_3 + 5.64 * cs_4 - TransCurveH;
4889 491 : Real64 ReflectCurveI = 1.00 - 4.06 * cs + 13.55 * cs_2 - 15.74 * cs_3 + 6.27 * cs_4 - TransCurveI;
4890 491 : Real64 ReflectCurveJ = 1.00 - 4.35 * cs + 14.27 * cs_2 - 16.32 * cs_3 + 6.39 * cs_4 - TransCurveJ;
4891 :
4892 491 : Real64 ReflectCurveFGHI = (ReflectCurveF + ReflectCurveG + ReflectCurveH + ReflectCurveI) / 4.0;
4893 491 : Real64 ReflectCurveFH = (ReflectCurveF + ReflectCurveH) / 2.0;
4894 491 : Real64 ReflectCurveBDCD = (ReflectCurveB + ReflectCurveD + ReflectCurveC + ReflectCurveD) / 4.0;
4895 :
4896 491 : Real64 TransTmp(0.0);
4897 491 : Real64 ReflectTmp(0.0);
4898 :
4899 491 : if (SimpleGlazingU < 1.4195) { // cell 1, 2, or 3
4900 80 : if (SimpleGlazingSHGC > 0.45) {
4901 : // cell # 1
4902 : // Curve E
4903 40 : TransTmp = TransCurveE;
4904 40 : ReflectTmp = ReflectCurveE;
4905 :
4906 40 : } else if ((0.35 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
4907 : // cell # 2
4908 : // 2 way interpolation between Curve E and Curve J
4909 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.35, 0.45, TransCurveJ, TransCurveE);
4910 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.35, 0.45, ReflectCurveJ, ReflectCurveE);
4911 :
4912 40 : } else if (SimpleGlazingSHGC < 0.35) {
4913 : // cell # 3
4914 : // Curve J
4915 40 : TransTmp = TransCurveJ;
4916 40 : ReflectTmp = ReflectCurveJ;
4917 : }
4918 :
4919 411 : } else if ((1.4195 <= SimpleGlazingU) && (SimpleGlazingU <= 1.7034)) { // cell 4, 5 , 6, 7, 8, 9, or 10
4920 0 : if (SimpleGlazingSHGC > 0.55) {
4921 : // cell # 4
4922 : // Curve E
4923 0 : TransTmp = TransCurveE;
4924 0 : ReflectTmp = ReflectCurveE;
4925 :
4926 0 : } else if ((0.5 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
4927 : // cell # 5
4928 : // 4 way interpolation between Curve E , Curve E, Curve E and Curve FGHI
4929 :
4930 0 : TransTmp = InterpolateBetweenFourValues(
4931 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.50, 0.55, TransCurveE, TransCurveE, TransCurveFGHI, TransCurveE);
4932 0 : ReflectTmp = InterpolateBetweenFourValues(
4933 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.50, 0.55, ReflectCurveE, ReflectCurveE, ReflectCurveFGHI, ReflectCurveE);
4934 :
4935 0 : } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.5)) {
4936 : // cell # 6
4937 : // 2 way interpolation between Curve E and Curve FGHI
4938 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveE, TransCurveFGHI);
4939 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveE, ReflectCurveFGHI);
4940 :
4941 0 : } else if ((0.35 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
4942 : // cell # 7
4943 : // 4 way interpolation between Curve E , Curve FGHI, Curve J and Curve FGHI
4944 0 : TransTmp = InterpolateBetweenFourValues(
4945 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.35, 0.45, TransCurveJ, TransCurveE, TransCurveFGHI, TransCurveFGHI);
4946 0 : ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
4947 : SimpleGlazingSHGC,
4948 : 1.4195,
4949 : 1.7034,
4950 : 0.35,
4951 : 0.45,
4952 : ReflectCurveJ,
4953 : ReflectCurveE,
4954 : ReflectCurveFGHI,
4955 : ReflectCurveFGHI);
4956 :
4957 0 : } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.35)) {
4958 : // cell # 8
4959 : // 2 way interpolation between Curve J and Curve FGHI
4960 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveJ, TransCurveFGHI);
4961 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveJ, ReflectCurveFGHI);
4962 :
4963 0 : } else if ((0.25 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
4964 : // cell # 9
4965 : // 4 way interpolation between Curve J, Curve FGHI, Curve J and Curve FH
4966 0 : TransTmp = InterpolateBetweenFourValues(
4967 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.25, 0.3, TransCurveJ, TransCurveJ, TransCurveFH, TransCurveFGHI);
4968 0 : ReflectTmp = InterpolateBetweenFourValues(
4969 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.25, 0.3, ReflectCurveJ, ReflectCurveJ, ReflectCurveFH, ReflectCurveFGHI);
4970 :
4971 0 : } else if (SimpleGlazingSHGC <= 0.25) {
4972 : // cell # 10
4973 : // 2 way interpolation between Curve J and Curve FH
4974 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveJ, TransCurveFH);
4975 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveJ, ReflectCurveFH);
4976 : }
4977 411 : } else if ((1.7034 < SimpleGlazingU) && (SimpleGlazingU < 3.4068)) { // cell 11, 12, 13, 14, or 15
4978 331 : if (SimpleGlazingSHGC > 0.55) {
4979 : // cell # 11
4980 : // Curve E
4981 0 : TransTmp = TransCurveE;
4982 0 : ReflectTmp = ReflectCurveE;
4983 :
4984 331 : } else if ((0.5 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
4985 : // cell # 12
4986 : // 2 way interpolation between Curve E and Curve FGHI
4987 80 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.5, 0.55, TransCurveFGHI, TransCurveE);
4988 80 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.5, 0.55, ReflectCurveFGHI, ReflectCurveE);
4989 :
4990 251 : } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC < 0.5)) {
4991 : // cell # 13
4992 : // Curve FGHI
4993 251 : TransTmp = TransCurveFGHI;
4994 251 : ReflectTmp = ReflectCurveFGHI;
4995 :
4996 0 : } else if ((0.25 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
4997 : // cell # 14
4998 : // 2 way interpolation between Curve FGHI and Curve FH
4999 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.25, 0.30, TransCurveFH, TransCurveFGHI);
5000 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.25, 0.30, ReflectCurveFH, ReflectCurveFGHI);
5001 :
5002 0 : } else if (SimpleGlazingSHGC < 0.25) {
5003 : // cell # 15
5004 : // Curve FH
5005 0 : TransTmp = TransCurveFH;
5006 0 : ReflectTmp = ReflectCurveFH;
5007 : }
5008 :
5009 80 : } else if ((3.4068 <= SimpleGlazingU) && (SimpleGlazingU <= 4.5424)) { // cell 16, 17, 18, 19, 20, 21, 22, or 23
5010 0 : if (SimpleGlazingSHGC > 0.65) {
5011 : // cell # 16
5012 : // 2 way interpolation between Curve E and Curve A
5013 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveE, TransCurveA);
5014 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveE, ReflectCurveA);
5015 :
5016 0 : } else if ((0.6 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.65)) {
5017 : // cell # 17
5018 : // 4 way interpolation between Curve E , Curve E, Curve A, and Curve BDCD
5019 0 : TransTmp = InterpolateBetweenFourValues(
5020 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.6, 0.65, TransCurveE, TransCurveE, TransCurveBDCD, TransCurveA);
5021 0 : ReflectTmp = InterpolateBetweenFourValues(
5022 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.6, 0.65, ReflectCurveE, ReflectCurveE, ReflectCurveBDCD, ReflectCurveA);
5023 :
5024 0 : } else if ((0.55 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.6)) {
5025 : // cell # 18
5026 : // 2 way interpolation between Curve E and Curve BDCD
5027 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveE, TransCurveBDCD);
5028 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveE, ReflectCurveBDCD);
5029 :
5030 0 : } else if ((0.5 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
5031 : // cell # 19
5032 : // 4 way interpolation between Curve E , Curve FGHI, Curve BDCD and Curve BDCD
5033 0 : TransTmp = InterpolateBetweenFourValues(
5034 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.5, 0.55, TransCurveFGHI, TransCurveE, TransCurveBDCD, TransCurveBDCD);
5035 0 : ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
5036 : SimpleGlazingSHGC,
5037 : 3.4068,
5038 : 4.5424,
5039 : 0.5,
5040 : 0.55,
5041 : ReflectCurveFGHI,
5042 : ReflectCurveE,
5043 : ReflectCurveBDCD,
5044 : ReflectCurveBDCD);
5045 :
5046 0 : } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.5)) {
5047 : // cell # 20
5048 : // 2 way interpolation between Curve FGHI and Curve BDCD
5049 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveFGHI, TransCurveBDCD);
5050 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveFGHI, ReflectCurveBDCD);
5051 :
5052 0 : } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
5053 : // cell # 21
5054 : // 4 way interpolation between Curve FGHI, Curve FGHI, Curve BDCD, and Curve D
5055 0 : TransTmp = InterpolateBetweenFourValues(
5056 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.3, 0.45, TransCurveFGHI, TransCurveFGHI, TransCurveD, TransCurveBDCD);
5057 0 : ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
5058 : SimpleGlazingSHGC,
5059 : 3.4068,
5060 : 4.5424,
5061 : 0.3,
5062 : 0.45,
5063 : ReflectCurveFGHI,
5064 : ReflectCurveFGHI,
5065 : ReflectCurveD,
5066 : ReflectCurveBDCD);
5067 :
5068 0 : } else if ((0.25 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
5069 : // cell # 22
5070 : // 4 way interpolation between Curve FGHI, Curve FH, Curve D, and Curve D
5071 0 : TransTmp = InterpolateBetweenFourValues(
5072 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.25, 0.3, TransCurveFH, TransCurveFGHI, TransCurveD, TransCurveD);
5073 0 : ReflectTmp = InterpolateBetweenFourValues(
5074 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.25, 0.3, ReflectCurveFH, ReflectCurveFGHI, ReflectCurveD, ReflectCurveD);
5075 :
5076 0 : } else if (SimpleGlazingSHGC <= 0.25) {
5077 : // cell # 23
5078 : // 2 way interpolation between Curve FH and Curve D
5079 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveFH, TransCurveD);
5080 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveFH, ReflectCurveD);
5081 : }
5082 80 : } else if (SimpleGlazingU > 4.5424) { // cell 24, 25, 26, 27, or 28
5083 80 : if (SimpleGlazingSHGC > 0.65) {
5084 : // cell # 24
5085 : // Curve A
5086 40 : TransTmp = TransCurveA;
5087 40 : ReflectTmp = ReflectCurveA;
5088 40 : } else if ((0.6 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.65)) {
5089 : // cell # 25
5090 : // 2 way interpolation between Curve A and Curve BDCD
5091 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.6, 0.65, TransCurveBDCD, TransCurveA);
5092 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.6, 0.65, ReflectCurveBDCD, ReflectCurveA);
5093 :
5094 40 : } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC < 0.6)) {
5095 : // cell # 26
5096 : // Curve BDCD
5097 0 : TransTmp = TransCurveBDCD;
5098 0 : ReflectTmp = ReflectCurveBDCD;
5099 :
5100 40 : } else if ((0.3 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
5101 : // cell # 27
5102 : // 2 way interpolation between Curve BDCD and Curve D
5103 40 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.3, 0.45, TransCurveD, TransCurveBDCD);
5104 40 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.3, 0.45, ReflectCurveD, ReflectCurveBDCD);
5105 :
5106 0 : } else if (SimpleGlazingSHGC < 0.3) {
5107 : // cell # 28
5108 : // Curve D
5109 0 : TransTmp = TransCurveD;
5110 0 : ReflectTmp = ReflectCurveD;
5111 :
5112 : } else {
5113 0 : assert(false);
5114 : }
5115 : } else {
5116 0 : assert(false);
5117 : }
5118 :
5119 491 : if (cs == 1.0) { // at 0 deg incident, TransTmp and ReflectTmp should be 1.0
5120 49 : TransTmp = 1.0;
5121 49 : ReflectTmp = 0.0;
5122 : }
5123 :
5124 : // now apply normalization factors to zero incidence angle properties
5125 491 : tfp = tf0 * TransTmp;
5126 491 : tfp = max(min(1.0, tfp), 0.0);
5127 :
5128 491 : rfp = rf0 * (1. - ReflectTmp) + ReflectTmp;
5129 491 : rfp = max(min(0.9999 - tfp, rfp), 0.0);
5130 :
5131 491 : rbp = rfp;
5132 :
5133 22441 : } else if (tf0 <= 0.0) {
5134 : // This is an opaque window. For all angles, set transmittance to 0; set reflectance to that at zero incidence angle.
5135 0 : tfp = 0.0;
5136 0 : rfp = rf0;
5137 0 : rbp = rb0;
5138 : } else {
5139 :
5140 22441 : betaf = pow_2(tf0) - pow_2(rf0) + 2.0 * rf0 + 1.0;
5141 22441 : betab = pow_2(tf0) - pow_2(rb0) + 2.0 * rb0 + 1.0;
5142 22441 : r0f = (betaf - std::sqrt(pow_2(betaf) - 4.0 * (2.0 - rf0) * rf0)) / (2.0 * (2.0 - rf0));
5143 22441 : r0b = (betab - std::sqrt(pow_2(betab) - 4.0 * (2.0 - rb0) * rb0)) / (2.0 * (2.0 - rb0));
5144 :
5145 22441 : tmp1 = std::abs(r0f - r0b);
5146 22441 : if (tmp1 != 0.0) {
5147 12680 : testval = std::abs(r0f - r0b) / (r0f + r0b);
5148 : } else {
5149 9761 : testval = 0.0;
5150 : }
5151 :
5152 22441 : if (testval < 0.001) { // CR8830, CR8942, implications of relaxation of glazing properties CR8413
5153 : // UNCOATED GLASS
5154 9761 : tmp1 = r0f * tf0;
5155 9761 : if (tmp1 != 0.0) {
5156 9761 : abf = std::log(tmp1 / (rf0 - r0f));
5157 : } else {
5158 0 : abf = 0.0;
5159 : }
5160 9761 : tmp2 = r0b * tf0;
5161 9761 : if (tmp2 != 0.0) {
5162 9761 : abb = std::log(tmp2 / (rb0 - r0b));
5163 : } else {
5164 0 : abb = 0.0;
5165 : }
5166 9761 : ngf = (1.0 + std::sqrt(r0f)) / (1.0 - std::sqrt(r0f));
5167 9761 : ngb = (1.0 + std::sqrt(r0b)) / (1.0 - std::sqrt(r0b));
5168 9761 : cgf = std::sqrt(1.0 - (1.0 - cs * cs) / pow_2(ngf));
5169 9761 : cgb = std::sqrt(1.0 - (1.0 - cs * cs) / pow_2(ngb));
5170 9761 : tmp3 = ngf * cs - cgf;
5171 9761 : if (tmp3 != 0.0) {
5172 9761 : rpf1 = pow_2(tmp3 / (ngf * cs + cgf));
5173 : } else {
5174 0 : rpf1 = 0.0;
5175 : }
5176 9761 : tmp4 = ngf * cgf - cs;
5177 9761 : if (tmp4 != 0.0) {
5178 9761 : rpf2 = pow_2(tmp4 / (ngf * cgf + cs));
5179 : } else {
5180 0 : rpf2 = 0.0;
5181 : }
5182 9761 : tpf1 = 1 - rpf1;
5183 9761 : tpf2 = 1 - rpf2;
5184 9761 : tmp5 = ngb * cs - cgb;
5185 9761 : if (tmp5 != 0.0) {
5186 9761 : rpb1 = pow_2(tmp5 / (ngb * cs + cgb));
5187 : } else {
5188 0 : rpb1 = 0.0;
5189 : }
5190 9761 : tmp6 = ngb * cgb - cs;
5191 9761 : if (tmp6 != 0.0) {
5192 9761 : rpb2 = pow_2(tmp6 / (ngb * cgb + cs));
5193 : } else {
5194 0 : rpb2 = 0.0;
5195 : }
5196 9761 : tpb1 = 1 - rpf1;
5197 9761 : tpb2 = 1 - rpf2;
5198 9761 : tmp7 = -abf;
5199 9761 : if (cgf != 0.0) {
5200 9761 : expmabfdivcgf = std::exp(tmp7 / cgf);
5201 : } else {
5202 0 : expmabfdivcgf = 0.0;
5203 : }
5204 9761 : tmp8 = -2.0 * abf;
5205 9761 : if (cgf != 0.0) {
5206 9761 : expm2abfdivcgf = std::exp(tmp8 / cgf);
5207 : } else {
5208 0 : expm2abfdivcgf = 0.0;
5209 : }
5210 9761 : if (tpf1 != 0.0) {
5211 9761 : tfp1 = pow_2(tpf1) * expmabfdivcgf / (1.0 - pow_2(rpf1) * expm2abfdivcgf);
5212 : } else {
5213 0 : tfp1 = 0.0;
5214 : }
5215 9761 : rfp1 = rpf1 * (1.0 + tfp1 * expmabfdivcgf);
5216 9761 : if (tpf2 != 0.0) {
5217 8805 : tfp2 = pow_2(tpf2) * expmabfdivcgf / (1.0 - pow_2(rpf2) * expm2abfdivcgf);
5218 : } else {
5219 956 : tfp2 = 0.0;
5220 : }
5221 9761 : rfp2 = rpf2 * (1.0 + tfp2 * expmabfdivcgf);
5222 9761 : tfp = 0.5 * (tfp1 + tfp2);
5223 9761 : rfp = 0.5 * (rfp1 + rfp2);
5224 9761 : tmp9 = -abb;
5225 9761 : if (tmp9 != 0.0) {
5226 9761 : expmabbdivcgb = std::exp(tmp9 / cgb);
5227 : } else {
5228 0 : expmabbdivcgb = 0.0;
5229 : }
5230 9761 : rbp1 = rpb1 * (1.0 + tfp1 * expmabbdivcgb);
5231 9761 : rbp2 = rpb2 * (1.0 + tfp2 * expmabbdivcgb);
5232 9761 : rbp = 0.5 * (rbp1 + rbp2);
5233 : } else {
5234 : // COATED GLASS
5235 12680 : if (tf0 > 0.645) {
5236 : // Use clear glass angular distribution.
5237 : // Normalized clear glass transmittance and reflectance distribution
5238 12500 : if (cs > 0.999) { // Angle of incidence = 0 deg
5239 1250 : tcl = 1.0;
5240 1250 : rcl = 0.0;
5241 11250 : } else if (cs < 0.001) { // Angle of incidence = 90 deg
5242 1250 : tcl = 0.0;
5243 1250 : rcl = 1.0;
5244 : } else {
5245 10000 : tcl = -0.0015 + (3.355 + (-3.840 + (1.460 + 0.0288 * cs) * cs) * cs) * cs;
5246 10000 : rcl = 0.999 + (-0.563 + (2.043 + (-2.532 + 1.054 * cs) * cs) * cs) * cs - tcl;
5247 : }
5248 12500 : tfp = tf0 * tcl;
5249 12500 : rfp = rf0 * (1.0 - rcl) + rcl;
5250 12500 : rbp = rb0 * (1.0 - rcl) + rcl;
5251 : } else {
5252 : // Use bronze glass angular distribution.
5253 : // Normalized bronze tinted glass transmittance and reflectance distribution
5254 180 : if (cs > 0.999) { // Angle of incidence = 0 deg
5255 18 : tbnz = 1.0;
5256 18 : rbnz = 0.0;
5257 162 : } else if (cs < 0.001) { // Angle of incidence = 90 deg
5258 18 : tbnz = 0.0;
5259 18 : rbnz = 1.0;
5260 : } else {
5261 144 : tbnz = -0.002 + (2.813 + (-2.341 + (-0.05725 + 0.599 * cs) * cs) * cs) * cs;
5262 144 : rbnz = 0.997 + (-1.868 + (6.513 + (-7.862 + 3.225 * cs) * cs) * cs) * cs - tbnz;
5263 : }
5264 180 : tfp = tf0 * tbnz;
5265 180 : rfp = rf0 * (1.0 - rbnz) + rbnz;
5266 180 : rbp = rb0 * (1.0 - rbnz) + rbnz;
5267 : }
5268 : }
5269 : }
5270 :
5271 : // total absorptance cannot be negative
5272 22932 : assert(1.0 - rfp - tfp >= -1e6);
5273 22932 : assert(1.0 - rbp - tfp >= -1e6);
5274 22932 : } // TransAndReflAtPhi()
5275 :
5276 240 : Real64 InterpolateBetweenTwoValues(Real64 const X, Real64 const X0, Real64 const X1, Real64 const F0, Real64 const F1)
5277 : {
5278 :
5279 : // FUNCTION INFORMATION:
5280 : // AUTHOR Brent Griffith
5281 : // DATE WRITTEN June 2009
5282 : // MODIFIED na
5283 : // RE-ENGINEERED na
5284 :
5285 : // PURPOSE OF THIS FUNCTION:
5286 : // Interpolate between two results
5287 :
5288 : // METHODOLOGY EMPLOYED:
5289 : // linear interpolation
5290 :
5291 : Real64 InterpResult;
5292 :
5293 240 : InterpResult = F0 + ((X - X0) / (X1 - X0)) * (F1 - F0);
5294 240 : return InterpResult;
5295 : } // InterpolateBetweenTwoValues()
5296 :
5297 0 : Real64 InterpolateBetweenFourValues(Real64 const X,
5298 : Real64 const Y,
5299 : Real64 const X1,
5300 : Real64 const X2,
5301 : Real64 const Y1,
5302 : Real64 const Y2,
5303 : Real64 const Fx1y1,
5304 : Real64 const Fx1y2,
5305 : Real64 const Fx2y1,
5306 : Real64 const Fx2y2)
5307 : {
5308 :
5309 : // FUNCTION INFORMATION:
5310 : // AUTHOR Brent Griffith
5311 : // DATE WRITTEN June 2009
5312 : // MODIFIED na
5313 : // RE-ENGINEERED na
5314 :
5315 : // PURPOSE OF THIS FUNCTION:
5316 : // Interpolate between four results.
5317 :
5318 : // METHODOLOGY EMPLOYED:
5319 : // bilinear interpolation (approximate)
5320 :
5321 : // REFERENCES:
5322 : // http://en.wikipedia.org/wiki/Bilinear_interpolation
5323 :
5324 : // Return value
5325 : Real64 InterpResult;
5326 :
5327 0 : InterpResult = (Fx1y1 / ((X2 - X1) * (Y2 - Y1))) * (X2 - X) * (Y2 - Y) + (Fx2y1 / ((X2 - X1) * (Y2 - Y1))) * (X - X1) * (Y2 - Y) +
5328 0 : (Fx1y2 / ((X2 - X1) * (Y2 - Y1))) * (X2 - X) * (Y - Y1) + (Fx2y2 / ((X2 - X1) * (Y2 - Y1))) * (X - X1) * (Y - Y1);
5329 0 : return InterpResult;
5330 : } // InterpolateBetweenFourValues()
5331 :
5332 : //**************************************************************************
5333 546 : void W5LsqFit(std::array<Real64, numPhis> const &ivars, // Independent variables
5334 : std::array<Real64, numPhis> const &dvars, // Dependent variables
5335 : std::array<Real64, maxPolyCoef> &coeffs // Polynomial coefficients from fit
5336 : )
5337 : {
5338 :
5339 : // SUBROUTINE INFORMATION:
5340 : // AUTHOR George Walton
5341 : // DATE WRITTEN April 1976
5342 : // MODIFIED November 1999 F.Winkelmann
5343 : // RE-ENGINEERED na
5344 :
5345 : // PURPOSE OF THIS SUBROUTINE:
5346 : // Does least squares fit for coefficients of a polynomial
5347 : // that gives a window property, such as transmittance, as a function of
5348 : // the cosine of the angle of incidence. The polynomial is of the
5349 : // form C1*X + C2*X**2 + C3*X**3 + ... +CN*X**N, where N <= 6.
5350 : // Adapted from BLAST subroutine LSQFIT.
5351 :
5352 : std::array<std::array<Real64, maxPolyCoef>, maxPolyCoef> A; // Least squares derivative matrix
5353 : std::array<Real64, maxPolyCoef> B; // Least squares derivative vector
5354 : std::array<std::array<Real64, 16>, maxPolyCoef> D; // Powers of independent variable
5355 :
5356 : // Set up least squares matrix
5357 6006 : for (int M = 0; M < numPhis; ++M) {
5358 5460 : D[0][M] = ivars[M];
5359 : }
5360 :
5361 3276 : for (int i = 1; i < maxPolyCoef; ++i) {
5362 30030 : for (int M = 0; M < numPhis; ++M) {
5363 27300 : D[i][M] = D[i - 1][M] * ivars[M];
5364 : }
5365 : }
5366 :
5367 3822 : for (int i = 0; i < maxPolyCoef; ++i) {
5368 3276 : Real64 SUM = 0.0;
5369 36036 : for (int M = 0; M < numPhis; ++M) {
5370 32760 : SUM += dvars[M] * D[i][M];
5371 : }
5372 3276 : B[i] = SUM;
5373 22932 : for (int j = 0; j < maxPolyCoef; ++j) {
5374 19656 : Real64 SUM2 = 0.0;
5375 216216 : for (int M = 0; M < numPhis; ++M) {
5376 196560 : SUM2 += D[i][M] * D[j][M];
5377 : }
5378 19656 : A[j][i] = SUM2;
5379 19656 : A[i][j] = SUM2;
5380 : }
5381 : }
5382 :
5383 : // Solve the simultaneous equations using Gauss elimination
5384 546 : int order1 = maxPolyCoef - 1;
5385 3276 : for (int K = 0; K < order1; ++K) {
5386 2730 : int KP1 = K + 1;
5387 10920 : for (int i = KP1; i < maxPolyCoef; ++i) {
5388 8190 : Real64 ACON = A[K][i] / A[K][K];
5389 8190 : B[i] -= B[K] * ACON;
5390 46410 : for (int j = K; j < maxPolyCoef; ++j) {
5391 38220 : A[j][i] -= A[j][K] * ACON;
5392 : }
5393 : }
5394 : }
5395 :
5396 : // Perform back substitution
5397 546 : coeffs[maxPolyCoef - 1] = B[maxPolyCoef - 1] / A[maxPolyCoef - 1][maxPolyCoef - 1];
5398 546 : int LP1 = maxPolyCoef - 1;
5399 546 : int L = maxPolyCoef - 2;
5400 :
5401 3276 : while (L >= 0) {
5402 2730 : Real64 SUM = 0.0;
5403 10920 : for (int j = LP1; j < maxPolyCoef; ++j) {
5404 8190 : SUM += A[j][L] * coeffs[j];
5405 : }
5406 2730 : coeffs[L] = (B[L] - SUM) / A[L][L];
5407 2730 : LP1 = L;
5408 2730 : --L;
5409 : }
5410 546 : } // W5LsqFit()
5411 :
5412 : //********************************************************************************
5413 :
5414 0 : void W5LsqFit2(Array1A<Real64> const IndepVar, // Independent variables
5415 : Array1A<Real64> const DepVar, // Dependent variables
5416 : int const N, // Order of polynomial
5417 : int const N1, // First and last data points used
5418 : int const N2,
5419 : Array1A<Real64> CoeffsCurve // Polynomial coefficients from fit
5420 : )
5421 : {
5422 :
5423 : // SUBROUTINE INFORMATION:
5424 : // AUTHOR George Walton
5425 : // DATE WRITTEN April 1976
5426 : // MODIFIED November 1999 F.Winkelmann
5427 : // May 2001 F. Winkelmann, to do 19 indep. variables
5428 : // RE-ENGINEERED na
5429 :
5430 : // PURPOSE OF THIS SUBROUTINE:
5431 : // Does least squares fit for coefficients of a polynomial
5432 : // that gives a window property, such as transmittance, as a function of
5433 : // the cosine of the angle of incidence. The polynomial is of the
5434 : // form C1*X + C2*X**2 + C3*X**3 + ... +CN*X**N, where N <= 6.
5435 : // Adapted from BLAST subroutine LSQFIT.
5436 :
5437 : // Argument array dimensioning
5438 0 : IndepVar.dim(19);
5439 0 : DepVar.dim(19);
5440 0 : CoeffsCurve.dim(6);
5441 :
5442 0 : Array2D<Real64> A(6, 6); // Least squares derivative matrix
5443 0 : Array1D<Real64> B(6); // Least squares derivative vector
5444 0 : Array2D<Real64> D(6, 16); // Powers of independent variable
5445 : Real64 ACON; // Intermediate variables
5446 : Real64 SUM;
5447 : int LP1;
5448 : int NM1;
5449 :
5450 : // Set up least squares matrix
5451 0 : for (int M = N1; M <= N2; ++M) {
5452 0 : D(1, M) = IndepVar(M);
5453 : }
5454 :
5455 0 : for (int i = 2; i <= N; ++i) {
5456 0 : for (int M = N1; M <= N2; ++M) {
5457 0 : D(i, M) = D(i - 1, M) * IndepVar(M);
5458 : }
5459 : }
5460 :
5461 0 : for (int i = 1; i <= N; ++i) {
5462 0 : SUM = 0.0;
5463 0 : for (int M = N1; M <= N2; ++M) {
5464 0 : SUM += DepVar(M) * D(i, M);
5465 : }
5466 0 : B(i) = SUM;
5467 0 : for (int j = 1; j <= N; ++j) {
5468 0 : SUM = 0.0;
5469 0 : for (int M = N1; M <= N2; ++M) {
5470 0 : SUM += D(i, M) * D(j, M);
5471 : }
5472 0 : A(j, i) = SUM;
5473 0 : A(i, j) = SUM;
5474 : }
5475 : }
5476 :
5477 : // Solve the simultaneous equations using Gauss elimination
5478 0 : NM1 = N - 1;
5479 0 : for (int K = 1; K <= NM1; ++K) {
5480 0 : int KP1 = K + 1;
5481 0 : for (int i = KP1; i <= N; ++i) {
5482 0 : ACON = A(K, i) / A(K, K);
5483 0 : B(i) -= B(K) * ACON;
5484 0 : for (int j = K; j <= N; ++j) {
5485 0 : A(j, i) -= A(j, K) * ACON;
5486 : }
5487 : }
5488 : }
5489 :
5490 : // Perform back substitution
5491 0 : CoeffsCurve(N) = B(N) / A(N, N);
5492 0 : LP1 = N;
5493 0 : int L = N - 1;
5494 :
5495 0 : while (L > 0) {
5496 0 : SUM = 0.0;
5497 0 : for (int j = LP1; j <= N; ++j) {
5498 0 : SUM += A(j, L) * CoeffsCurve(j);
5499 : }
5500 0 : CoeffsCurve(L) = (B(L) - SUM) / A(L, L);
5501 0 : LP1 = L;
5502 0 : --L;
5503 : }
5504 0 : } // W5LsqFit2()
5505 :
5506 : //***********************************************************************
5507 :
5508 1982 : Real64 DiffuseAverage(std::array<Real64, numPhis> const &props) // Property value at angles of incidence
5509 : {
5510 :
5511 : // FUNCTION INFORMATION:
5512 : // AUTHOR Fred Winkelmann
5513 : // DATE WRITTEN November 1999
5514 : // MODIFIED na
5515 : // RE-ENGINEERED na
5516 :
5517 : // PURPOSE OF THIS FUNCTION:
5518 : // Calculate value of property, such as transmittance, for hemispherical
5519 : // diffuse radiation from property values at angles of incidence from
5520 : // 0 to 90 degrees in 10 degree increments.
5521 :
5522 : // METHODOLOGY EMPLOYED:
5523 : // By Simpson's rule, evaluates the integral from 0 to 90 deg of
5524 : // 2*PropertyValue(phi)*cos(phi)*sin(phi)*dphi (which is same as
5525 : // PropertyValue(phi)*sin(2*phi)*dphi)
5526 :
5527 : // Locals
5528 : // SUBROUTINE ARGUMENT DEFINITIONS:
5529 : // 0,10,20,...,80,90 degrees
5530 :
5531 1982 : constexpr Real64 dPhiR = dPhiDeg * Constant::DegToRad; // Half of 10-deg incidence angle increment (radians)
5532 :
5533 1982 : Real64 avg = 0.0;
5534 19820 : for (int iPhi = 0; iPhi < numPhis - 1; ++iPhi) {
5535 17838 : avg += 0.5 * dPhiR * (props[iPhi] * std::sin(2.0 * iPhi * dPhiR) + props[iPhi + 1] * std::sin(2.0 * (iPhi + 1) * dPhiR));
5536 : }
5537 :
5538 1982 : return (avg < 0.0) ? 0.0 : avg;
5539 : } // DiffuseAverage()
5540 :
5541 : //*************************************************************************************
5542 :
5543 9 : void CalcWinFrameAndDividerTemps(EnergyPlusData &state,
5544 : int const SurfNum, // Surface number
5545 : Real64 const tout, // Outside air temperature (K)
5546 : Real64 const tin, // Inside air temperature (K)
5547 : Real64 const HOutConv, // Outside convective air film conductance (W/m2-K)
5548 : Real64 const HInConv, // Inside convective air film conductance (W/m2-K)
5549 : Real64 const Outir, // Exterior IR irradiance from sky and ground
5550 : int const ConstrNum // Construction number of window
5551 : )
5552 : {
5553 :
5554 : // SUBROUTINE INFORMATION:
5555 : // AUTHOR F. Winkelmann
5556 : // DATE WRITTEN May 2000
5557 : // MODIFIED Aug 2000, FCW: Add effect of frame and divider projections
5558 : // Jun 2001, FCW: Add frame/divider contribution to WinHeatGain
5559 : // Aug 2003, FCW: Fix calculation of divider outside temp: frame
5560 : // inside temp was being used instead of divider inside temp
5561 : // RE-ENGINEERED na
5562 :
5563 : // PURPOSE OF THIS SUBROUTINE:
5564 : // Calculates window frame divider face temperatures from a linearized
5565 : // heat balance on the inside and outside faces
5566 :
5567 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5568 : Real64 HInRad; // Inside radiative conductance (W/m2-K)
5569 : Real64 HOutRad; // Outside radiative conductance (W/m2-K)
5570 : int FrDivNum; // Frame/divider number
5571 : Real64 TInRad; // Inside radiative temperature (K)
5572 : Real64 TInRadFr; // Effective inside radiative temperature for frame (K)
5573 : Real64 TInRadDiv; // Effective inside radiative temperature for divider (K)
5574 : Real64 TOutRad; // Outside radiative temperature (K)
5575 : Real64 TOutRadFr; // Effective outside radiative temperature for frame (K)
5576 : Real64 TOutRadDiv; // Effective outside radiative temperature for divider (K)
5577 : WinShadingType ShadeFlag; // Window shading flag
5578 : Real64 FrameCon; // Frame conductance (W/m2-K)
5579 :
5580 : Real64 Afac; // Intermediate calculation variables
5581 : Real64 Bfac;
5582 : Real64 Dfac;
5583 : Real64 Efac;
5584 : DataSurfaces::FrameDividerType DivType; // Divider type
5585 : Real64 DivCon; // Divider conductance (W/m2-K)
5586 : Real64 DivEmisIn; // Inside divider emissivity
5587 : Real64 DivEmisOut; // Outside divider emissivity
5588 :
5589 : Real64 ProjCorrFrOut; // Outside correction factor for absorbed radiation
5590 : // for frame with outside projection
5591 : Real64 ProjCorrFrIn; // Inside correction factor for absorbed radiation
5592 : // for frame with inside projection
5593 : Real64 HOutConvFr; // Effective outside convective coeff for frame
5594 : // with outside projection (W/m2-K)
5595 : Real64 HOutConvDiv; // Effective outside convective coeff for divider
5596 : // with outside projection (W/m2-K)
5597 : Real64 HInConvFr; // Effective inside convective coeff for frame
5598 : // with inside projection (W/m2-K)
5599 : Real64 HInConvDiv; // Effective inside convective coeff for divider
5600 : // with inside projection (W/m2-K)
5601 : Real64 EmisGlassOut; // Outside surface emissivity of window glazing
5602 : Real64 EmisGlassIn; // Inside surface emissivity of window glazing
5603 : int TotGlassLayers; // Total number of glass layers
5604 : int TotLayers; // Total number of layers in unshaded construction
5605 : // Real64 DivTempOut; // Outside surface divider temperature (K)
5606 : Real64 FrameHeatGain; // Heat gain to zone from frame (W)
5607 : // Real64 FrameHeatTransfer; // Heat transfer through frame (W)
5608 : // Real64 ProjCorrWinHeatGain; // Inside projection correction to IR from divider to zone
5609 : // for window heat gain calculation
5610 : Real64 DividerHeatGain; // Heat gain to zone from divider (W)
5611 : // Real64 DividerHeatTransfer; // Heat transfer through divider (W)
5612 :
5613 9 : auto &s_mat = state.dataMaterial;
5614 9 : auto &s_surf = state.dataSurface;
5615 :
5616 9 : auto const &surfWin = s_surf->SurfaceWindow(SurfNum);
5617 :
5618 9 : TInRad = root_4(s_surf->SurfWinIRfromParentZone(SurfNum) / Constant::StefanBoltzmann);
5619 9 : TOutRad = root_4(Outir / Constant::StefanBoltzmann);
5620 9 : ShadeFlag = s_surf->SurfWinShadingFlag(SurfNum);
5621 9 : FrDivNum = s_surf->Surface(SurfNum).FrameDivider;
5622 9 : auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
5623 9 : TotLayers = thisConstruct.TotLayers;
5624 9 : TotGlassLayers = thisConstruct.TotSolidLayers;
5625 9 : EmisGlassOut = s_mat->materials(thisConstruct.LayerPoint(1))->AbsorpThermalFront;
5626 9 : EmisGlassIn = s_mat->materials(thisConstruct.LayerPoint(TotLayers))->AbsorpThermalBack;
5627 9 : FrameHeatGain = 0.0;
5628 9 : DividerHeatGain = 0.0;
5629 9 : s_surf->SurfWinFrameHeatGain(SurfNum) = 0.0;
5630 9 : s_surf->SurfWinFrameHeatLoss(SurfNum) = 0.0;
5631 9 : s_surf->SurfWinDividerHeatGain(SurfNum) = 0.0;
5632 9 : s_surf->SurfWinDividerHeatLoss(SurfNum) = 0.0;
5633 :
5634 9 : if (s_surf->SurfWinFrameArea(SurfNum) > 0.0) {
5635 : // Window has a frame. Note that if a shade, screen or blind is present it covers only the glazed part of the
5636 : // window and is assumed not to shadow long- or short-wave radiation incident on the frame elements.
5637 9 : ProjCorrFrOut = s_surf->SurfWinProjCorrFrOut(SurfNum);
5638 9 : ProjCorrFrIn = s_surf->SurfWinProjCorrFrIn(SurfNum);
5639 9 : TOutRadFr = TOutRad * root_4((1.0 + 0.5 * ProjCorrFrOut) / (1.0 + ProjCorrFrOut));
5640 9 : TInRadFr = TInRad * root_4((1.0 + 0.5 * ProjCorrFrIn) / (1.0 + ProjCorrFrIn));
5641 9 : FrameCon = s_surf->SurfWinFrameConductance(SurfNum);
5642 9 : HInRad = 0.5 * s_surf->SurfWinFrameEmis(SurfNum) * Constant::StefanBoltzmann *
5643 9 : pow_3(TInRadFr + s_surf->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin);
5644 9 : HInConvFr = HInConv;
5645 9 : HOutRad = 0.5 * s_surf->SurfWinFrameEmis(SurfNum) * Constant::StefanBoltzmann *
5646 9 : pow_3(TOutRadFr + s_surf->SurfWinFrameTempSurfOut(SurfNum) + Constant::Kelvin);
5647 9 : HOutConvFr = HOutConv;
5648 9 : auto const &frdiv = s_surf->FrameDivider(FrDivNum);
5649 9 : if (frdiv.FrameProjectionOut > 0.0) {
5650 0 : HOutRad *= (1.0 + ProjCorrFrOut);
5651 0 : HOutConvFr = HOutConv * (1.0 + ProjCorrFrOut);
5652 : // Add long-wave from outside window surface absorbed by frame outside projection
5653 0 : s_surf->SurfWinFrameQRadOutAbs(SurfNum) += 0.5 * s_surf->SurfWinProjCorrFrOut(SurfNum) * frdiv.FrameEmis * EmisGlassOut *
5654 0 : Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[1]);
5655 : }
5656 9 : if (frdiv.FrameProjectionIn > 0.0) {
5657 0 : HInRad *= (1.0 + ProjCorrFrIn);
5658 0 : HInConvFr = HInConv * (1.0 + ProjCorrFrIn);
5659 : // Add long-wave from inside window surface absorbed by frame inside projection
5660 0 : s_surf->SurfWinFrameQRadInAbs(SurfNum) += 0.5 * s_surf->SurfWinProjCorrFrIn(SurfNum) * frdiv.FrameEmis * EmisGlassIn *
5661 0 : Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[2 * TotGlassLayers]);
5662 : }
5663 9 : Afac = (HOutRad * TOutRadFr + HOutConvFr * tout + s_surf->SurfWinFrameQRadOutAbs(SurfNum)) / (HOutRad + FrameCon + HOutConvFr);
5664 9 : Bfac = FrameCon / (HOutRad + FrameCon + HOutConvFr);
5665 9 : Dfac = (HInRad * TInRadFr + HInConvFr * tin + s_surf->SurfWinFrameQRadInAbs(SurfNum)) / (HInRad + FrameCon + HInConvFr);
5666 9 : Efac = FrameCon / (HInRad + FrameCon + HInConvFr);
5667 9 : s_surf->SurfWinFrameTempIn(SurfNum) = (Dfac + Efac * Afac) / (1.0 - Efac * Bfac) - Constant::Kelvin;
5668 9 : s_surf->SurfWinFrameTempSurfOut(SurfNum) = Afac + Bfac * (s_surf->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin) - Constant::Kelvin;
5669 : // Heat gain to zone from frame
5670 :
5671 : // FrameHeatTransfer = s_surf->SurfWinFrameArea(SurfNum) * FrameCon *
5672 : // (s_surf->SurfWinFrameTempSurfOut(SurfNum) - s_surf->SurfWinFrameTempIn(SurfNum));
5673 9 : FrameHeatGain = s_surf->SurfWinFrameArea(SurfNum) * (1.0 + s_surf->SurfWinProjCorrFrIn(SurfNum)) *
5674 9 : (HInConvFr * (s_surf->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin - tin));
5675 :
5676 9 : if (FrameHeatGain > 0.0) {
5677 0 : s_surf->SurfWinFrameHeatGain(SurfNum) = FrameHeatGain;
5678 : } else {
5679 9 : s_surf->SurfWinFrameHeatLoss(SurfNum) = std::abs(FrameHeatGain);
5680 : }
5681 :
5682 9 : s_surf->SurfWinHeatGain(SurfNum) += FrameHeatGain;
5683 9 : s_surf->SurfWinGainFrameDividerToZoneRep(SurfNum) = FrameHeatGain;
5684 : } // End of check if window has a frame
5685 :
5686 9 : if (s_surf->SurfWinDividerArea(SurfNum) > 0.0 && s_surf->SurfWinStormWinFlag(SurfNum) < 1) {
5687 : // Window has divider. Note that if the window has a storm window layer in place (StormWinFlag = 1)
5688 : // the divider heat transfer calculation is not done.
5689 :
5690 9 : DivType = s_surf->SurfWinDividerType(SurfNum);
5691 9 : DivCon = s_surf->SurfWinDividerConductance(SurfNum);
5692 :
5693 9 : if (DivType == DataSurfaces::FrameDividerType::DividedLite) { // Divided lite
5694 9 : DivEmisIn = s_surf->SurfWinDividerEmis(SurfNum);
5695 9 : DivEmisOut = DivEmisIn;
5696 : } else { // Suspended (between-glass) divider
5697 0 : DivEmisOut = s_mat->materials(thisConstruct.LayerPoint(1))->AbsorpThermalFront;
5698 0 : DivEmisIn = s_mat->materials(thisConstruct.LayerPoint(thisConstruct.TotLayers))->AbsorpThermalBack;
5699 : }
5700 :
5701 9 : TOutRadDiv = TOutRad * root_4((1.0 + s_surf->SurfWinProjCorrDivOut(SurfNum)) / (1.0 + 2.0 * s_surf->SurfWinProjCorrDivOut(SurfNum)));
5702 9 : TInRadDiv = TInRad * root_4((1.0 + s_surf->SurfWinProjCorrDivIn(SurfNum)) / (1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum)));
5703 9 : HInRad = 0.5 * DivEmisIn * Constant::StefanBoltzmann * pow_3(TInRadDiv + s_surf->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin);
5704 9 : HOutRad =
5705 9 : 0.5 * DivEmisOut * Constant::StefanBoltzmann * pow_3(TOutRadDiv + s_surf->SurfWinDividerTempSurfOut(SurfNum) + Constant::Kelvin);
5706 9 : HOutConvDiv = HOutConv;
5707 9 : auto const &frdiv = s_surf->FrameDivider(FrDivNum);
5708 9 : if (frdiv.DividerProjectionOut > 0.0) {
5709 0 : HOutRad *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivOut(SurfNum));
5710 0 : if (s_surf->SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade) HOutConvDiv = s_surf->SurfWinConvCoeffWithShade(SurfNum);
5711 0 : HOutConvDiv *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivOut(SurfNum));
5712 : // Add long-wave from outside window surface absorbed by divider outside projection
5713 0 : s_surf->SurfWinDividerQRadOutAbs(SurfNum) += s_surf->SurfWinProjCorrDivOut(SurfNum) * frdiv.DividerEmis * EmisGlassOut *
5714 0 : Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[1]);
5715 : }
5716 :
5717 9 : HInConvDiv = HInConv;
5718 :
5719 9 : if (frdiv.DividerProjectionIn > 0.0) {
5720 0 : HInRad *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum));
5721 0 : if (s_surf->SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade) HInConvDiv = s_surf->SurfWinConvCoeffWithShade(SurfNum);
5722 0 : HInConvDiv *= (1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum));
5723 : // Add long-wave from inside window surface absorbed by divider inside projection
5724 0 : s_surf->SurfWinDividerQRadInAbs(SurfNum) += s_surf->SurfWinProjCorrDivIn(SurfNum) * frdiv.DividerEmis * EmisGlassIn *
5725 0 : Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[2 * TotGlassLayers]);
5726 : }
5727 9 : Afac = (HOutRad * TOutRadDiv + HOutConvDiv * tout + s_surf->SurfWinDividerQRadOutAbs(SurfNum)) / (HOutRad + DivCon + HOutConvDiv);
5728 9 : Bfac = DivCon / (HOutRad + DivCon + HOutConvDiv);
5729 9 : Dfac = (HInRad * TInRadDiv + HInConvDiv * tin + s_surf->SurfWinDividerQRadInAbs(SurfNum)) / (HInRad + DivCon + HInConvDiv);
5730 9 : Efac = DivCon / (HInRad + DivCon + HInConvDiv);
5731 9 : s_surf->SurfWinDividerTempIn(SurfNum) = (Dfac + Efac * Afac) / (1 - Efac * Bfac) - Constant::Kelvin;
5732 9 : s_surf->SurfWinDividerTempSurfOut(SurfNum) = Afac + Bfac * (s_surf->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin) - Constant::Kelvin;
5733 : // Contribution of divider to window heat gain
5734 : // ProjCorrWinHeatGain = 1.0 + 2.0 * s_surf->SurfWinProjCorrDivIn(SurfNum);
5735 :
5736 9 : DividerHeatGain = s_surf->SurfWinDividerArea(SurfNum) * (1.0 + s_surf->SurfWinProjCorrDivIn(SurfNum)) *
5737 9 : (HInConvDiv * (s_surf->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin - tin));
5738 : // DividerHeatTransfer = s_surf->SurfWinDividerArea(SurfNum) * DivCon *
5739 : // (s_surf->SurfWinDividerTempSurfOut(SurfNum) - s_surf->SurfWinDividerTempIn(SurfNum));
5740 :
5741 9 : if (DividerHeatGain > 0.0) {
5742 0 : s_surf->SurfWinDividerHeatGain(SurfNum) = DividerHeatGain;
5743 : } else {
5744 9 : s_surf->SurfWinDividerHeatLoss(SurfNum) = std::abs(DividerHeatGain);
5745 : }
5746 9 : s_surf->SurfWinHeatGain(SurfNum) += DividerHeatGain;
5747 9 : s_surf->SurfWinGainFrameDividerToZoneRep(SurfNum) += DividerHeatGain;
5748 : // If interior shade is present it is assumed that both the convective and IR radiative gain
5749 : // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative
5750 : // interaction between divider and shade is ignored due to the difficulty of calculating this interaction
5751 : // at the same time that the interaction between glass and shade is calculated.
5752 9 : if (ANY_INTERIOR_SHADE_BLIND(s_surf->SurfWinShadingFlag(SurfNum))) s_surf->SurfWinDividerHeatGain(SurfNum) = DividerHeatGain;
5753 : // DivTempOut = s_surf->SurfWinDividerTempSurfOut(SurfNum) + Constant::Kelvin;
5754 : } // End of check if window has dividers
5755 9 : } // CalcWinFrameAndDividerTemps()
5756 :
5757 : //************************************************************************************
5758 :
5759 66 : void CalcNominalWindowCond(EnergyPlusData &state,
5760 : int const ConstrNum, // Construction number
5761 : int const WinterSummerFlag, // 1=winter, 2=summer
5762 : Real64 &NominalConductance, // Nominal center-of-glass conductance, including air films
5763 : Real64 &SHGC, // Nominal center-of-glass solar heat gain coefficient for
5764 : Real64 &TSolNorm, // Overall beam solar transmittance at normal incidence
5765 : Real64 &TVisNorm, // Overall beam visible transmittance at normal incidence
5766 : int &errFlag // Error flag
5767 : )
5768 : {
5769 :
5770 : // SUBROUTINE INFORMATION:
5771 : // AUTHOR F. Winkelmann
5772 : // DATE WRITTEN September 2000
5773 : // MODIFIED Oct 2000, FW: add solar heat gain coefficient
5774 : // June 2001, FW: account for blinds; change summer outside air
5775 : // temp from 35.0C to 31.7C to correspond to ASHRAE value
5776 : // Feb 2003, FW: add comments that this routine is not called for
5777 : // between-glass shade/blind constructions.
5778 : // May 2006, RR: account for screens
5779 : // Oct 2007, LKL: change temps to match Window 5 values
5780 : // Feb 2009, BG: Changes for CR7682 (SHGC)
5781 : // RE-ENGINEERED na
5782 :
5783 : // PURPOSE OF THIS SUBROUTINE:
5784 : // Calculates nominal center-of-glass U-value and solar heat gain coefficient
5785 : // (SHGC) of a window construction for ASHRAE winter and summer conditions.
5786 : // This function is just for reporting
5787 : // Winter:
5788 : // Inside air temperature = 21.C (69.80F)
5789 : // Outside air temperature = -18C (-.4F)
5790 : // Windspeed = 5.5 m/s (12.3 mph)
5791 : // No solar radiation
5792 : // Replaced Winter:
5793 : // Inside air temperature = 21.1C (70F)
5794 : // Outside air temperature = -17.8C (0F)
5795 : // Windspeed = 6.71 m/s (15 mph)
5796 : // No solar radiation
5797 : // Summer:
5798 : // Inside air temperature = 24C (75.2F)
5799 : // Outside air temperature = 32C (89.6F)
5800 : // Windspeed = 2.8 m/s (6.2 mph)
5801 : // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
5802 : // Replaced Summer:
5803 : // Inside air temperature = 24C (75.2F) ! BG changed again Feb. 2009 by 0.1 (per Window5 team)
5804 : // Outside air temperature = 31.7C (89F)
5805 : // Windspeed = 3.35 m/s (7.5 mph)
5806 : // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
5807 : // The window's inside surround is assumed to be a black body at the inside air temp.
5808 : // The window's outside surround is assumed t be a black body at the outside air temp.
5809 : // Note that in this routine we use a value of 26 W/m2 for the outside convective
5810 : // air film conductance for 5.5 m/s (12.3 mph) wind speed.
5811 : // This is the value used in Window 5 and is also the value for which the center-of-glass
5812 : // conductances in the EnergyPlus window construction reference data set were calculated.
5813 : // However, in the time step loop we will have different values of outside film
5814 : // conductance depending on that time step's wind speed, wind direction, surface-to-air temp difference,
5815 : // etc.(see subroutine InitExteriorConvectionCoeff).
5816 : // This routine will return an error and exit for window constructions with between-glass shade or blind
5817 : // until a method is worked out to determine the nominal conductance and SHGC in this case.
5818 : // If an interior or exterior shade or blind is present in the construction,
5819 : // the conductance calculation does not include the effect of the shade or blind.
5820 : // This is because in this case the conductance depends on the natural convective
5821 : // air flow in the shade/glass, screen/glass or blind/glass channel, which in turn is highly dependent
5822 : // on window height and other parameters that are not part of the construction definition.
5823 : // Therefore, the reported conductance value will be too high for windows with a tightly fitting
5824 : // shade, screen or blind with a relatively high thermal resistance.
5825 : // For SHGC calculation, all solar absorbed by interior blind or shade is assumed
5826 : // to go into zone air. (This is not true in general; the fraction of this absorbed solar that
5827 : // is conducted back out is accounted for in the time-step glazing calculation.)
5828 : // For CR 7682, the SHGC calculations were changed to model the absorbed solar arriving at the middle of the layer
5829 : // rather than at the outer face of the layer. The resistances changed by one half the glazing layer, or 0.5/scon(n).
5830 : // (CR 7682 also changed WindowTempsForNominalCond to include absorbed solar, a bigger change)
5831 :
5832 : // Locals
5833 : // SUBROUTINE ARGUMENT DEFINITIONS:
5834 : // normal incidence beam solar radiation
5835 :
5836 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5837 : int TotLay; // Total number of layers in a construction
5838 : // (sum of solid layers and gap layers)
5839 : int TotGlassLay; // Total number of glass layers in a construction
5840 : int LayPtr; // Material number for a layer
5841 :
5842 : Real64 BeamSolarInc; // Incident beam radiation at zero angle of incidence (W/m2)
5843 : // Real64 hOutRad; // Radiative conductance of outside and inside airfilm [W/m2-K]
5844 : // Real64 hInRad;
5845 : // Real64 rOut; // Combined radiative and conductive outside and inside film
5846 : // Real64 rIn;
5847 : // resistance [m2-K/W]
5848 : Array1D<Real64> hgap(
5849 66 : maxGlassLayers); // Conductive gap conductance [W/m2-K]
5850 : // Array1D<Real64> hGapTot(5); // Combined radiative and conductive gap conductance [W/m2-K]
5851 : // Real64 Rbare; // Nominal center-of-glass resistance without air films [m2-K/W]
5852 : WinShadingType ShadeFlag; // Shading flag
5853 : Real64 ShadeRes; // Thermal resistance of shade
5854 : int MatOutside; // Material number of outside layer of construction
5855 : int MatInside; // Material number of inside layer of construction
5856 : int MatShade; // Material number of shade layer
5857 66 : Array1D<Real64> AbsBeamNorm(maxGlassLayers); // Beam absorptance at normal incidence for each glass layer
5858 : Real64 AbsBeamShadeNorm; // Shade solar absorptance at normal incidence
5859 : int ConstrNumBare; // Construction without shading device
5860 : int BlNum; // Blind number
5861 : Real64 SlatAng; // Slat angle (rad)
5862 : int LayPtrSh; // Layer pointer of blind
5863 : Real64 TBmBm; // Bare glass normal incidence beam-beam transmittance
5864 : Real64 TBmBmVis;
5865 : Real64 TBlBmBm; // Normal incidence blind beam-beam transmittance
5866 : Real64 TScBmBm; // Screen incident beam-beam transmittance
5867 : Real64 TScBmBmVis;
5868 : Real64 TBmBmBl; // TBmBm * TBlBmBm, TBmBmVis * TBlBmBm
5869 : Real64 TBmBmBlVis;
5870 : Real64 RGlDiffBack; // Bare glass back sol/vis reflectance
5871 : Real64 RGlDiffBackVis;
5872 : Real64 RGlDiffFront; // Bare glass front sol/vis reflectance
5873 : Real64 RGlDiffFrontVis;
5874 : Real64 RhoBlFront; // Blind normal front beam-diffuse sol/vis reflectance
5875 : Real64 RhoBlFrontVis;
5876 : Real64 RhoBlBack; // Blind normal back beam-diffuse sol/vis reflectance
5877 : Real64 RhoBlBackVis;
5878 : Real64 RScBack; // Screen back beam-diffuse sol/vis reflectance (same as front)
5879 : Real64 RScBackVis;
5880 : Real64 AbsBlFront; // Blind normal front beam solar absorptance
5881 : Real64 AbsBlBack; // Blind normal back beam solar absorptance
5882 : Real64 RhoBlDiffFront; // Blind front diffuse-diffuse sol/vis reflectance
5883 : Real64 RhoBlDiffFrontVis;
5884 : Real64 AbsBlDiffFront; // Blind front diffuse solar absorptance
5885 : Real64 AbsBlDiffBack; // Blind back diffuse solar absorptance
5886 : Real64 RGlFront; // Bare glass normal front beam sol/vis reflectance
5887 : Real64 RGlFrontVis;
5888 : Real64 RhoBlDiffBack; // Blind back diffuse-diffuse sol/vis reflectance
5889 : Real64 RhoBlDiffBackVis;
5890 : Real64 RScDifBack; // Screen back diffuse-diffuse sol/vis reflectance (doesn't change with sun angle)
5891 : Real64 RScDifBackVis;
5892 : Real64 TBlBmDif; // Blind front normal beam-diffuse sol/vis transmittance
5893 : Real64 TBlBmDifVis;
5894 : Real64 TBlDifDif; // Blind front diffuse-diffuse sol/vis transmittance
5895 : Real64 TBlDifDifVis;
5896 : Real64 TScBmDif; // Screen front beam-diffuse sol/vis transmittance
5897 : Real64 TScBmDifVis;
5898 : Real64 TDif; // Bare glass diffuse sol/vis transmittance
5899 : Real64 TDifVis;
5900 : Real64 AGlDiffBack; // Back diffuse solar absorptance of a glass layer
5901 :
5902 66 : auto &s_mat = state.dataMaterial;
5903 66 : auto &s_surf = state.dataSurface;
5904 66 : auto &wm = state.dataWindowManager;
5905 : // Autodesk:Uninit Initialize variables used uninitialized
5906 : // Rbare = 0.0; // Autodesk:Uninit Force default initialization
5907 :
5908 66 : NominalConductance = 0.0;
5909 66 : errFlag = 0;
5910 66 : TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
5911 66 : TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
5912 66 : wm->ngllayer = TotGlassLay; // Autodesk:Uninit This routine needs to check/enforce 1<=ngllayer<=4
5913 : // EPTeam - believe that is done on input.
5914 66 : wm->nglface = 2 * wm->ngllayer;
5915 66 : wm->tilt = 90.0; // Assume vertical window
5916 :
5917 66 : if (WinterSummerFlag == 1) { // Winter
5918 : // LKL Oct 2007: According to Window5, Winter environmental conditions are:
5919 41 : wm->tin = 294.15; // Inside air temperature (69.8F, 21.C)
5920 41 : wm->tout = 255.15; // Outside air temperature (-.4F, -18C)
5921 41 : wm->hcout = 26.0; // Outside convective film conductance for 5.5 m/s (12.3 mph) wind speed
5922 : // (the value used in Window 5)
5923 : // tin = 294.26 ! Inside air temperature (70F, 21.1C)
5924 : // tout = 255.35 ! Outside air temperature (0F, -17.8C)
5925 : // hcout = 25.47 ! Outside convective film conductance for 6.71 m/s (15 mph) wind speed
5926 : // ! (the value used in Window 4)
5927 41 : BeamSolarInc = 0.0;
5928 : } else { // Summer
5929 : // LKL Oct 2007: According to Window5, Summer environmental conditions are:
5930 : // tin = 297.05d0 ! Inside air temperature (75.2F, 24C)
5931 : // BG Feb. 2009: According to Window5 Expert Christian Kohler, it is exactly 24C or 297.15
5932 25 : wm->tin = 297.15;
5933 25 : wm->tout = 305.15; // Outside air temperature (89.6F, 32C)
5934 25 : wm->hcout = 15.0; // Outside convective film conductance for 2.8 m/s (6.2 mph) wind speed
5935 : // (the value used in Window 5)
5936 : // tin = 297.05 ! Inside air temperature (75F, 23.9C)
5937 : // !tout = 308.15 ! Outside air temperature (95F, 35.0C)
5938 : // ! Changed 6/20/01 by FCW to make consistent with Window 4 and 5.
5939 : // tout = 304.82 ! Outside air temperature (89F, 31.7C)
5940 : // hcout = 18.86 ! Outside convective film conductance for 3.35 m/s (7.5 mph) wind speed
5941 : // ! (average of Window 4 0 m/s and 6.71 m/s values)
5942 25 : BeamSolarInc = 783.0;
5943 : }
5944 :
5945 : // IR incident on inside of glazing (inside surround assumed to be
5946 : // a black body at inside air temperature)
5947 66 : wm->Rmir = Constant::StefanBoltzmann * pow_4(wm->tin);
5948 :
5949 : // IR incident on outside of glazing
5950 : // (outside surround is assumed to be a black body at outside air temperature)
5951 66 : wm->Outir = Constant::StefanBoltzmann * pow_4(wm->tout);
5952 :
5953 : // Determine whether construction has an exterior or interior shade or blind
5954 66 : ShadeFlag = WinShadingType::NoShade;
5955 66 : ShadeRes = 0.0;
5956 66 : MatOutside = state.dataConstruction->Construct(ConstrNum).LayerPoint(1);
5957 66 : MatInside = state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLay);
5958 66 : if (s_mat->materials(MatOutside)->group == Material::Group::Shade) { // Exterior shade present
5959 0 : MatShade = MatOutside;
5960 0 : ShadeFlag = WinShadingType::ExtShade;
5961 : // Set glazing outside convection coefficient to Window 4 still-air value
5962 0 : wm->hcout = 12.25;
5963 66 : } else if (s_mat->materials(MatOutside)->group == Material::Group::Screen) { // Exterior screen present
5964 0 : MatShade = MatOutside;
5965 0 : ShadeFlag = WinShadingType::ExtScreen;
5966 0 : wm->hcout = 12.25;
5967 66 : } else if (s_mat->materials(MatOutside)->group == Material::Group::Blind) { // Exterior blind present
5968 0 : MatShade = MatOutside;
5969 0 : ShadeFlag = WinShadingType::ExtBlind;
5970 0 : BlNum = MatOutside;
5971 0 : wm->hcout = 12.25;
5972 66 : } else if (s_mat->materials(MatInside)->group == Material::Group::Shade) { // Interior shade present
5973 0 : MatShade = MatInside;
5974 0 : ShadeFlag = WinShadingType::IntShade;
5975 66 : } else if (s_mat->materials(MatInside)->group == Material::Group::Blind) { // Interior blind present
5976 2 : MatShade = MatInside;
5977 2 : BlNum = MatShade;
5978 2 : ShadeFlag = WinShadingType::IntBlind;
5979 64 : } else if (TotGlassLay == 2) {
5980 17 : if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(3))->group == Material::Group::Shade)
5981 0 : ShadeFlag = WinShadingType::BGShade;
5982 17 : if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(3))->group == Material::Group::Blind)
5983 0 : ShadeFlag = WinShadingType::BGBlind;
5984 47 : } else if (TotGlassLay == 3) {
5985 0 : if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(5))->group == Material::Group::Shade)
5986 0 : ShadeFlag = WinShadingType::BGShade;
5987 0 : if (s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(5))->group == Material::Group::Blind)
5988 0 : ShadeFlag = WinShadingType::BGBlind;
5989 : }
5990 :
5991 66 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
5992 0 : errFlag = 2;
5993 0 : return;
5994 : }
5995 :
5996 66 : TSolNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef);
5997 66 : TVisNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransVisBeamCoef);
5998 66 : AbsBeamShadeNorm = 0.0;
5999 66 : if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) { // Exterior or interior shade on
6000 0 : AbsBeamShadeNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamShadeCoef);
6001 : // Exterior blind or screen or interior blind on
6002 66 : } else if (ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) {
6003 : // Find unshaded construction that goes with this construction w/blind or screen
6004 2 : ConstrNumBare = 0;
6005 24 : for (int ConstrNum1 = 1; ConstrNum1 <= state.dataHeatBal->TotConstructs; ++ConstrNum1) {
6006 24 : if (ConstrNum1 != ConstrNum && state.dataConstruction->Construct(ConstrNum1).TypeIsWindow &&
6007 50 : state.dataConstruction->Construct(ConstrNum1).TotGlassLayers == state.dataConstruction->Construct(ConstrNum1).TotSolidLayers &&
6008 2 : state.dataConstruction->Construct(ConstrNum1).TotGlassLayers == state.dataConstruction->Construct(ConstrNum).TotGlassLayers) {
6009 : // We have an unshaded window construction with the same number of glass layers as ConstrNum;
6010 : // see if the glass and gas layers match
6011 2 : ConstrNumBare = ConstrNum1;
6012 4 : for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum1).TotLayers; ++Lay) {
6013 2 : LayPtr = state.dataConstruction->Construct(ConstrNum1).LayerPoint(Lay);
6014 2 : if (ShadeFlag == WinShadingType::IntBlind) { // The shaded construction has an interior blind
6015 2 : LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
6016 : } else { // The shaded construction has an exterior blind or screen
6017 0 : LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay + 1);
6018 : }
6019 2 : if (LayPtrSh != LayPtr) ConstrNumBare = 0;
6020 : }
6021 2 : if (ConstrNumBare != 0) break;
6022 : }
6023 : }
6024 2 : if (ConstrNumBare == 0) {
6025 : // No matching bare construction found for this construction with blind or screen
6026 0 : errFlag = 1;
6027 0 : return;
6028 : }
6029 :
6030 2 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6031 2 : TBmBm = POLYF(1.0, constructBare.TransSolBeamCoef);
6032 2 : TBmBmVis = POLYF(1.0, constructBare.TransVisBeamCoef);
6033 :
6034 2 : if (ShadeFlag == WinShadingType::ExtScreen) {
6035 : // Don't need to call subroutine, use normal incident properties (SUBROUTINE CalcNominalWindowCond)
6036 : // Last call to CalcScreenTransmittance(ISurf) was done at direct normal angle (0,0) in CalcWindowScreenProperties
6037 0 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(s_mat->materials(MatShade));
6038 0 : assert(matScreen != nullptr);
6039 0 : auto const &btar = matScreen->btars[0][0];
6040 0 : TScBmBm = btar.BmTrans;
6041 0 : TScBmBmVis = btar.BmTransVis;
6042 0 : TScBmDif = btar.DfTrans;
6043 0 : TScBmDifVis = btar.DfTransVis;
6044 0 : TDif = constructBare.TransDiff;
6045 0 : TDifVis = constructBare.TransDiffVis;
6046 0 : RScBack = matScreen->ShadeRef;
6047 0 : RScBackVis = matScreen->ShadeRefVis;
6048 0 : RScDifBack = matScreen->DfRef;
6049 0 : RScDifBackVis = matScreen->DfRefVis;
6050 0 : RGlFront = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6051 0 : RGlFrontVis = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6052 0 : RGlDiffFront = constructBare.ReflectSolDiffFront;
6053 0 : RGlDiffFrontVis = constructBare.ReflectVisDiffFront;
6054 0 : TSolNorm = TScBmBm * (TBmBm + TDif * RGlFront * RScBack / (1 - RGlDiffFront * RScDifBack)) +
6055 0 : TScBmDif * TDif / (1 - RGlDiffFront * RScDifBack);
6056 0 : TVisNorm = TScBmBmVis * (TBmBmVis + TDifVis * RGlFrontVis * RScBackVis / (1 - RGlDiffFrontVis * RScDifBackVis)) +
6057 0 : TScBmDifVis * TDifVis / (1 - RGlDiffFrontVis * RScDifBackVis);
6058 :
6059 : } else { // Blind
6060 2 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlNum));
6061 2 : assert(matBlind != nullptr);
6062 :
6063 2 : SlatAng = matBlind->SlatAngle * Constant::DegToRad;
6064 2 : Real64 ProfAng = 0.0;
6065 :
6066 : int slatIdxLo, slatIdxHi;
6067 : Real64 slatInterpFac;
6068 2 : Material::GetSlatIndicesInterpFac(SlatAng, slatIdxLo, slatIdxHi, slatInterpFac);
6069 2 : Material::BlindTraAbsRef<Material::MaxProfAngs + 1> blindTAR;
6070 : // This interpolates all blind properties. No need to interpolate them one-by-one
6071 2 : blindTAR.interpSlatAng(matBlind->TARs[slatIdxLo], matBlind->TARs[slatIdxHi], slatInterpFac);
6072 :
6073 : int profIdxLo, profIdxHi;
6074 2 : Material::GetProfIndices(ProfAng, profIdxLo, profIdxHi);
6075 :
6076 2 : assert(profIdxLo == (Material::MaxProfAngs / 2) + 1); // Should be true for ProfAng == 0.0
6077 :
6078 2 : TBlBmBm = matBlind->BeamBeamTrans(0.0, SlatAng);
6079 2 : TBmBmBl = TBmBm * TBlBmBm;
6080 2 : TBmBmBlVis = TBmBmVis * TBlBmBm;
6081 2 : TBlBmDif = blindTAR.Sol.Ft.Bm[profIdxLo].DfTra;
6082 2 : TBlBmDifVis = blindTAR.Vis.Ft.Bm[profIdxLo].DfTra;
6083 2 : TDif = constructBare.TransDiff;
6084 2 : TDifVis = constructBare.TransDiffVis;
6085 2 : if (ShadeFlag == WinShadingType::IntBlind) {
6086 2 : RGlDiffBack = constructBare.ReflectSolDiffBack;
6087 2 : RGlDiffBackVis = constructBare.ReflectVisDiffBack;
6088 2 : RhoBlFront = blindTAR.Sol.Ft.Bm[profIdxLo].DfRef;
6089 2 : RhoBlFrontVis = blindTAR.Vis.Ft.Bm[profIdxLo].DfRef;
6090 2 : AbsBlFront = blindTAR.Sol.Ft.Bm[profIdxLo].Abs;
6091 2 : RhoBlDiffFront = blindTAR.Sol.Ft.Df.Ref;
6092 2 : RhoBlDiffFrontVis = blindTAR.Vis.Ft.Df.Ref;
6093 2 : AbsBlDiffFront = blindTAR.Sol.Ft.Df.Abs;
6094 2 : AbsBeamShadeNorm = TBmBm * (AbsBlFront + RhoBlFront * RGlDiffBack * AbsBlDiffFront / (1.0 - RhoBlDiffFront * RGlDiffBack));
6095 2 : TBlDifDif = blindTAR.Sol.Ft.Df.Tra;
6096 2 : TBlDifDifVis = blindTAR.Vis.Ft.Df.Tra;
6097 2 : TSolNorm = TBmBm * (TBlBmBm + TBlBmDif + TBlDifDif * RhoBlFront * RGlDiffBack / (1.0 - RhoBlDiffFront * RGlDiffBack));
6098 : // use of TBlBmBm here is correct, visible and IR transmittance are the same (reference deleted CR6925 on 3/20/2006)
6099 2 : TVisNorm = TBmBmVis *
6100 2 : (TBlBmBm + TBlBmDifVis + TBlDifDifVis * RhoBlFrontVis * RGlDiffBackVis / (1.0 - RhoBlDiffFrontVis * RGlDiffBackVis));
6101 :
6102 0 : } else if (ShadeFlag == WinShadingType::ExtBlind) {
6103 0 : RGlFront = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6104 0 : RGlFrontVis = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6105 0 : AbsBlFront = blindTAR.Sol.Ft.Bm[profIdxLo].Abs;
6106 0 : AbsBlBack = blindTAR.Sol.Bk.Bm[profIdxLo].Abs;
6107 0 : AbsBlDiffBack = blindTAR.Sol.Bk.Df.Abs;
6108 0 : RGlDiffFront = constructBare.ReflectSolDiffFront;
6109 0 : RGlDiffFrontVis = constructBare.ReflectVisDiffFront;
6110 :
6111 0 : RhoBlDiffBack = blindTAR.Sol.Bk.Df.Ref;
6112 0 : RhoBlDiffBackVis = blindTAR.Vis.Bk.Df.Ref;
6113 0 : RhoBlBack = blindTAR.Sol.Bk.Bm[profIdxLo].DfRef;
6114 0 : RhoBlBackVis = blindTAR.Vis.Bk.Bm[profIdxLo].DfRef;
6115 :
6116 0 : AbsBeamShadeNorm =
6117 0 : AbsBlFront + AbsBlBack * RGlFront * TBlBmBm +
6118 0 : (AbsBlDiffBack * RGlDiffFront / (1.0 - RhoBlDiffBack * RGlDiffFront)) * (RGlFront * TBlBmBm * RhoBlBack + TBlBmDif);
6119 0 : RGlDiffFront = constructBare.ReflectSolDiffFront;
6120 0 : TSolNorm = TBlBmBm * (TBmBm + TDif * RGlFront * RhoBlBack / (1 - RGlDiffFront * RhoBlDiffBack)) +
6121 0 : TBlBmDif * TDif / (1.0 - RGlDiffFront * RhoBlDiffBack);
6122 0 : TVisNorm = TBlBmBm * (TBmBmVis + TDifVis * RGlFrontVis * RhoBlBackVis / (1 - RGlDiffFrontVis * RhoBlDiffBackVis)) +
6123 0 : TBlBmDifVis * TDifVis / (1.0 - RGlDiffFrontVis * RhoBlDiffBackVis);
6124 : } // (ExtBlind)
6125 : } // (Screen or Blind)
6126 : } // (Shade, Blind, or Screen)
6127 :
6128 : // Fill the layer properties needed for the thermal calculation.
6129 :
6130 : // The layer and face numbering are as follows (for the triple glazing case):
6131 : // Glass layers are 1,2 and 3, where 1 is the outside (outside environment facing)
6132 : // layer and 3 is the inside (room-facing) layer;
6133 : // Faces (also called surfaces) are 1,2,3,4,5 and 6, where face 1 is the
6134 : // outside (front) face of glass layer 1, face 2 is the inside (back)
6135 : // face of glass layer 1, face 3 is the outer face of glass layer 2, face 4 is the
6136 : // inner face of glass layer 2, etc.
6137 : // Gap layers are 1 and 2, where gap layer 1 is between glass layers 1 and 2
6138 : // and gap layer 2 is between glass layers 2 and 3.
6139 :
6140 66 : int IGlass = 0;
6141 66 : int IGap = 0;
6142 :
6143 172 : for (int Lay = 1; Lay <= TotLay; ++Lay) {
6144 106 : LayPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
6145 106 : auto const *mat = s_mat->materials(LayPtr);
6146 :
6147 106 : if ((mat->group == Material::Group::Glass) || (mat->group == Material::Group::GlassSimple)) {
6148 83 : auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
6149 83 : assert(matGlass != nullptr);
6150 :
6151 83 : ++IGlass;
6152 83 : wm->thick[IGlass - 1] = matGlass->Thickness;
6153 83 : wm->scon[IGlass - 1] = matGlass->Conductivity / matGlass->Thickness;
6154 83 : wm->emis[2 * IGlass - 2] = matGlass->AbsorpThermalFront;
6155 83 : wm->emis[2 * IGlass - 1] = matGlass->AbsorpThermalBack;
6156 83 : wm->tir[2 * IGlass - 2] = matGlass->TransThermal;
6157 83 : wm->tir[2 * IGlass - 1] = matGlass->TransThermal;
6158 83 : AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef(IGlass));
6159 83 : if (ShadeFlag == WinShadingType::IntBlind) { // Interior blind on
6160 2 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6161 2 : AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
6162 2 : AGlDiffBack = constructBare.AbsDiffBack(IGlass);
6163 2 : AbsBeamNorm(IGlass) += TBmBm * AGlDiffBack * RhoBlFront / (1.0 - RhoBlFront * RGlDiffBack);
6164 81 : } else if (ShadeFlag == WinShadingType::ExtBlind) { // Exterior blind on
6165 0 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6166 0 : AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
6167 0 : AbsBeamNorm(IGlass) = TBlBmBm * AbsBeamNorm(IGlass) + (TBlBmBm * RGlFront * RhoBlBack + TBlBmDif) *
6168 0 : constructBare.AbsDiff(IGlass) / (1.0 - RGlDiffFront * RhoBlDiffBack);
6169 81 : } else if (ShadeFlag == WinShadingType::ExtScreen) { // Exterior screen on
6170 0 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6171 0 : AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
6172 0 : AbsBeamNorm(IGlass) = TScBmBm * AbsBeamNorm(IGlass) + (TScBmBm * RGlFront * RScBack + TScBmDif) * constructBare.AbsDiff(IGlass) /
6173 0 : (1.0 - RGlDiffFront * RScDifBack);
6174 : }
6175 83 : wm->AbsRadGlassFace[2 * IGlass - 2] = 0.5 * BeamSolarInc * AbsBeamNorm(IGlass);
6176 83 : wm->AbsRadGlassFace[2 * IGlass - 1] = 0.5 * BeamSolarInc * AbsBeamNorm(IGlass);
6177 : }
6178 106 : if (mat->group == Material::Group::Gas || mat->group == Material::Group::GasMixture ||
6179 91 : mat->group == Material::Group::ComplexWindowGap) { // Gap layer
6180 19 : ++IGap;
6181 :
6182 19 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
6183 19 : assert(matGas != nullptr);
6184 19 : wm->gaps[IGap - 1].width = matGas->Thickness;
6185 19 : wm->gaps[IGap - 1].numGases = matGas->numGases;
6186 38 : for (int IMix = 0; IMix < wm->gaps[IGap - 1].numGases; ++IMix) {
6187 19 : wm->gaps[IGap - 1].gases[IMix] = matGas->gases[IMix];
6188 19 : wm->gaps[IGap - 1].gasFracts[IMix] = matGas->gasFracts[IMix];
6189 : }
6190 : }
6191 : } // for (Lay)
6192 :
6193 : // Factors used in glass temperature solution
6194 66 : if (wm->ngllayer >= 2) {
6195 17 : wm->A23P = -wm->emis[2] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
6196 17 : wm->A32P = wm->emis[1] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
6197 17 : wm->A23 = wm->emis[1] * Constant::StefanBoltzmann * wm->A23P;
6198 : }
6199 :
6200 66 : if (wm->ngllayer >= 3) {
6201 0 : wm->A45P = -wm->emis[4] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
6202 0 : wm->A54P = wm->emis[3] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
6203 0 : wm->A45 = wm->emis[3] * Constant::StefanBoltzmann * wm->A45P;
6204 : }
6205 :
6206 66 : if (wm->ngllayer == 4) {
6207 0 : wm->A67P = -wm->emis[6] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
6208 0 : wm->A76P = wm->emis[5] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
6209 0 : wm->A67 = wm->emis[5] * Constant::StefanBoltzmann * wm->A67P;
6210 : }
6211 :
6212 66 : wm->thetas = {0.0};
6213 :
6214 66 : WindowTempsForNominalCond(state, ConstrNum, hgap, 1.0);
6215 :
6216 66 : if (!ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) AbsBeamShadeNorm = 0.0;
6217 :
6218 : // Get center-of-glass conductance and solar heat gain coefficient
6219 : // including inside and outside air films
6220 66 : auto const *mat = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1));
6221 29 : Real64 inputU = (mat->group == Material::Group::Glass || mat->group == Material::Group::GlassSimple)
6222 95 : ? dynamic_cast<Material::MaterialGlass const *>(mat)->SimpleWindowUfactor
6223 66 : : 0.0;
6224 :
6225 : // Calculate the NominalConductance glazing only (before adjusted)
6226 66 : EvalNominalWindowCond(state, AbsBeamShadeNorm, AbsBeamNorm, hgap, NominalConductance, SHGC, TSolNorm);
6227 :
6228 66 : if (WinterSummerFlag == 1) {
6229 41 : state.dataHeatBal->NominalUBeforeAdjusted(ConstrNum) = NominalConductance;
6230 41 : if (inputU > 0) { // only compute adjustment ratio when there is valid user input U
6231 15 : Real64 wettedAreaAdjRatio = 1; // Adjustment ratio for the wetted area
6232 15 : Real64 hcoutRated = wm->hcout;
6233 : // Adjustment ratio applies to convective film coefficients when input U value is above the limit of the simple glazing nominal U
6234 : // Representing the nominal highly conductive frame effects. Solved iteratively.
6235 15 : Real64 adjLower = 1.0;
6236 15 : Real64 adjUpper = 2.0;
6237 15 : int MaxIter = 100;
6238 39 : while (std::abs(inputU - NominalConductance) > 0.01 && MaxIter > 0) {
6239 24 : wettedAreaAdjRatio = (adjLower + adjUpper) / 2;
6240 24 : WindowTempsForNominalCond(
6241 : state, ConstrNum, hgap, wettedAreaAdjRatio); // reeval hcout at each iteration, hcin is not linear to wetted area
6242 24 : wm->hcout = hcoutRated * wettedAreaAdjRatio; // reeval hcout
6243 24 : EvalNominalWindowCond(state, AbsBeamShadeNorm, AbsBeamNorm, hgap, NominalConductance, SHGC, TSolNorm);
6244 24 : if (NominalConductance < inputU) {
6245 8 : adjLower = wettedAreaAdjRatio;
6246 : } else {
6247 16 : adjUpper = wettedAreaAdjRatio;
6248 : }
6249 24 : MaxIter -= 1;
6250 : }
6251 15 : state.dataHeatBal->CoeffAdjRatio(ConstrNum) = wettedAreaAdjRatio;
6252 : }
6253 : }
6254 :
6255 : // EPTeam - again -- believe that is enforced in input //Autodesk But this routine is not self-protecting: Add as an assert
6256 :
6257 : // init the surface convective and radiative adjustment ratio
6258 220 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
6259 308 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
6260 154 : auto const &thisSpace = state.dataHeatBal->space(spaceNum);
6261 154 : int const firstSurfWin = thisSpace.WindowSurfaceFirst;
6262 154 : int const lastSurfWin = thisSpace.WindowSurfaceLast;
6263 367 : for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) {
6264 213 : if (s_surf->Surface(SurfNum).ExtBoundCond == ExternalEnvironment) {
6265 213 : int ConstrNum2 = s_surf->Surface(SurfNum).Construction;
6266 213 : state.dataHeatBalSurf->SurfWinCoeffAdjRatio(SurfNum) = state.dataHeatBal->CoeffAdjRatio(ConstrNum2);
6267 : }
6268 : }
6269 : }
6270 : }
6271 :
6272 : // Need to add variables writing here since this routine will override previously calculated values from WinCalc-Engine
6273 66 : if (wm->inExtWindowModel->isExternalLibraryModel()) {
6274 0 : TSolNorm = GetSolarTransDirectHemispherical(state, ConstrNum);
6275 0 : TVisNorm = GetVisibleTransDirectHemispherical(state, ConstrNum);
6276 : }
6277 66 : } // CalcNominalWindowCond()
6278 :
6279 90 : void EvalNominalWindowCond(EnergyPlusData &state,
6280 : Real64 const AbsBeamShadeNorm, // Shade solar absorptance at normal incidence
6281 : Array1D<Real64> const AbsBeamNorm, // Beam absorptance at normal incidence for each glass layer
6282 : Array1D<Real64> const hgap, // Conductive gap conductance [W/m2-K]
6283 : Real64 &NominalConductance, // Nominal center-of-glass conductance, including air films
6284 : Real64 &SHGC, // Nominal center-of-glass solar heat gain coefficient for
6285 : Real64 const TSolNorm // Overall beam solar transmittance at normal incidence
6286 : )
6287 : {
6288 90 : Array1D<Real64> hGapTot(5); // Combined radiative and conductive gap conductance [W/m2-K]
6289 :
6290 90 : auto const &wm = state.dataWindowManager;
6291 90 : Real64 hOutRad = wm->emis[0] * Constant::StefanBoltzmann * 0.5 * pow_3(wm->tout + wm->thetas[0]);
6292 90 : Real64 rOut = 1.0 / (hOutRad + wm->hcout);
6293 90 : Real64 hInRad = wm->emis[wm->nglface - 1] * Constant::StefanBoltzmann * 0.5 * pow_3(wm->tin + wm->thetas[wm->nglface - 1]);
6294 90 : Real64 rIn = 1.0 / (hInRad + wm->hcin);
6295 90 : Real64 Rbare = 0;
6296 :
6297 90 : switch (wm->ngllayer) {
6298 : // the switch cases here are just the integer number of layers, not exactly "magic" numbers 1, 2, 3. and 4.
6299 73 : case 1: {
6300 73 : Rbare = 1.0 / wm->scon[0];
6301 73 : wm->Rtot = rOut + Rbare + rIn;
6302 73 : SHGC = AbsBeamNorm(1) * (rOut + (0.5 / wm->scon[0])) / wm->Rtot; // BG changed for CR7682 (solar absorbed in middle of layer)
6303 73 : SHGC += AbsBeamShadeNorm;
6304 73 : SHGC += TSolNorm;
6305 73 : } break;
6306 :
6307 17 : case 2: {
6308 17 : hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
6309 17 : Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1];
6310 17 : wm->Rtot = rOut + Rbare + rIn;
6311 17 : SHGC = AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
6312 17 : AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot; // CR7682
6313 17 : SHGC += AbsBeamShadeNorm;
6314 17 : SHGC += TSolNorm;
6315 17 : } break;
6316 :
6317 0 : case 3: {
6318 0 : hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
6319 0 : hGapTot(2) = hgap(2) + std::abs(wm->A45) * 0.5 * pow_3(wm->thetas[3] + wm->thetas[4]);
6320 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];
6321 0 : wm->Rtot = rOut + Rbare + rIn;
6322 0 : SHGC =
6323 0 : AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
6324 0 : AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot +
6325 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;
6326 0 : SHGC += AbsBeamShadeNorm;
6327 0 : SHGC += TSolNorm;
6328 0 : } break;
6329 :
6330 0 : case 4: {
6331 0 : hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
6332 0 : hGapTot(2) = hgap(2) + std::abs(wm->A45) * 0.5 * pow_3(wm->thetas[3] + wm->thetas[4]);
6333 0 : hGapTot(3) = hgap(3) + std::abs(wm->A67) * 0.5 * pow_3(wm->thetas[5] + wm->thetas[6]);
6334 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) +
6335 0 : 1.0 / wm->scon[3];
6336 0 : wm->Rtot = rOut + Rbare + rIn;
6337 0 : SHGC =
6338 0 : AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
6339 0 : AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot +
6340 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 +
6341 0 : AbsBeamNorm(4) *
6342 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) +
6343 0 : 0.5 / wm->scon[3]) /
6344 0 : wm->Rtot; // CR7682
6345 0 : SHGC += AbsBeamShadeNorm;
6346 0 : SHGC += TSolNorm;
6347 0 : } break;
6348 0 : default:
6349 0 : break;
6350 : }
6351 90 : NominalConductance = 1.0 / (rOut + Rbare + rIn);
6352 90 : } // EvalNominalWindowCond()
6353 :
6354 : //****************************************************************************
6355 :
6356 90 : void WindowTempsForNominalCond(EnergyPlusData &state,
6357 : int const ConstrNum, // Construction number
6358 : Array1A<Real64> hgap, // Gap gas conductive conductance (W/m2-K)
6359 : Real64 const adjRatio // adjustment Ratio to hcin
6360 : )
6361 : {
6362 :
6363 : // SUBROUTINE INFORMATION:
6364 : // AUTHOR F. Winkelmann
6365 : // DATE WRITTEN September 2000
6366 : // MODIFIED Nov 2002, FW: increase MaxIterations from 15 to 100, add face
6367 : // temperature relaxation, and increase convergence tolerance by
6368 : // a factor of 10 if no convergence after MaxIterations,
6369 : // all for consistency with SolveForWindowTemperatures.
6370 : // Mar 2003, FW: increase convergence tolerance from 0.01 to 0.02;
6371 : // remove redundant relaxation on radiative conductances (both of
6372 : // these were also done in SolveForWindowTemperatures).
6373 : // Jan 2009, BG: changed interior convection coefficient correlation to match
6374 : // ISO 15099.
6375 : // Feb 2009, BG: extended coefficient to include absorbed radiation
6376 : // to cover summer conditions for SHGC determination.
6377 : // RE-ENGINEERED na
6378 :
6379 : // PURPOSE OF THIS SUBROUTINE:
6380 : // This is a shortened form of SolveForWindowTemperatures tailored
6381 : // for calculation of the nominal center-of-glass U-value for a window
6382 : // construction at ASHRAE winter conditions and for determining conditions at
6383 : // summer conditions for calculating SHGC.
6384 : // Evaluates the coefficients Aface and Bface in the system of linear
6385 : // algebraic equations
6386 : // Sum [Aface(i,j)*thetas(j)] = Bface(i), i = 1,nglface
6387 : // j=1,nglface
6388 : // where
6389 : // nglface = number of glass faces (= 2 * number of layers) and
6390 : // thetas(j) = temperature of face j
6391 :
6392 : // METHODOLOGY EMPLOYED:
6393 : // The Aface and Bface coefficients are determined by the equations for
6394 : // heat balance at the glass faces. The system of linear equations is solved
6395 : // by LU decomposition.
6396 :
6397 : // Argument array dimensioning
6398 90 : hgap.dim(5);
6399 :
6400 90 : int constexpr MaxIterations(100); // Maximum allowed number of iterations
6401 90 : Real64 constexpr errtemptol(0.02); // Tolerance on errtemp for convergence
6402 : static constexpr std::string_view RoutineName("WindowTempsForNominalCond");
6403 :
6404 90 : Array1D<Real64> hr(10); // Radiative conductance (W/m2-K)
6405 : Real64 hcinprev; // Value of hcin from previous iteration
6406 : int d; // +1 if number of row interchanges is even,
6407 : // -1 if odd (in LU decomposition)
6408 90 : Array1D_int indx(10); // Vector of row permutations in LU decomposition
6409 90 : Array2D<Real64> Aface(10, 10); // Coefficient in equation Aface*thetas = Bface
6410 90 : Array1D<Real64> Bface(10); // Coefficient in equation Aface*thetas = Bface
6411 : int iter; // Iteration number
6412 : Real64 errtemp; // Absolute value of sum of face temperature differences
6413 : // between iterations, divided by number of faces
6414 : Real64 TmeanFilm; // mean film temperature
6415 : Real64 TmeanFilmKelvin; // mean film temperature for property evaluation
6416 : Real64 rho; // density of (apparently dry) air [kg/m3]
6417 : Real64 g; // acceleration due to gravity [m/s2]
6418 : Real64 Height; // window cavity height [m]
6419 : Real64 Cp; // specific heat of air [J/kg-K]
6420 : Real64 lambda; // thermal conductivity of air [W/m-K]
6421 : Real64 mu; // dynamic viscosity of air [kg/m-s]
6422 : Real64 RaH; // Rayleigh number for cavity height [ Non dim]
6423 : Real64 TiltDeg; // glazing tilt in degrees
6424 : Real64 sineTilt; // sine of glazing tilt
6425 : Real64 Nuint; // Nusselt number for interior surface convection
6426 :
6427 90 : auto &wm = state.dataWindowManager;
6428 :
6429 90 : iter = 0;
6430 :
6431 : // Initialize face temperatures
6432 90 : StartingWinTempsForNominalCond(state);
6433 :
6434 : // Calculate radiative conductance
6435 90 : errtemp = errtemptol * 2.0;
6436 :
6437 90 : TiltDeg = 90.0;
6438 :
6439 90 : sineTilt = std::sin(TiltDeg * Constant::DegToRad); // degrees as arg
6440 :
6441 686 : while (iter < MaxIterations && errtemp > errtemptol) {
6442 1964 : for (int i = 1; i <= wm->nglface; ++i) {
6443 1368 : hr(i) = wm->emis[i - 1] * Constant::StefanBoltzmann * pow_3(wm->thetas[i - 1]);
6444 : //! fw 3/4/03 if ( iter >= 1 ) hr(i) = 0.5*(hrprev(i)+hr(i))
6445 : }
6446 :
6447 596 : Aface = 0.0;
6448 596 : Bface = 0.0;
6449 :
6450 : // Inside convective film conductance for vertical window
6451 596 : if (iter >= 1) {
6452 506 : hcinprev = wm->hcin;
6453 : }
6454 : // CR7670 BG this next correlation was used for hcin but is not "standard" for windows
6455 : // hcin = 1.31d0*((ABS(thetas(nglface)-tin))**0.3333d0)
6456 : // Begin calculating for ISO 15099 method.
6457 : // mean film temperature
6458 596 : TmeanFilmKelvin = wm->tin + 0.25 * (wm->thetas[wm->nglface - 1] - wm->tin); // eq. 133 in ISO 15099
6459 596 : TmeanFilm = TmeanFilmKelvin - 273.15;
6460 : // the following properties are constants or linear relations for "standard" type reporting
6461 596 : rho = Psychrometrics::PsyRhoAirFnPbTdbW(state, 101325.0, TmeanFilm, 0.0, RoutineName); // dry air assumption
6462 596 : g = 9.81;
6463 596 : Height = 1.0; // standard window rating practice is to use 1 meter (rather than actual)
6464 :
6465 596 : lambda = 2.873E-3 + 7.76E-5 * TmeanFilmKelvin; // Table B.1 in ISO 15099
6466 596 : mu = 3.723E-6 + 4.94E-8 * TmeanFilmKelvin; // Table B.2 in ISO 15099
6467 596 : Cp = 1002.737 + 1.2324E-2 * TmeanFilmKelvin; // Table B.3 in ISO 15099
6468 :
6469 : // eq 132 in ISO 15099
6470 596 : RaH = (pow_2(rho) * pow_3(Height) * g * Cp * (std::abs(wm->thetas[wm->nglface - 1] - wm->tin))) / (TmeanFilmKelvin * mu * lambda);
6471 :
6472 596 : Nuint = 0.56 * root_4(RaH * sineTilt); // eq. 135 in ISO 15099 (only need this one because tilt is 90 deg
6473 :
6474 596 : wm->hcin = Nuint * lambda / Height;
6475 :
6476 : // End calculations for ISO 15099 method.
6477 :
6478 596 : if (iter >= 1) wm->hcin = 0.5 * (hcinprev + wm->hcin);
6479 :
6480 596 : wm->hcin *= adjRatio;
6481 :
6482 596 : ++iter;
6483 :
6484 596 : GetHeatBalanceEqCoefMatrixSimple(state, wm->ngllayer, hr, hgap, Aface, Bface);
6485 :
6486 596 : LUdecomposition(state, Aface, wm->nglface, indx, d); // Note that these routines change Aface;
6487 596 : LUsolution(state, Aface, wm->nglface, indx, Bface); // face temperatures are returned in Bface
6488 :
6489 596 : errtemp = 0.0;
6490 1964 : for (int i = 1; i <= wm->nglface; ++i) {
6491 1368 : errtemp += std::abs(wm->thetas[i - 1] - Bface(i)) / wm->nglface;
6492 : }
6493 :
6494 1964 : for (int i = 1; i <= wm->nglface; ++i) {
6495 1368 : wm->thetas[i - 1] = 0.5 * (wm->thetas[i - 1] + Bface(i));
6496 : }
6497 : }
6498 :
6499 : // No convergence after MaxIterations; and/or error tolerance
6500 90 : if (errtemp >= 10 * errtemptol) {
6501 : // Fatal error: didn't converge
6502 0 : ShowFatalError(
6503 : state,
6504 0 : format("Convergence error in WindowTempsForNominalCond for construction {}", state.dataConstruction->Construct(ConstrNum).Name));
6505 : }
6506 90 : } // WindowTempsForNominalCond()
6507 :
6508 : //****************************************************************************
6509 :
6510 90 : void StartingWinTempsForNominalCond(EnergyPlusData &state)
6511 : {
6512 :
6513 : // SUBROUTINE INFORMATION:
6514 : // AUTHOR F. Winkelmann
6515 : // DATE WRITTEN September 2000
6516 :
6517 : // PURPOSE OF THIS SUBROUTINE:
6518 : // Initializes face temperature distribution prior to iteration.
6519 : // This is a shortened form of StartingWindowTemps for use in calculating
6520 : // the nominal center-of-glass U-value.
6521 :
6522 90 : Real64 constexpr hrad = 5.3; // Typical radiative conductance (W/m2-K)
6523 90 : Real64 constexpr hcinStartValue = 3.2; // Starting value for inside air film convective
6524 : // conductance (estimated for typical double glazing
6525 : // using 1.31(dT**0.333), where dT =
6526 : // room air temp - inside surface temp = 14.2K)
6527 90 : Real64 constexpr resgap = 0.21; // Typical gap resistance (m2-K/W)
6528 :
6529 90 : Array1D<Real64> rguess(11); // Combined radiative/convective resistance (m2-K/W) of
6530 : // inside or outside air film, or gap
6531 : Real64 restot; // Total window resistance including outside
6532 : // and inside air films (m2-K/W)
6533 : Real64 temdiff; // Inside/outside air temperature difference (K)
6534 : Real64 ressum; // Resistance sum (m2-K/W)
6535 :
6536 90 : auto const &wm = state.dataWindowManager;
6537 :
6538 90 : rguess(1) = 1.0 / (wm->hcout + hrad);
6539 90 : rguess(wm->nglface + 1) = 1.0 / (hcinStartValue + hrad);
6540 :
6541 197 : for (int i = 2; i <= wm->nglface; i += 2) {
6542 107 : rguess(i) = 1.0 / wm->scon[i / 2 - 1];
6543 107 : if (i < wm->nglface) rguess(i + 1) = resgap;
6544 : }
6545 90 : restot = 0.0;
6546 :
6547 394 : for (int i = 1; i <= wm->nglface + 1; ++i) {
6548 304 : restot += rguess(i);
6549 : }
6550 :
6551 90 : temdiff = wm->tin - wm->tout;
6552 90 : if (std::abs(temdiff) < 0.5) temdiff = 2.0;
6553 90 : ressum = 0.0;
6554 :
6555 304 : for (int i = 1; i <= wm->nglface; ++i) {
6556 214 : ressum += rguess(i);
6557 214 : wm->thetas[i - 1] = (ressum / restot) * temdiff + wm->tout;
6558 : }
6559 90 : } // StartingWinTempsForNominalCond()
6560 :
6561 : //****************************************************************************
6562 :
6563 110 : void ReportGlass(EnergyPlusData &state)
6564 : {
6565 :
6566 : // SUBROUTINE INFORMATION:
6567 : // AUTHOR Linda K. Lawrie
6568 : // DATE WRITTEN March 2000
6569 :
6570 : // PURPOSE OF THIS SUBROUTINE:
6571 : // This routine gives a detailed report to the user about
6572 : // the calculation parameters for windows and their associated
6573 : // materials.
6574 :
6575 110 : Real64 TempVar = 0.0; // just temporary usage for complex fenestration
6576 :
6577 : Real64 NominalConductanceWinter; // Nominal center-of-glass conductance of a window construction
6578 : // for ASHRAE winter conditions (W/m2-K):
6579 : // Inside air temperature = 21.1C (70F)
6580 : // Outside air temperature = -17.8C (0F)
6581 : // Windspeed = 6.71 m/s (15 mph)
6582 : // No solar radiation
6583 : Real64 NominalConductanceSummer; // Nominal center-of-glass conductance of a window construction
6584 : // for ASHRAE summer conditions (W/m2-K):
6585 : // Inside air temperature = 23.9C (75F)
6586 : // Outside air temperature = 35.0C (95F)
6587 : // Windspeed = 3.35 m/s (7.5 mph)
6588 : // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
6589 110 : Real64 SHGCWinter(0.0); // Center-of-glass solar heat gain coefficient for ASHRAE
6590 110 : Real64 SHGCSummer(0.0);
6591 : // winter and summer conditions
6592 : Real64 TransSolNorm; // Window construction solar transmittance at normal incidence
6593 : Real64 TransVisNorm; // Window construction visible transmittance at normal incidence
6594 : int errFlag; // Error flag
6595 :
6596 110 : auto &wm = state.dataWindowManager;
6597 :
6598 330 : General::ScanForReports(state, "Constructions", wm->DoReport, "Constructions");
6599 :
6600 110 : if (std::any_of(state.dataConstruction->Construct.begin(),
6601 110 : state.dataConstruction->Construct.end(),
6602 296 : [](Construction::ConstructionProps const &e) { return e.TypeIsWindow; }))
6603 28 : wm->HasWindows = true;
6604 110 : if (std::any_of(state.dataConstruction->Construct.begin(),
6605 110 : state.dataConstruction->Construct.end(),
6606 323 : [](Construction::ConstructionProps const &e) { return e.WindowTypeBSDF; }))
6607 1 : wm->HasComplexWindows = true; // Yes, this is a bit different than actually using them.
6608 110 : if (std::any_of(state.dataConstruction->Construct.begin(),
6609 110 : state.dataConstruction->Construct.end(),
6610 323 : [](Construction::ConstructionProps const &e) { return e.WindowTypeEQL; }))
6611 6 : wm->HasEQLWindows = true; // for reporting purpose only
6612 110 : if (wm->DoReport && (wm->HasWindows || wm->HasComplexWindows || wm->HasEQLWindows)) {
6613 1 : auto const &s_mat = state.dataMaterial;
6614 : // Write Descriptions
6615 1 : print(state.files.eio,
6616 : "{}\n",
6617 : "! <WindowConstruction>,Construction Name,Index,#Layers,Roughness,Conductance {W/m2-K},Conductance (Before Adjusted) {W/m2-K},"
6618 : "Convection Coefficient Adjustment Ratio,SHGC,"
6619 : "Solar Transmittance at Normal Incidence,Visible Transmittance at Normal Incidence");
6620 1 : if ((s_mat->NumSimpleWindows > 0) || (s_mat->NumW5Glazings > 0) || (s_mat->NumW5AltGlazings > 0))
6621 1 : print(state.files.eio,
6622 : "{}\n",
6623 : "! <WindowMaterial:Glazing>, Material Name, Optical Data Type, Spectral Data Set Name, "
6624 : "Thickness {m}, Solar Transmittance,Front Solar Reflectance, Back Solar Reflectance, Visible "
6625 : "Transmittance, Front Visible Reflectance,Back Visible Reflectance,Infrared Transmittance, "
6626 : "Front Thermal Emissivity, Back Thermal Emissivity,Conductivity {W/m-K},Dirt Factor,Solar "
6627 : "Diffusing");
6628 1 : if ((s_mat->NumW5Gases > 0) || (s_mat->NumW5GasMixtures > 0))
6629 0 : print(state.files.eio, "{}\n", "! <WindowMaterial:Gas>,Material Name,GasType,Thickness {m}");
6630 1 : if (s_mat->NumShades > 0)
6631 0 : print(state.files.eio,
6632 : "{}\n",
6633 : "! <WindowMaterial:Shade>,Material Name,Thickness {m},Conductivity {W/m-K},Thermal "
6634 : "Absorptance,Transmittance,Visible Transmittance,Shade Reflectance");
6635 1 : if (s_mat->NumScreens > 0)
6636 0 : print(state.files.eio,
6637 : "{}\n",
6638 : "! <WindowMaterial:Screen>,Material Name,Thickness {m},Conductivity {W/m-K},Thermal "
6639 : "Absorptance,Transmittance,Reflectance,Visible Reflectance,Diffuse Reflectance,Diffuse Visible "
6640 : "Reflectance,Screen Material Diameter To Spacing Ratio,Screen To GlassDistance {m}");
6641 1 : if (s_mat->NumBlinds > 0)
6642 1 : print(state.files.eio,
6643 : "{}\n",
6644 : "! <WindowMaterial:Blind>,Material Name,Slat Width {m},Slat Separation {m},Slat Thickness "
6645 : "{m},Slat Angle {deg},Slat Beam Solar Transmittance,Slat Beam Solar Front Reflectance,Blind To "
6646 : "Glass Distance {m}");
6647 :
6648 1 : if (wm->HasComplexWindows)
6649 0 : print(state.files.eio,
6650 : "{}\n",
6651 : "! <WindowConstruction:Complex>,Construction Name,Index,#Layers,U-factor {W/m2-K},SHGC"
6652 : "NFRC Product Type,Assembly U-Factor {W/m2-K},Assembly SHGC,Assembly Visible Transmittance");
6653 :
6654 1 : if (wm->HasEQLWindows)
6655 0 : print(state.files.eio,
6656 : "{}\n",
6657 : "! <Construction:WindowEquivalentLayer>,Construction Name,Index,#Layers,U-factor {W/m2-K},SHGC, "
6658 : "Solar Transmittance at Normal Incidence");
6659 1 : if (s_mat->NumEQLGlazings > 0)
6660 0 : print(state.files.eio,
6661 : "{}\n",
6662 : "! <WindowMaterial:Glazing:EquivalentLayer>, Material Name, Optical Data Type, Spectral Data "
6663 : "Set Name, Front Side Beam-Beam Solar Transmittance, Back Side Beam-Beam Solar Transmittance, "
6664 : "Front Side Beam-Beam Solar Reflectance, Back Side Beam-Beam Solar Reflectance, Front Side "
6665 : "Beam-Diffuse Solar Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side "
6666 : "Beam-Diffuse Solar Reflectance, Back Side Beam-Diffuse Solar Reflectance, Diffuse-Diffuse "
6667 : "Solar Transmittance, Front Side Diffuse-Diffuse Solar Reflectance, Back Side Diffuse-Diffuse "
6668 : "Solar Reflectance, Infrared Transmittance, Front Side Infrared Emissivity, Back Side Infrared "
6669 : "Emissivity");
6670 1 : if (s_mat->NumEQLShades > 0)
6671 0 : print(state.files.eio,
6672 : "{}\n",
6673 : "! <WindowMaterial:Shade:EquivalentLayer>, Material Name, Front Side Beam-Beam Solar "
6674 : "Transmittance, Back Side Beam-Beam Solar Transmittance, Front Side Beam-Diffuse Solar "
6675 : "Transmittance, Back Side Beam-Diffuse Solar Transmittance, Front Side Beam-Diffuse Solar "
6676 : "Reflectance, Back Side Beam-Diffuse Solar Reflectance, Infrared Transmittance, Front Side "
6677 : "Infrared Emissivity, Back Side Infrared Emissivity");
6678 :
6679 1 : if (s_mat->NumEQLDrapes > 0)
6680 0 : print(state.files.eio,
6681 : "{}\n",
6682 : "! <WindowMaterial:Drape:EquivalentLayer>, Material Name, Front Side Beam-Beam Solar "
6683 : "Transmittance, Back Side Beam-Beam Solar Transmittance, Front Side Beam-Diffuse Solar "
6684 : "Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side Beam-Diffuse Solar "
6685 : "Reflectance, Back Side Beam-Diffuse Solar Reflectance, Infrared Transmittance, Front Side "
6686 : "Infrared Emissivity, Back Side Infrared Emissivity, Width of Pleated Fabric, Length of Pleated "
6687 : "Fabric");
6688 :
6689 1 : if (s_mat->NumEQLBlinds > 0)
6690 0 : print(state.files.eio,
6691 : "{}\n",
6692 : "! <WindowMaterial:Blind:EquivalentLayer>, Material Name, Slat Orientation, Slat Width, Slat "
6693 : "Separation, Slat Crown, Slat Angle, Front Side Slate Beam-Diffuse Solar Transmittance, Back "
6694 : "Side Slate Beam-Diffuse Solar Transmittance, Front Side Slate Beam-Diffuse Solar Reflectance, "
6695 : "Back Side Slate Beam-Diffuse Solar Reflectance, Slat Diffuse-Diffuse Solar Transmittance, "
6696 : "Front Side Slat Diffuse-Diffuse Solar Reflectance, Back Side Slat Diffuse-Diffuse Solar "
6697 : "Reflectance, Infrared Transmittance, Front Side Infrared Emissivity, Back Side Infrared "
6698 : "Emissivity, Slat Angle Control");
6699 1 : if (s_mat->NumEQLScreens > 0)
6700 0 : print(state.files.eio,
6701 : "{}\n",
6702 : "! <WindowMaterial:Screen:EquivalentLayer>, Material Name, Screen Beam-Beam Solar "
6703 : "Transmittance, Screen Beam-Diffuse Solar Transmittance, Screen Beam-Diffuse Solar Reflectance, "
6704 : "Screen Infrared Transmittance, Screen Infrared Emissivity, Screen Wire Spacing, Screen Wire "
6705 : "Diameter");
6706 1 : if (s_mat->NumEQLGaps > 0)
6707 0 : print(state.files.eio, "{}\n", "! <WindowMaterial:Gap:EquivalentLayer>, Material Name, GasType, Gap Thickness {m}, Gap Vent Type");
6708 :
6709 26 : for (int ThisNum = 1; ThisNum <= state.dataHeatBal->TotConstructs; ++ThisNum) {
6710 25 : auto &construct = state.dataConstruction->Construct(ThisNum);
6711 25 : if (construct.WindowTypeBSDF) {
6712 :
6713 0 : int i = ThisNum;
6714 0 : WindowComplexManager::CalcComplexWindowThermal(
6715 : state, 0, i, TempVar, TempVar, TempVar, TempVar, DataBSDFWindow::Condition::Winter);
6716 0 : WindowComplexManager::CalcComplexWindowThermal(
6717 : state, 0, i, TempVar, TempVar, TempVar, TempVar, DataBSDFWindow::Condition::Summer);
6718 :
6719 : static constexpr std::string_view Format_800(" WindowConstruction:Complex,{},{},{},{:.3R},{:.3R}\n");
6720 0 : print(state.files.eio,
6721 : Format_800,
6722 0 : construct.Name,
6723 : ThisNum,
6724 0 : construct.TotSolidLayers,
6725 0 : state.dataHeatBal->NominalU(ThisNum),
6726 0 : construct.SummerSHGC);
6727 :
6728 25 : } else if (construct.TypeIsWindow) {
6729 : // Calculate for ASHRAE winter and summer conditions:
6730 : // (1) nominal center-of-glass conductance, including inside and outside air films,
6731 : // (2) solar heat gain coefficient (SHGC),
6732 : // (3) solar transmittance at normal incidence, and (4) visible transmittance at normal incidence.
6733 :
6734 5 : if (construct.WindowTypeEQL) {
6735 : // for equivalent layer Window already calculated
6736 : // NominalU(ThisNum)=NominalConductanceWinter
6737 : // Save the SHGC for later use in tabular report IVRS
6738 : // Construct(ThisNum)%SummerSHGC = SHGCSummer
6739 0 : construct.VisTransNorm = 0.0; // TODO list
6740 :
6741 : static constexpr std::string_view Format_799(" Construction:WindowEquivalentLayer,{},{},{},{:.3R},{:.3R},{:.3R}\n");
6742 0 : print(state.files.eio,
6743 : Format_799,
6744 0 : construct.Name,
6745 : ThisNum,
6746 0 : construct.TotSolidLayers,
6747 0 : state.dataHeatBal->NominalU(ThisNum),
6748 0 : construct.SummerSHGC,
6749 0 : construct.SolTransNorm);
6750 :
6751 : } else {
6752 :
6753 5 : CalcNominalWindowCond(state, ThisNum, 1, NominalConductanceWinter, SHGCWinter, TransSolNorm, TransVisNorm, errFlag);
6754 :
6755 5 : if (errFlag == 1) {
6756 0 : ShowWarningError(state, format("Window construction {} has an interior or exterior blind", construct.Name));
6757 0 : ShowContinueError(state, "but the corresponding construction without the blind cannot be found.");
6758 0 : ShowContinueError(state, "The ReportGlass entry for this construction will not be printed in eplusout.eio.");
6759 0 : continue;
6760 : }
6761 :
6762 : // Skip constructions with between-glass shade/blind until method is worked out to determine
6763 : // nominal conductance and SHGC.
6764 :
6765 5 : if (errFlag == 2) {
6766 0 : ShowWarningError(state, format("Window construction {} has a between-glass shade or blind", construct.Name));
6767 0 : ShowContinueError(state, "The ReportGlass entry for this construction will not be printed in eplusout.eio.");
6768 0 : continue;
6769 : }
6770 :
6771 5 : state.dataHeatBal->NominalU(ThisNum) = NominalConductanceWinter;
6772 5 : if (!construct.WindowTypeEQL) {
6773 5 : CalcNominalWindowCond(state, ThisNum, 2, NominalConductanceSummer, SHGCSummer, TransSolNorm, TransVisNorm, errFlag);
6774 : }
6775 : // Save the SHGC for later use in tabular report IVRS
6776 5 : construct.SummerSHGC = SHGCSummer;
6777 5 : construct.VisTransNorm = TransVisNorm;
6778 5 : construct.SolTransNorm = TransSolNorm;
6779 :
6780 : static constexpr std::string_view Format_700(" WindowConstruction,{},{},{},{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
6781 10 : print(state.files.eio,
6782 : Format_700,
6783 5 : construct.Name,
6784 : ThisNum,
6785 5 : construct.TotLayers,
6786 5 : Material::surfaceRoughnessNames[(int)construct.OutsideRoughness],
6787 : NominalConductanceWinter,
6788 5 : state.dataHeatBal->NominalUBeforeAdjusted(ThisNum),
6789 5 : state.dataHeatBal->CoeffAdjRatio(ThisNum),
6790 : SHGCSummer,
6791 : TransSolNorm,
6792 : TransVisNorm);
6793 : }
6794 : // Write(OutputFileConstrainParams, 705) TRIM(Construct(ThisNum)%Name), SHGCSummer ,TransVisNorm
6795 :
6796 11 : for (int i = 1; i <= construct.TotLayers; ++i) {
6797 6 : int Layer = construct.LayerPoint(i);
6798 6 : auto const *mat = s_mat->materials(Layer);
6799 6 : std::string SpectralDataName;
6800 :
6801 6 : switch (mat->group) {
6802 :
6803 0 : case Material::Group::Gas: {
6804 0 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
6805 0 : assert(matGas != nullptr);
6806 : static constexpr std::string_view Format_702(" WindowMaterial:Gas,{},{},{:.3R}\n");
6807 0 : print(state.files.eio, Format_702, matGas->Name, Material::gasTypeNames[(int)matGas->gases[0].type], matGas->Thickness);
6808 : //! fw CASE(WindowGasMixture)
6809 0 : } break;
6810 :
6811 0 : case Material::Group::Shade: {
6812 0 : auto const *matShade = dynamic_cast<Material::MaterialShade const *>(mat);
6813 0 : assert(matShade != nullptr);
6814 :
6815 : static constexpr std::string_view Format_703(" WindowMaterial:Shade,{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
6816 0 : print(state.files.eio,
6817 : Format_703,
6818 0 : matShade->Name,
6819 0 : matShade->Thickness,
6820 0 : matShade->Conductivity,
6821 0 : matShade->AbsorpThermal,
6822 0 : matShade->Trans,
6823 0 : matShade->TransVis,
6824 0 : matShade->ReflectShade);
6825 0 : } break;
6826 :
6827 1 : case Material::Group::Blind: {
6828 1 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(mat);
6829 :
6830 : static constexpr std::string_view Format_704(
6831 : " WindowMaterial:Blind,{},{:.4R},{:.4R},{:.4R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
6832 1 : print(state.files.eio,
6833 : Format_704,
6834 1 : matBlind->Name,
6835 1 : matBlind->SlatWidth,
6836 1 : matBlind->SlatSeparation,
6837 1 : matBlind->SlatThickness,
6838 1 : matBlind->SlatAngle,
6839 1 : matBlind->slatTAR.Sol.Ft.Bm[0].DfTra,
6840 1 : matBlind->slatTAR.Sol.Ft.Bm[0].DfRef,
6841 1 : matBlind->toGlassDist);
6842 1 : } break;
6843 :
6844 0 : case Material::Group::Screen: {
6845 0 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(mat);
6846 0 : assert(matScreen != nullptr);
6847 0 : auto const &btar = matScreen->btars[0][0]; // AR: Going with normal incidence here
6848 :
6849 : static constexpr std::string_view Format_706 =
6850 : " WindowMaterial:Screen,{},{:.5R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n";
6851 :
6852 : // AR: assuming normal incidence
6853 0 : print(state.files.eio,
6854 : Format_706,
6855 0 : matScreen->Name,
6856 0 : matScreen->Thickness,
6857 0 : matScreen->Conductivity,
6858 0 : matScreen->AbsorpThermal,
6859 0 : btar.BmTrans,
6860 0 : btar.RefSolFront,
6861 0 : btar.RefVisFront,
6862 0 : matScreen->DfRef,
6863 0 : matScreen->DfRefVis,
6864 0 : matScreen->diameterToSpacingRatio,
6865 0 : matScreen->toGlassDist);
6866 0 : } break;
6867 :
6868 5 : case Material::Group::Glass:
6869 : case Material::Group::GlassSimple: {
6870 5 : auto const *matGlass = dynamic_cast<Material::MaterialGlass const *>(mat);
6871 5 : assert(matGlass != nullptr);
6872 5 : std::string SolarDiffusing = "No";
6873 5 : if (matGlass->SolarDiffusing) SolarDiffusing = "Yes";
6874 :
6875 5 : if (matGlass->windowOpticalData == Window::OpticalDataModel::Spectral) {
6876 0 : SpectralDataName = s_mat->SpectralData(matGlass->GlassSpectralDataPtr).Name;
6877 5 : } else if (matGlass->windowOpticalData == Window::OpticalDataModel::SpectralAndAngle) {
6878 0 : SpectralDataName = format("{}, {}, {}",
6879 0 : matGlass->GlassSpecAngTransCurve->Name,
6880 0 : matGlass->GlassSpecAngFReflCurve->Name,
6881 0 : matGlass->GlassSpecAngBReflCurve->Name);
6882 : } else {
6883 5 : SpectralDataName = "";
6884 : }
6885 :
6886 : static constexpr std::string_view Format_707(
6887 : " WindowMaterial:Glazing,{},{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{"
6888 : ":.5R},{:.5R},{:.5R},{:.5R},{:.5R},{}\n");
6889 5 : print(state.files.eio,
6890 : Format_707,
6891 5 : matGlass->Name,
6892 5 : Window::opticalDataModelNames[(int)matGlass->windowOpticalData],
6893 : SpectralDataName,
6894 5 : matGlass->Thickness,
6895 5 : matGlass->Trans,
6896 5 : matGlass->ReflectSolBeamFront,
6897 5 : matGlass->ReflectSolBeamBack,
6898 5 : matGlass->TransVis,
6899 5 : matGlass->ReflectVisBeamFront,
6900 5 : matGlass->ReflectVisBeamBack,
6901 5 : matGlass->TransThermal,
6902 5 : matGlass->AbsorpThermalFront,
6903 5 : matGlass->AbsorpThermalBack,
6904 5 : matGlass->Conductivity,
6905 5 : matGlass->GlassTransDirtFactor,
6906 : SolarDiffusing);
6907 5 : } break;
6908 :
6909 0 : case Material::Group::GlassEQL: {
6910 0 : auto const *matEQL = dynamic_cast<Material::MaterialGlassEQL const *>(mat);
6911 0 : assert(matEQL != nullptr);
6912 0 : std::string OpticalDataType = "SpectralAverage";
6913 0 : SpectralDataName = "";
6914 : static constexpr std::string_view Format_708(
6915 : " WindowMaterial:Glazing:EquivalentLayer,{},{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}"
6916 : ",{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}\n");
6917 0 : print(state.files.eio,
6918 : Format_708,
6919 0 : matEQL->Name,
6920 : OpticalDataType,
6921 : SpectralDataName,
6922 0 : matEQL->TAR.Sol.Ft.Bm[0].BmTra,
6923 0 : matEQL->TAR.Sol.Bk.Bm[0].BmTra,
6924 0 : matEQL->TAR.Sol.Ft.Bm[0].BmRef,
6925 0 : matEQL->TAR.Sol.Bk.Bm[0].BmRef,
6926 0 : matEQL->TAR.Sol.Ft.Bm[0].DfTra,
6927 0 : matEQL->TAR.Sol.Bk.Bm[0].DfTra,
6928 0 : matEQL->TAR.Sol.Ft.Bm[0].DfRef,
6929 0 : matEQL->TAR.Sol.Bk.Bm[0].DfRef,
6930 0 : matEQL->TAR.Sol.Ft.Df.Tra,
6931 0 : matEQL->TAR.Sol.Ft.Df.Ref,
6932 0 : matEQL->TAR.Sol.Bk.Df.Ref,
6933 0 : matEQL->TAR.IR.Ft.Tra,
6934 0 : matEQL->TAR.IR.Ft.Emi,
6935 0 : matEQL->TAR.IR.Bk.Emi);
6936 0 : } break;
6937 :
6938 0 : case Material::Group::ShadeEQL: {
6939 0 : auto const *matEQL = dynamic_cast<Material::MaterialShadeEQL const *>(mat);
6940 0 : assert(matEQL != nullptr);
6941 : static constexpr std::string_view Format_709(
6942 : " WindowMaterial:Shade:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R}\n");
6943 0 : print(state.files.eio,
6944 : Format_709,
6945 0 : matEQL->Name,
6946 0 : matEQL->TAR.Sol.Ft.Bm[0].BmTra,
6947 0 : matEQL->TAR.Sol.Bk.Bm[0].BmTra,
6948 0 : matEQL->TAR.Sol.Ft.Bm[0].DfTra,
6949 0 : matEQL->TAR.Sol.Bk.Bm[0].DfTra,
6950 0 : matEQL->TAR.Sol.Ft.Bm[0].DfRef,
6951 0 : matEQL->TAR.Sol.Bk.Bm[0].DfRef,
6952 0 : matEQL->TAR.IR.Ft.Tra,
6953 0 : matEQL->TAR.IR.Ft.Emi,
6954 0 : matEQL->TAR.IR.Bk.Emi);
6955 0 : } break;
6956 :
6957 0 : case Material::Group::DrapeEQL: {
6958 0 : auto const *matEQL = dynamic_cast<Material::MaterialDrapeEQL const *>(mat);
6959 0 : assert(matEQL != nullptr);
6960 : static constexpr std::string_view Format_710(
6961 : " WindowMaterial:Drape:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},"
6962 : "{:.4R},{:.4R},{:.5R},{:.5R}\n");
6963 0 : print(state.files.eio,
6964 : Format_710,
6965 0 : matEQL->Name,
6966 0 : matEQL->TAR.Sol.Ft.Bm[0].BmTra,
6967 0 : matEQL->TAR.Sol.Ft.Bm[0].DfTra,
6968 0 : matEQL->TAR.Sol.Bk.Bm[0].DfTra,
6969 0 : matEQL->TAR.Sol.Ft.Bm[0].DfRef,
6970 0 : matEQL->TAR.Sol.Bk.Bm[0].DfRef,
6971 0 : matEQL->TAR.IR.Ft.Tra,
6972 0 : matEQL->TAR.IR.Ft.Emi,
6973 0 : matEQL->TAR.IR.Bk.Emi,
6974 0 : matEQL->pleatedWidth,
6975 0 : matEQL->pleatedLength);
6976 0 : } break;
6977 :
6978 0 : case Material::Group::ScreenEQL: {
6979 0 : auto const *matEQL = dynamic_cast<Material::MaterialScreenEQL const *>(mat);
6980 0 : assert(matEQL != nullptr);
6981 : static constexpr std::string_view Format_711(
6982 : " WindowMaterial:Screen:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R}"
6983 : ",{:.4R},{:.4R},{:.5R},{:.5R}\n");
6984 0 : print(state.files.eio,
6985 : Format_711,
6986 0 : matEQL->Name,
6987 0 : matEQL->TAR.Sol.Ft.Bm[0].BmTra,
6988 0 : matEQL->TAR.Sol.Ft.Bm[0].DfTra,
6989 0 : matEQL->TAR.Sol.Bk.Bm[0].DfTra,
6990 0 : matEQL->TAR.Sol.Ft.Bm[0].DfRef,
6991 0 : matEQL->TAR.Sol.Bk.Bm[0].DfRef,
6992 0 : matEQL->TAR.IR.Ft.Tra,
6993 0 : matEQL->TAR.IR.Ft.Emi,
6994 0 : matEQL->TAR.IR.Bk.Emi,
6995 0 : matEQL->wireSpacing,
6996 0 : matEQL->wireDiameter);
6997 0 : } break;
6998 :
6999 0 : case Material::Group::BlindEQL: {
7000 0 : auto const *matEQL = dynamic_cast<Material::MaterialBlindEQL const *>(mat);
7001 0 : assert(matEQL != nullptr);
7002 :
7003 : // Formats
7004 : static constexpr std::string_view Format_712(
7005 : " WindowMaterial:Blind:EquivalentLayer,{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:."
7006 : "5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}");
7007 0 : print(state.files.eio,
7008 : Format_712,
7009 0 : matEQL->Name,
7010 0 : DataWindowEquivalentLayer::orientationNames[(int)matEQL->SlatOrientation],
7011 0 : matEQL->SlatWidth,
7012 0 : matEQL->SlatSeparation,
7013 0 : matEQL->SlatCrown,
7014 0 : matEQL->SlatAngle,
7015 0 : matEQL->TAR.Sol.Ft.Bm[0].DfTra,
7016 0 : matEQL->TAR.Sol.Bk.Bm[0].DfTra,
7017 0 : matEQL->TAR.Sol.Ft.Bm[0].DfRef,
7018 0 : matEQL->TAR.Sol.Bk.Bm[0].DfRef,
7019 0 : matEQL->TAR.Sol.Ft.Df.Tra,
7020 0 : matEQL->TAR.Sol.Ft.Df.Ref,
7021 0 : matEQL->TAR.Sol.Bk.Df.Ref,
7022 0 : matEQL->TAR.IR.Ft.Tra,
7023 0 : matEQL->TAR.IR.Ft.Emi,
7024 0 : matEQL->TAR.IR.Bk.Emi);
7025 0 : } break;
7026 :
7027 0 : case Material::Group::WindowGapEQL: {
7028 0 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
7029 0 : assert(matGas != nullptr);
7030 : static constexpr std::string_view Format_713(" WindowMaterial:Gap:EquivalentLayer,{},{},{:.3R},{}\n");
7031 0 : print(state.files.eio,
7032 : Format_713,
7033 0 : matGas->Name,
7034 0 : Material::gasTypeNames[(int)matGas->gases[0].type],
7035 0 : matGas->Thickness,
7036 0 : Material::gapVentTypeNames[(int)matGas->gapVentType]);
7037 0 : } break;
7038 :
7039 0 : default:
7040 0 : break;
7041 : }
7042 6 : } // for (i)
7043 : } // if (construct.TypeIsWindow)
7044 : } // for (ThisNum)
7045 :
7046 109 : } else if (wm->HasWindows) {
7047 :
7048 143 : for (int ThisNum = 1; ThisNum <= state.dataHeatBal->TotConstructs; ++ThisNum) {
7049 116 : auto &construct = state.dataConstruction->Construct(ThisNum);
7050 116 : if (!construct.TypeIsWindow) continue;
7051 37 : if (construct.WindowTypeEQL) continue; // skip if equivalent layer window
7052 :
7053 : // Calculate for ASHRAE winter and summer conditions: (1)nominal center-of-glass conductance,
7054 : // (2) solar heat gain coefficient (SHGC), including inside and outside air films,
7055 : // (3) solar transmittance at normal incidence, and (4) visible transmittance at normal incidence.
7056 :
7057 31 : CalcNominalWindowCond(state, ThisNum, 1, NominalConductanceWinter, SHGCWinter, TransSolNorm, TransVisNorm, errFlag);
7058 31 : if (errFlag == 1 || errFlag == 2) continue;
7059 31 : state.dataHeatBal->NominalU(ThisNum) = NominalConductanceWinter;
7060 : // Need to have this because of window assembly reports (Simon)
7061 31 : construct.SummerSHGC = SHGCSummer;
7062 31 : construct.VisTransNorm = TransVisNorm;
7063 : }
7064 : }
7065 110 : } // ReportGlass()
7066 :
7067 : //*************************************************************************************
7068 :
7069 2 : void CalcWindowBlindProperties(EnergyPlusData &state)
7070 : {
7071 :
7072 : // SUBROUTINE INFORMATION:
7073 : // AUTHOR Hans Simmler
7074 : // DATE WRITTEN July-Aug 1995
7075 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
7076 : // Dec 2001 (FCW): add variable slat angle
7077 :
7078 : // PURPOSE OF THIS SUBROUTINE:
7079 : // Calculates solar-optical properties of a window blind
7080 : // from slat properties and solar profile angle. Assumes flat slats.
7081 :
7082 : // METHODOLOGY EMPLOYED:
7083 : // The solar profile angle is varied from -90 to +90 deg and slat angle is varied from 0 to 180deg,
7084 : // covering the full range of possible profile angles and slat angles.
7085 : // (The profile angle is defined as the angle of incidence when the radiation
7086 : // source is located in a plane that (1)is perpendicular to the plane of the blinds [which is
7087 : // the same as the window plane] and (2) contains the slat normal vector.)
7088 :
7089 : // In the time-step calculation,the blind properties vs. profile angle and slat angle
7090 : // that are calculated here will be applicable to windows and slats
7091 : // of arbitrary orientation, and to arbitrary sun positions, as long as the appropriate
7092 : // profile angle is used. The slat angle for a particular window with blinds is determined
7093 : // each time step in subroutine WindowShadingManager on the basis of user-specified
7094 : // slat control options.
7095 :
7096 : // REFERENCES:
7097 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
7098 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
7099 :
7100 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7101 :
7102 2 : Array1D<Real64> bld_pr(15); // Slat properties
7103 2 : Array1D<Real64> st_lay(16); // Solar-optical blind/glazing system properties
7104 : Real64 sun_el; // Solar profile angle (radians)
7105 2 : Array1D<Real64> sun_el_deg(Material::MaxProfAngs); // Solar profile angle (deg) corresponding to sun_el values
7106 : Real64 bld_el; // Slat angle (elevation of slat normal vector in plane
7107 : // perpendicular to window and containing the slat normal vector) (radians)
7108 :
7109 2 : auto &s_mat = state.dataMaterial;
7110 :
7111 46 : for (auto *mat : s_mat->materials) {
7112 44 : if (mat->group != Material::Group::Blind) continue;
7113 :
7114 2 : auto *matBlind = dynamic_cast<Material::MaterialBlind *>(mat);
7115 2 : assert(matBlind != nullptr);
7116 :
7117 2 : bld_pr(2) = matBlind->SlatWidth;
7118 2 : bld_pr(3) = matBlind->SlatSeparation;
7119 :
7120 6 : for (int ISolVis = 1; ISolVis <= 2; ++ISolVis) {
7121 4 : if (ISolVis == 1) { // For solar calculation
7122 2 : bld_pr(4) = 0.0;
7123 2 : bld_pr(5) = 0.0;
7124 2 : bld_pr(6) = 0.0;
7125 2 : bld_pr(7) = matBlind->slatTAR.Sol.Ft.Bm[0].DfTra;
7126 2 : bld_pr(8) = matBlind->slatTAR.Sol.Ft.Bm[0].DfRef;
7127 2 : bld_pr(9) = matBlind->slatTAR.Sol.Bk.Bm[0].DfRef;
7128 2 : bld_pr(10) = matBlind->slatTAR.Sol.Ft.Df.Tra;
7129 2 : bld_pr(11) = matBlind->slatTAR.Sol.Ft.Df.Ref;
7130 2 : bld_pr(12) = matBlind->slatTAR.Sol.Bk.Df.Ref;
7131 : } else { // For visible calculation
7132 2 : bld_pr(4) = 0.0;
7133 2 : bld_pr(5) = 0.0;
7134 2 : bld_pr(6) = 0.0;
7135 2 : bld_pr(7) = matBlind->slatTAR.Vis.Ft.Bm[0].DfTra;
7136 2 : bld_pr(8) = matBlind->slatTAR.Vis.Ft.Bm[0].DfRef;
7137 2 : bld_pr(9) = matBlind->slatTAR.Vis.Bk.Bm[0].DfRef;
7138 2 : bld_pr(10) = matBlind->slatTAR.Vis.Ft.Df.Tra;
7139 2 : bld_pr(11) = matBlind->slatTAR.Vis.Ft.Df.Ref;
7140 2 : bld_pr(12) = matBlind->slatTAR.Vis.Bk.Df.Ref;
7141 : }
7142 : // For IR calculation
7143 4 : bld_pr(13) = matBlind->slatTAR.IR.Ft.Tra;
7144 4 : bld_pr(14) = matBlind->slatTAR.IR.Ft.Emi;
7145 4 : bld_pr(15) = matBlind->slatTAR.IR.Bk.Emi;
7146 :
7147 : // Calculate diffuse properties of blind. If blind has variable slat angle, &
7148 : // vary slat angle from 0 to 180 deg in 10-deg steps (for Material::MaxSlatAngs = 19).
7149 : // If blind has fixed slat angle, calculate properties at that angle only.
7150 :
7151 728 : for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
7152 :
7153 724 : auto &btar = matBlind->TARs[iSlatAng];
7154 :
7155 724 : st_lay = 0.0;
7156 724 : bld_el = Material::dSlatAng * iSlatAng; // 0 <= bld_el <= 180 deg
7157 :
7158 724 : BlindOpticsDiffuse(state, matBlind->Num, ISolVis, bld_pr, bld_el, st_lay);
7159 :
7160 724 : if (ISolVis == 1) { // Fill blind diffuse solar and IR properties
7161 362 : btar.Sol.Ft.Df.Tra = st_lay(9);
7162 362 : btar.Sol.Ft.Df.Ref = st_lay(10);
7163 362 : btar.Sol.Bk.Df.Tra = st_lay(11);
7164 362 : btar.Sol.Bk.Df.Ref = st_lay(12);
7165 362 : btar.Sol.Ft.Df.Abs = max(0.0, 1.0 - st_lay(9) - st_lay(10));
7166 362 : btar.Sol.Bk.Df.Abs = max(0.0, 1.0 - st_lay(11) - st_lay(12));
7167 362 : btar.IR.Ft.Tra = st_lay(13);
7168 362 : btar.IR.Ft.Emi = st_lay(14);
7169 362 : btar.IR.Bk.Tra = st_lay(13);
7170 362 : btar.IR.Bk.Emi = st_lay(15);
7171 : } else { // Fill blind diffuse visible properties
7172 362 : btar.Vis.Ft.Df.Tra = st_lay(9);
7173 362 : btar.Vis.Ft.Df.Ref = st_lay(10);
7174 362 : btar.Vis.Bk.Df.Tra = st_lay(11);
7175 362 : btar.Vis.Bk.Df.Ref = st_lay(12);
7176 : }
7177 :
7178 : // If blind has variable slat angle, vary slat angle from 0 to 180 deg in 10-deg steps
7179 : // (for Material::MaxSlatAngs = 19). If blind has fixed slat angle, calculate properties at that angle only.
7180 :
7181 27512 : for (int IProfAng = 1; IProfAng <= Material::MaxProfAngs; ++IProfAng) {
7182 26788 : sun_el = -Constant::Pi / 2.0 + (Constant::Pi / 36.0) * (IProfAng - 1);
7183 26788 : sun_el_deg(IProfAng) = 57.2958 * sun_el;
7184 :
7185 : // Beam solar-optical properties of blind for given profile angle and slat angle
7186 :
7187 26788 : BlindOpticsBeam(state, matBlind->Num, bld_pr, bld_el, sun_el, st_lay);
7188 :
7189 26788 : if (ISolVis == 1) { // Fill blind beam solar properties
7190 13394 : btar.Sol.Ft.Bm[IProfAng].BmTra = st_lay(1);
7191 13394 : btar.Sol.Ft.Bm[IProfAng].BmRef = st_lay(2);
7192 13394 : btar.Sol.Bk.Bm[IProfAng].BmTra = st_lay(3);
7193 13394 : btar.Sol.Bk.Bm[IProfAng].BmRef = st_lay(4);
7194 13394 : btar.Sol.Ft.Bm[IProfAng].DfTra = st_lay(5);
7195 13394 : btar.Sol.Ft.Bm[IProfAng].DfRef = st_lay(6);
7196 13394 : btar.Sol.Bk.Bm[IProfAng].DfTra = st_lay(7);
7197 13394 : btar.Sol.Bk.Bm[IProfAng].DfRef = st_lay(8);
7198 13394 : btar.Sol.Ft.Bm[IProfAng].Abs = max(0.0, 1.0 - st_lay(6) - st_lay(1) - st_lay(5));
7199 13394 : btar.Sol.Bk.Bm[IProfAng].Abs = max(0.0, 1.0 - st_lay(7) - st_lay(3) - st_lay(8));
7200 :
7201 : } else { // Fill blind beam visible properties
7202 13394 : btar.Vis.Ft.Bm[IProfAng].BmTra = st_lay(1);
7203 13394 : btar.Vis.Ft.Bm[IProfAng].BmRef = st_lay(2);
7204 13394 : btar.Vis.Bk.Bm[IProfAng].BmTra = st_lay(3);
7205 13394 : btar.Vis.Bk.Bm[IProfAng].BmRef = st_lay(4);
7206 13394 : btar.Vis.Ft.Bm[IProfAng].DfTra = st_lay(5);
7207 13394 : btar.Vis.Ft.Bm[IProfAng].DfRef = st_lay(6);
7208 13394 : btar.Vis.Bk.Bm[IProfAng].DfTra = st_lay(7);
7209 13394 : btar.Vis.Bk.Bm[IProfAng].DfRef = st_lay(8);
7210 : }
7211 : } // End of loop over slat angles
7212 : } // End of loop over profile angles
7213 :
7214 4 : if (ISolVis == 1) {
7215 :
7216 364 : for (int iSlatAng = 0; iSlatAng < Material::MaxSlatAngs; ++iSlatAng) {
7217 362 : auto &btar = matBlind->TARs[iSlatAng];
7218 :
7219 362 : Real64 sumDenom = 0.0, sumTra1 = 0.0, sumTra2 = 0.0, sumRef = 0.0, sumAbs = 0.0;
7220 :
7221 : // Integrate from -90 to 0 deg
7222 6878 : for (int IPhi = 1; IPhi <= 18; ++IPhi) {
7223 6516 : auto const &btargs = btar.Sol.Ft.Bm[IPhi];
7224 6516 : auto const &btargs1 = btar.Sol.Ft.Bm[IPhi + 1];
7225 :
7226 6516 : Real64 denom = Material::dProfAng * std::cos(-Constant::PiOvr2 + (IPhi - 0.5) * Material::dProfAng);
7227 6516 : sumDenom += denom;
7228 : // Why adding beam transmittance here?
7229 6516 : sumTra1 += denom * (btargs.BmTra + btargs1.BmTra) * 0.5;
7230 6516 : sumTra2 += denom * (btargs.DfTra + btargs1.DfTra) * 0.5;
7231 6516 : sumRef += denom * (btargs.DfRef + btargs1.DfRef) * 0.5;
7232 6516 : sumAbs += denom * (btargs.Abs + btargs1.Abs) * 0.5;
7233 : }
7234 :
7235 362 : btar.Sol.Ft.Df.TraGnd = std::max(0.0, sumTra1 / sumDenom) + std::max(0.0, sumTra2 / sumDenom);
7236 362 : btar.Sol.Ft.Df.RefGnd = std::max(0.0, sumRef / sumDenom);
7237 362 : btar.Sol.Ft.Df.AbsGnd = std::max(0.0, sumAbs / sumDenom);
7238 :
7239 362 : sumDenom = sumTra1 = sumTra2 = sumRef = sumAbs = 0.0;
7240 :
7241 : // Integrate from -90 to 0 deg
7242 6878 : for (int IPhi = 19; IPhi <= Material::MaxProfAngs - 1; ++IPhi) {
7243 6516 : auto const &btargs = btar.Sol.Ft.Bm[IPhi];
7244 6516 : auto const &btargs1 = btar.Sol.Ft.Bm[IPhi + 1];
7245 :
7246 6516 : Real64 denom = Material::dProfAng * std::cos(-Constant::PiOvr2 + (IPhi - 0.5) * Material::dProfAng);
7247 6516 : sumDenom += denom;
7248 : // Why adding beam transmittance here?
7249 6516 : sumTra1 += denom * (btargs.BmTra + btargs1.BmTra) * 0.5;
7250 6516 : sumTra2 += denom * (btargs.DfTra + btargs1.DfTra) * 0.5;
7251 6516 : sumRef += denom * (btargs.DfRef + btargs1.DfRef) * 0.5;
7252 6516 : sumAbs += denom * (btargs.Abs + btargs1.Abs) * 0.5;
7253 : }
7254 :
7255 362 : btar.Sol.Ft.Df.TraSky = std::max(0.0, sumTra1 / sumDenom) + std::max(0.0, sumTra2 / sumDenom);
7256 362 : btar.Sol.Ft.Df.RefSky = std::max(0.0, sumRef / sumDenom);
7257 362 : btar.Sol.Ft.Df.AbsSky = std::max(0.0, sumAbs / sumDenom);
7258 : } // for (iSlatAng)
7259 : }
7260 :
7261 : } // End of loop over solar vs. visible properties
7262 :
7263 : } // End of loop over blinds
7264 2 : } // CalcWindowBlindProperties()
7265 :
7266 : //*************************************************************************************
7267 :
7268 0 : void CalcWindowScreenProperties(EnergyPlusData &state)
7269 : {
7270 :
7271 : // SUBROUTINE INFORMATION:
7272 : // AUTHOR Richard Raustad
7273 : // DATE WRITTEN April 2006
7274 :
7275 : // PURPOSE OF THIS SUBROUTINE:
7276 : // Initialize static properties of window screens.
7277 :
7278 : // METHODOLOGY EMPLOYED:
7279 : // Loop through all surfaces to determine which window has an exterior screen. Static
7280 : // variables are defined here, dynamic variables are calculated in CalcScreenTransmittance.
7281 :
7282 : // Locals
7283 : // SUBROUTINE PARAMETER DEFINITIONS:
7284 0 : int constexpr M = 18;
7285 0 : int constexpr N = 18;
7286 :
7287 : int ConstrNumSh; // Index to shaded construction
7288 : int MatNum; // Index to material number
7289 : Real64 SumTrans; // Integration variable for transmittance
7290 : Real64 SumTransVis; // Integration variable for visible transmittance
7291 : Real64 SumReflect; // Integration variable for reflectance
7292 : Real64 SumReflectVis; // Integration variable for visible reflectance
7293 : Real64 SumArea; // Integration variable for area of quarter hemisphere
7294 : // is used on multiple surfaces
7295 :
7296 : // Pre-calculate these constants
7297 0 : std::vector<Real64> sunAzimuth;
7298 0 : std::vector<Real64> sin_sunAzimuth;
7299 0 : std::vector<Real64> cos_sunAzimuth;
7300 0 : std::vector<Real64> sunAltitude;
7301 0 : std::vector<Real64> sin_sunAltitude;
7302 0 : std::vector<Real64> cos_sunAltitude;
7303 0 : std::vector<Real64> skyArea; // Area of integration
7304 0 : Array2D<Real64> relativeAzimuth; // Relative azimuth angle of sun with respect to surface outward normal
7305 0 : Array2D<Real64> relativeAltitude; // Relative altitude angle of sun with respect to surface outward normal
7306 :
7307 0 : auto &s_mat = state.dataMaterial;
7308 0 : auto &s_surf = state.dataSurface;
7309 :
7310 0 : relativeAzimuth.allocate(N, M);
7311 0 : relativeAltitude.allocate(N, M);
7312 :
7313 0 : for (int j = 0; j <= N - 1; ++j) {
7314 0 : Real64 currAzimuth = (90.0 / N) * j * Constant::DegToRad;
7315 0 : sunAzimuth.push_back(currAzimuth); // Azimuth angle of sun during integration
7316 0 : sin_sunAzimuth.push_back(std::sin(currAzimuth));
7317 0 : cos_sunAzimuth.push_back(std::cos(currAzimuth));
7318 : }
7319 :
7320 0 : for (int i = 0; i <= M - 1; ++i) {
7321 0 : Real64 currAltitude = (90.0 / M) * i * Constant::DegToRad;
7322 0 : sunAltitude.push_back(currAltitude); // Altitude angle of sun during integration
7323 0 : sin_sunAltitude.push_back(std::sin(currAltitude));
7324 0 : cos_sunAltitude.push_back(std::cos(currAltitude));
7325 0 : skyArea.push_back(sin_sunAltitude[i] * cos_sunAltitude[i]);
7326 : }
7327 :
7328 0 : for (int j = 1; j <= N; ++j) {
7329 0 : for (int i = 1; i <= M; ++i) {
7330 : // Integrate transmittance using coordinate transform
7331 0 : relativeAzimuth(i, j) = std::asin(sin_sunAltitude[i - 1] * cos_sunAzimuth[j - 1]); // phi prime
7332 0 : relativeAltitude(i, j) = std::atan(std::tan(sunAltitude[i - 1]) * sin_sunAzimuth[j - 1]); // alpha
7333 : }
7334 : }
7335 :
7336 0 : bool PrintTransMap = false; // Flag used to print transmittance map
7337 :
7338 0 : for (int SurfNum = 1; SurfNum <= s_surf->TotSurfaces; ++SurfNum) {
7339 0 : auto const &surf = s_surf->Surface(SurfNum);
7340 :
7341 0 : if (!surf.HasShadeControl) continue;
7342 :
7343 0 : if (s_surf->WindowShadingControl(surf.activeWindowShadingControl).ShadingType != WinShadingType::ExtScreen) continue;
7344 :
7345 0 : ConstrNumSh = surf.activeShadedConstruction;
7346 0 : MatNum = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1);
7347 0 : auto *matScreen = dynamic_cast<Material::MaterialScreen *>(s_mat->materials(MatNum));
7348 0 : assert(matScreen != nullptr);
7349 0 : s_surf->SurfaceWindow(SurfNum).screenNum = MatNum;
7350 :
7351 0 : if (matScreen->isUsed) continue; // Has already been initialized
7352 :
7353 0 : matScreen->isUsed = true;
7354 0 : if (matScreen->mapDegResolution > 0) PrintTransMap = true;
7355 :
7356 : // If a screen material is used more than once, the Material structure's screen data pointer holds the screen number
7357 : // of the last window surface. Use this method to access the screen parameter's only for static variables such as
7358 : // diffuse properties (InitGlassOpticalCalculations). For all cases where the screen properties are a function of
7359 : // sun azimuth and altitude angles, use the Screens structure.
7360 : // Invert calculation done in GetMaterialInput to find Diameter to Spacing ratio (Props(7)/Props(6))
7361 : // dataMaterial.Material(MaterNum)%Trans = (1 - MaterialProps(7)/MaterialProps(6))**2.0
7362 0 : matScreen->diameterToSpacingRatio = 1.0 - std::sqrt(matScreen->Trans);
7363 :
7364 : // Reflectance of screen material only
7365 0 : matScreen->CylinderRef = matScreen->ShadeRef / (1 - matScreen->Trans);
7366 0 : matScreen->CylinderRefVis = matScreen->ShadeRefVis / (1 - matScreen->Trans);
7367 :
7368 : // Integrate the transmittance over a quarter hemisphere for use in diffuse calculations
7369 0 : SumTrans = 0.0;
7370 0 : SumTransVis = 0.0;
7371 0 : SumReflect = 0.0;
7372 0 : SumReflectVis = 0.0;
7373 0 : SumArea = 0.0;
7374 : // Integration over quarter hemisphere in polar coordinates and converting to rectangular to call screen model.
7375 : // Proceed in reverse order such that the last calculation yields zero sun angle to window screen normal (angles=0,0).
7376 : // The properties calculated at zero sun angle are then used elsewhere prior to the start of the actual simulation.
7377 :
7378 0 : Material::ScreenBmTransAbsRef btar;
7379 :
7380 0 : for (int j = N; j >= 1; --j) {
7381 0 : for (int i = M; i >= 1; --i) {
7382 : // Integrate transmittance using coordinate transform
7383 : // TODO: switch to interpolation?
7384 0 : CalcScreenTransmittance(state, matScreen, relativeAltitude(i, j), relativeAzimuth(i, j), btar);
7385 0 : SumTrans += (btar.BmTrans + btar.DfTrans) * skyArea[i - 1];
7386 0 : SumTransVis += (btar.BmTransVis + btar.DfTransVis) * skyArea[i - 1];
7387 0 : SumReflect += btar.RefSolFront * skyArea[i - 1];
7388 0 : SumReflectVis += btar.RefVisFront * skyArea[i - 1];
7389 0 : SumArea += skyArea[i - 1];
7390 : }
7391 : }
7392 :
7393 : // Reflectance of overall screen including openings and scattered transmittance
7394 0 : matScreen->ShadeRef = matScreen->CylinderRef * (1.0 - (btar.BmTrans + btar.DfTrans));
7395 0 : matScreen->ShadeRefVis = matScreen->CylinderRefVis * (1.0 - (btar.BmTransVis + btar.DfTransVis));
7396 :
7397 0 : if (SumArea != 0) {
7398 0 : matScreen->DfTrans = SumTrans / SumArea;
7399 0 : matScreen->DfTransVis = SumTransVis / SumArea;
7400 0 : matScreen->DfRef = SumReflect / SumArea;
7401 0 : matScreen->DfRefVis = SumReflectVis / SumArea;
7402 : }
7403 0 : matScreen->DfAbs = max(0.0, (1.0 - matScreen->DfTrans - matScreen->DfRef));
7404 :
7405 0 : matScreen->AbsorpThermalBack = matScreen->DfAbs;
7406 0 : matScreen->AbsorpThermalFront = matScreen->DfAbs;
7407 0 : matScreen->ReflectSolBeamFront = matScreen->DfRef;
7408 0 : matScreen->ReflectSolBeamBack = matScreen->DfRef;
7409 :
7410 : // Initialize incident-angle dependent beam matrix (will interpolate from this)
7411 0 : for (int ip = 0; ip < Material::maxIPhi; ++ip) {
7412 0 : Real64 Phi = ip * matScreen->dPhi;
7413 0 : for (int it = 0; it < Material::maxITheta; ++it) {
7414 0 : Real64 Theta = it * matScreen->dTheta;
7415 0 : CalcScreenTransmittance(state, matScreen, Phi, Theta, matScreen->btars[ip][it]);
7416 : }
7417 : }
7418 :
7419 : } // for (SurfNum)
7420 :
7421 : // Write transmittance versus direct normal angle to csv file
7422 :
7423 0 : if (PrintTransMap) {
7424 : // Fortran version did not have error handling in case of file open failure. This one does.
7425 : // Which is correct?
7426 0 : auto screenCsvFile = state.files.screenCsv.open(state, "CalcWindowScreenComponents", state.files.outputControl.screen);
7427 :
7428 : // WRITE(ScreenTransUnitNo,*)' '
7429 0 : for (auto *mat : s_mat->materials) {
7430 :
7431 0 : if (mat->group != Material::Group::Screen) continue;
7432 0 : if (!mat->isUsed) continue;
7433 :
7434 0 : auto *screen = dynamic_cast<Material::MaterialScreen *>(mat);
7435 0 : assert(screen != nullptr);
7436 :
7437 : // Do not print transmittance map if angle increment is equal to 0
7438 0 : if (screen->mapDegResolution == 0) continue;
7439 :
7440 0 : int maxIPrint = int(90 / screen->mapDegResolution);
7441 :
7442 0 : print(screenCsvFile, "MATERIAL:WINDOWSCREEN:{}\n", screen->Name);
7443 0 : print(screenCsvFile,
7444 : "Tabular data for beam solar transmittance at varying \"relative\" azimuth (row) and "
7445 : "altitude (column) angles (deg) [relative to surface normal].\n");
7446 0 : for (int it = maxIPrint; it >= 0; --it) {
7447 0 : print(screenCsvFile, ",{}", it * screen->mapDegResolution);
7448 : }
7449 0 : print(screenCsvFile, "\n");
7450 :
7451 0 : for (int it = 0; it <= maxIPrint; ++it) {
7452 0 : print(screenCsvFile, "{}", it * screen->mapDegResolution);
7453 0 : for (int ip = maxIPrint; ip >= 0; --ip) {
7454 0 : Real64 phi = ip * screen->mapDegResolution * Constant::DegToRad;
7455 0 : Real64 theta = it * screen->mapDegResolution * Constant::DegToRad;
7456 : int ip1, ip2, it1, it2;
7457 : BilinearInterpCoeffs coeffs;
7458 0 : Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2);
7459 0 : GetBilinearInterpCoeffs(
7460 0 : phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs);
7461 0 : Real64 bmTrans = BilinearInterp(screen->btars[ip1][it1].BmTrans,
7462 0 : screen->btars[ip1][it2].BmTrans,
7463 0 : screen->btars[ip2][it1].BmTrans,
7464 0 : screen->btars[ip2][it2].BmTrans,
7465 0 : coeffs);
7466 : // bmTrans = screen->btars[ip][it].BmTrans;
7467 0 : print(screenCsvFile, ",{:.6R}", bmTrans);
7468 : }
7469 0 : print(screenCsvFile, "\n");
7470 : }
7471 0 : print(screenCsvFile, "\n\n");
7472 :
7473 0 : print(screenCsvFile, "MATERIAL:WINDOWSCREEN:{}\n", screen->Name);
7474 0 : print(screenCsvFile,
7475 : "Tabular data for scattered solar transmittance at varying \"relative\" azimuth (row) and "
7476 : "altitude (column) angles (deg) [relative to surface normal].\n");
7477 :
7478 0 : for (int it = 0; it <= maxIPrint; ++it) {
7479 0 : print(screenCsvFile, ",{}", it * screen->mapDegResolution);
7480 : }
7481 0 : print(screenCsvFile, "\n");
7482 :
7483 0 : for (int it = 0; it <= maxIPrint; ++it) {
7484 0 : print(screenCsvFile, "{}", it * screen->mapDegResolution);
7485 0 : for (int ip = 0; ip <= maxIPrint; ++ip) {
7486 0 : Real64 phi = ip * screen->mapDegResolution * Constant::DegToRad;
7487 0 : Real64 theta = it * screen->mapDegResolution * Constant::DegToRad;
7488 : int ip1, ip2, it1, it2;
7489 : BilinearInterpCoeffs coeffs;
7490 0 : Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2);
7491 0 : GetBilinearInterpCoeffs(
7492 0 : phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs);
7493 0 : Real64 dfTrans = BilinearInterp(screen->btars[ip1][it1].DfTrans,
7494 0 : screen->btars[ip1][it2].DfTrans,
7495 0 : screen->btars[ip2][it1].DfTrans,
7496 0 : screen->btars[ip2][it2].DfTrans,
7497 0 : coeffs);
7498 :
7499 : // dfTrans = screen->btars[ip][it].DfTrans;
7500 0 : print(screenCsvFile, ",{:.6R}", dfTrans);
7501 : }
7502 0 : print(screenCsvFile, "\n");
7503 : }
7504 0 : print(screenCsvFile, "\n\n");
7505 : }
7506 0 : } // if (PrintTransMap)
7507 0 : } // CalcWindowScreenProperties()
7508 :
7509 724 : void BlindOpticsDiffuse(EnergyPlusData &state,
7510 : int const BlindNum, // Blind number
7511 : int const ISolVis, // 1 = solar and IR calculation; 2 = visible calculation
7512 : Array1A<Real64> const c, // Slat properties
7513 : Real64 const b_el, // Slat elevation (radians)
7514 : Array1A<Real64> p // Blind properties
7515 : )
7516 : {
7517 :
7518 : // SUBROUTINE INFORMATION:
7519 : // AUTHOR Hans Simmler
7520 : // DATE WRITTEN July-Aug 1995
7521 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
7522 : // Aug 2002 (FCW): make corrections so that calculations are consistent with
7523 : // G(i) = Sum over j of J(j)*F(j,i). Previously, i,j was
7524 : // interchanged in F, so that
7525 : // G(i) = Sum over j of J(j)*F(i,j), which is wrong.
7526 : // This change was made to resolve discrepancies between EnergyPlus results
7527 : // and blind transmittance measurements made at Oklahoma State Univ.
7528 : // Feb 2004 (FCW): modify slat edge correction calc to avoid possible divide by zero
7529 :
7530 : // PURPOSE OF THIS SUBROUTINE:
7531 : // From the slat properties, calculates the diffuse solar, diffuse visible and IR
7532 : // transmission and reflection properties of a window blind.
7533 :
7534 : // REFERENCES:
7535 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
7536 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
7537 :
7538 : // Argument array dimensioning
7539 724 : c.dim(15);
7540 724 : p.dim(16);
7541 :
7542 724 : Array1D<Real64> fEdgeA(2); // Average slat edge correction factor for upper and lower quadrants
7543 : // seen by window blind
7544 724 : Array1D<Real64> j(6); // Slat section radiosity vector
7545 724 : Array1D<Real64> G(6); // Slat section irradiance vector
7546 724 : Array1D<Real64> Q(6); // Slat section radiance vector
7547 724 : Array2D<Real64> F(6, 6); // View factor array
7548 724 : Array2D<Real64> X(4, 4); // Exchange matrix
7549 724 : Array2D<Real64> Xinv(4, 4); // Inverse of exchange matrix
7550 724 : Array1D_int indx(4); // LU decomposition indices
7551 :
7552 : // The slat input properties are:
7553 : // c(1) 0. (unused)
7554 : // c(2) Slat width (m)
7555 : // c(3) Slat separation (m)
7556 : // c(4) 0. (unused)
7557 : // c(5) 0. (unused)
7558 : // c(6) 0. (unused)
7559 : // The following are solar or visible properties
7560 : // c(7) trans beam-diff
7561 : // c(8) refl front beam-diff
7562 : // c(9) refl back beam-diff
7563 : // c(10) trans diff-diff
7564 : // c(11) refl front diff-diff
7565 : // c(12) refl back diff-diff
7566 : // The following are hemispherical thermal IR properties
7567 : // c(13) trans diff-diff
7568 : // c(14) emiss front diff
7569 : // c(15) emiss back diff
7570 :
7571 : // The calculated blind properties are:
7572 : // The following are solar or visible properties
7573 : // p(1) trans front beam-beam
7574 : // p(2) refl front beam-beam
7575 : // p(3) trans back beam-beam
7576 : // p(4) refl back beam-beam
7577 : // p(5) trans front beam-diff
7578 : // p(6) refl front beam-diff
7579 : // p(7) trans back beam-diff
7580 : // p(8) refl back beam-diff
7581 : // p(9) trans front diff-diff
7582 : // p(10) refl front diff-diff
7583 : // p(11) trans back diff-diff
7584 : // p(12) refl back diff-diff
7585 : // The following are IR properties
7586 : // p(13) IR trans front (same as IR trans back)
7587 : // p(14) IR emissivity front
7588 : // p(15) IR emissivity back
7589 : // p(16) 0.0 (unused)
7590 :
7591 724 : auto &s_mat = state.dataMaterial;
7592 724 : auto *matBlind = dynamic_cast<Material::MaterialBlind *>(s_mat->materials(BlindNum));
7593 : // Calculate view factors between slat sections (slat is divided longitudinally into two equal parts)
7594 :
7595 724 : ViewFac(c(2), c(3), b_el, Constant::PiOvr2, F);
7596 :
7597 : // Set up exchange matrix X for diffuse properties
7598 :
7599 2172 : for (int k = 3; k <= 5; k += 2) {
7600 7240 : for (int m = 3; m <= 6; ++m) {
7601 5792 : X(m - 2, k - 2) = -c(12) * F(k, m) - c(10) * F(k + 1, m);
7602 5792 : X(m - 2, k - 1) = -c(10) * F(k, m) - c(11) * F(k + 1, m);
7603 : }
7604 : }
7605 :
7606 3620 : for (int k = 1; k <= 4; ++k) {
7607 2896 : ++X(k, k);
7608 : }
7609 :
7610 724 : indx = 0;
7611 724 : InvertMatrix(state, X, Xinv, indx, 4); // Autodesk:Note X modified by this call
7612 :
7613 : //---------Calculate diffuse short-wave properties for the front side of the blind
7614 :
7615 : // Sources
7616 :
7617 724 : Q(3) = c(12) * F(3, 1) + c(10) * F(4, 1);
7618 724 : Q(4) = c(10) * F(3, 1) + c(11) * F(4, 1);
7619 724 : Q(5) = c(12) * F(5, 1) + c(10) * F(6, 1);
7620 724 : Q(6) = c(10) * F(5, 1) + c(11) * F(6, 1);
7621 :
7622 : // Radiosities
7623 :
7624 724 : j(1) = 1.0;
7625 724 : j(2) = 0.0;
7626 3620 : for (int k = 3; k <= 6; ++k) {
7627 2896 : j(k) = 0.0;
7628 14480 : for (int m = 3; m <= 6; ++m) {
7629 11584 : j(k) += Xinv(m - 2, k - 2) * Q(m);
7630 : }
7631 : }
7632 :
7633 : // Irradiances
7634 5068 : for (int k = 1; k <= 6; ++k) {
7635 4344 : G(k) = 0.0;
7636 30408 : for (int m = 1; m <= 6; ++m) {
7637 : // G(k)=G(k)+F(k,m)*J(m)
7638 26064 : G(k) += j(m) * F(k, m);
7639 : }
7640 : }
7641 :
7642 : // Slat edge correction factor
7643 : std::array<Real64, numPhis> fEdgeSource; // Slat edge correction factor vs source elevation
7644 :
7645 724 : Real64 const phib = b_el; // Elevation of slat normal vector (radians)
7646 724 : Real64 constexpr delphis =
7647 : Constant::PiOvr2 /
7648 : 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.
7649 :
7650 2172 : for (int IUpDown = 1; IUpDown <= 2; ++IUpDown) {
7651 15928 : for (int iPhi = 0; iPhi < numPhis; ++iPhi) {
7652 14480 : Real64 phis = -((double)iPhi + 0.5) * delphis; // Source elevation (radians)
7653 14480 : if (IUpDown == 2) phis = ((double)iPhi + 0.5) * delphis;
7654 14480 : fEdgeSource[iPhi] = 0.0;
7655 14480 : Real64 fEdge1 = 0.0;
7656 14480 : Real64 gamma = phib - phis;
7657 14480 : if (std::abs(std::sin(gamma)) > 0.01) {
7658 14320 : if ((phib > 0.0 && phib <= Constant::PiOvr2 && phis <= phib) ||
7659 7120 : (phib > Constant::PiOvr2 && phib <= Constant::Pi && phis > -(Constant::Pi - phib))) {
7660 10720 : fEdge1 = matBlind->SlatThickness * std::abs(std::sin(gamma)) /
7661 10720 : ((matBlind->SlatSeparation + matBlind->SlatThickness / std::abs(std::sin(phib))) * std::cos(phis));
7662 : }
7663 14320 : fEdgeSource[iPhi] = min(1.0, std::abs(fEdge1));
7664 : }
7665 : }
7666 1448 : fEdgeA(IUpDown) = DiffuseAverage(fEdgeSource);
7667 : }
7668 724 : Real64 fEdge = 0.5 * (fEdgeA(1) + fEdgeA(2)); // Slat edge correction factor
7669 :
7670 : // Front diffuse-diffuse transmittance (transmittance of slat edge assumed zero)
7671 724 : p(9) = G(2) * (1.0 - fEdge);
7672 :
7673 : // Front diffuse-diffuse reflectance (edge of slat is assumed to have same diffuse
7674 : // reflectance as front side of slat, c(11))
7675 724 : p(10) = G(1) * (1.0 - fEdge) + fEdge * c(11);
7676 :
7677 : //-----------Calculate diffuse short-wave properties for the back side of the blind
7678 :
7679 : // Sources
7680 :
7681 724 : Q(3) = c(12) * F(3, 2) + c(10) * F(4, 2);
7682 724 : Q(4) = c(10) * F(3, 2) + c(11) * F(4, 2);
7683 724 : Q(5) = c(12) * F(5, 2) + c(10) * F(6, 2);
7684 724 : Q(6) = c(10) * F(5, 2) + c(11) * F(6, 2);
7685 :
7686 : // Radiosities
7687 :
7688 724 : j(1) = 0.0;
7689 724 : j(2) = 1.0;
7690 3620 : for (int k = 3; k <= 6; ++k) {
7691 2896 : j(k) = 0.0;
7692 14480 : for (int m = 3; m <= 6; ++m) {
7693 11584 : j(k) += Xinv(m - 2, k - 2) * Q(m);
7694 : }
7695 : }
7696 :
7697 : // Irradiances
7698 :
7699 5068 : for (int k = 1; k <= 6; ++k) {
7700 4344 : G(k) = 0.0;
7701 30408 : for (int m = 1; m <= 6; ++m) {
7702 : // G(k)=G(k)+F(k,m)*J(m)
7703 26064 : G(k) += j(m) * F(k, m);
7704 : }
7705 : }
7706 :
7707 : // Back diffuse-diffuse transmittance
7708 724 : p(11) = G(1) * (1.0 - fEdge);
7709 :
7710 : // Back hemi-hemi reflectance
7711 724 : p(12) = G(2) * (1.0 - fEdge) + fEdge * c(11);
7712 :
7713 724 : if (ISolVis == 1) {
7714 :
7715 : //-----------Calculate IR properties of the blind
7716 : // (use same set of view factors as for diffuse short-wave properties)
7717 :
7718 : // Front and back slat IR reflectances
7719 362 : Real64 ri = 1 - c(13) - c(14); // Front and back IR slat reflectance
7720 362 : Real64 rib = 1 - c(13) - c(15);
7721 :
7722 : // Set up exchange matrix X for diffuse properties
7723 :
7724 1086 : for (int k = 3; k <= 5; k += 2) {
7725 3620 : for (int m = 3; m <= 6; ++m) {
7726 2896 : X(m - 2, k - 2) = -rib * F(k, m) - c(13) * F(k + 1, m);
7727 2896 : X(m - 2, k - 1) = -c(13) * F(k, m) - ri * F(k + 1, m);
7728 : }
7729 : }
7730 :
7731 1810 : for (int k = 1; k <= 4; ++k) {
7732 1448 : ++X(k, k);
7733 : }
7734 :
7735 362 : indx = 0;
7736 362 : InvertMatrix(state, X, Xinv, indx, 4); // Autodesk:Note X modified by this call
7737 :
7738 : //---------Calculate diffuse IR properties for the FRONT side of the blind
7739 :
7740 : // Sources
7741 :
7742 362 : Q(3) = rib * F(3, 1) + c(13) * F(4, 1);
7743 362 : Q(4) = c(13) * F(3, 1) + ri * F(4, 1);
7744 362 : Q(5) = rib * F(5, 1) + c(13) * F(6, 1);
7745 362 : Q(6) = c(13) * F(5, 1) + ri * F(6, 1);
7746 :
7747 : // Radiosities
7748 :
7749 362 : j(1) = 1.0;
7750 362 : j(2) = 0.0;
7751 1810 : for (int k = 3; k <= 6; ++k) {
7752 1448 : j(k) = 0.0;
7753 7240 : for (int m = 3; m <= 6; ++m) {
7754 5792 : j(k) += Xinv(m - 2, k - 2) * Q(m);
7755 : }
7756 : }
7757 :
7758 : // Irradiances
7759 2534 : for (int k = 1; k <= 6; ++k) {
7760 2172 : G(k) = 0.0;
7761 15204 : for (int m = 1; m <= 6; ++m) {
7762 : // G(k)=G(k)+F(k,m)*J(m)
7763 13032 : G(k) += j(m) * F(k, m);
7764 : }
7765 : }
7766 :
7767 : // Front diffuse-diffuse IR transmittance (transmittance of slat edge assumed zero)
7768 362 : p(13) = G(2) * (1.0 - fEdge);
7769 :
7770 : // Front diffuse-diffuse IR reflectance (edge of slat is assumed to have same IR
7771 : // reflectance as front side of slat, ri)
7772 362 : Real64 BlindIRreflFront = G(1) * (1.0 - fEdge) + fEdge * ri; // Blind front IR reflectance
7773 :
7774 : // Front IR emissivity
7775 362 : p(14) = max(0.0001, 1.0 - p(13) - BlindIRreflFront);
7776 :
7777 : //-----------Calculate diffuse IR properties for the BACK side of the blind
7778 :
7779 : // Sources
7780 :
7781 362 : Q(3) = rib * F(3, 2) + c(13) * F(4, 2);
7782 362 : Q(4) = c(13) * F(3, 2) + ri * F(4, 2);
7783 362 : Q(5) = rib * F(5, 2) + c(13) * F(6, 2);
7784 362 : Q(6) = c(13) * F(5, 2) + ri * F(6, 2);
7785 :
7786 : // Radiosities
7787 :
7788 362 : j(1) = 0.0;
7789 362 : j(2) = 1.0;
7790 1810 : for (int k = 3; k <= 6; ++k) {
7791 1448 : j(k) = 0.0;
7792 7240 : for (int m = 3; m <= 6; ++m) {
7793 5792 : j(k) += Xinv(m - 2, k - 2) * Q(m);
7794 : }
7795 : }
7796 :
7797 : // Irradiances
7798 :
7799 2534 : for (int k = 1; k <= 6; ++k) {
7800 2172 : G(k) = 0.0;
7801 15204 : for (int m = 1; m <= 6; ++m) {
7802 : // G(k)=G(k)+F(k,m)*J(m)
7803 13032 : G(k) += j(m) * F(k, m);
7804 : }
7805 : }
7806 :
7807 : // Back diffuse-diffuse IR reflectance
7808 362 : Real64 BlindIRreflBack = G(2) * (1.0 - fEdge) + fEdge * ri; // Blind back IR reflectance
7809 :
7810 : // Back IR emissivity
7811 362 : p(15) = max(0.0001, 1.0 - p(13) - BlindIRreflBack);
7812 :
7813 : } // End of IR properties calculation
7814 724 : } // BlindOpticsDiffuse()
7815 :
7816 : //**********************************************************************************************
7817 :
7818 26788 : void BlindOpticsBeam(EnergyPlusData &state,
7819 : int const BlindNum, // Blind number
7820 : Array1A<Real64> const c, // Slat properties (equivalent to BLD_PR)
7821 : Real64 const b_el, // Slat elevation (radians)
7822 : Real64 const s_el, // Solar profile angle (radians)
7823 : Array1A<Real64> p // Blind properties (equivalent to ST_LAY)
7824 : )
7825 : {
7826 :
7827 : // SUBROUTINE INFORMATION:
7828 : // AUTHOR Hans Simmler
7829 : // DATE WRITTEN July-Aug 1995
7830 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
7831 : // Aug 2002 (FCW): make corrections so that calculations are consistent with
7832 : // G(i) = Sum over j of J(j)*F(j,i). Previously, i,j was
7833 : // interchanged in F, so that
7834 : // G(i) = Sum over j of J(j)*F(i,j), which is wrong.
7835 : // This change was made to resolve discrepancies between EnergyPlus results
7836 : // and blind transmittance measurements made at Oklahoma State Univ.
7837 :
7838 : // PURPOSE OF THIS SUBROUTINE:
7839 : // Calculates the beam radiation properties of a
7840 : // window blind consisting of flat slats with known material properties.
7841 : // The calculation for the reverse direction is done with the radiation source
7842 : // reflected at the window plane.
7843 :
7844 : // REFERENCES:
7845 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
7846 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
7847 :
7848 : // Argument array dimensioning
7849 26788 : c.dim(15);
7850 26788 : p.dim(16);
7851 :
7852 : struct BlindInputs
7853 : {
7854 : Real64 slatWidth;
7855 : Real64 slatSeparation;
7856 : Real64 BmDfTrans;
7857 : Real64 BmDfRefFront;
7858 : Real64 BmDfRefBack;
7859 : Real64 DfDfTrans;
7860 : Real64 DfDfRefFront;
7861 : Real64 DfDfRefBack;
7862 : Real64 DfDfTransIR;
7863 : Real64 DfEmissFront;
7864 : Real64 DfEmissBack;
7865 : };
7866 :
7867 : // The slat input properties are:
7868 : // c(1) 0. (unused)
7869 : // c(2) Slat width (m)
7870 : // c(3) Slat separation (m)
7871 : // c(4) 0. (unused)
7872 : // c(5) 0. (unused)
7873 : // c(6) 0. (unused)
7874 : // The following are solar or visible properties
7875 : // c(7) trans beam-diff
7876 : // c(8) refl front beam-diff
7877 : // c(9) refl back beam-diff
7878 : // c(10) trans diff-diff
7879 : // c(11) refl front diff-diff
7880 : // c(12) refl back diff-diff
7881 : // The following are hemispherical thermal IR properties
7882 : // c(13) trans diff-diff
7883 : // c(14) emiss front diff
7884 : // c(15) emiss back diff
7885 :
7886 : struct BlindOutputs
7887 : {
7888 : Real64 BmBmTransFront;
7889 : Real64 BmBmRefFront;
7890 : Real64 BmBmTransBack;
7891 : Real64 BmBmRefBack;
7892 : Real64 BmDfTransFront;
7893 : Real64 BmDfRefFront;
7894 : Real64 BmDfTransBack;
7895 : Real64 BmDfRefBack;
7896 : Real64 DfDfTransFront;
7897 : Real64 DfDfRefFront;
7898 : Real64 DfDfTransBack;
7899 : Real64 DfDfRefBack;
7900 :
7901 : Real64 TransFrontIR;
7902 : Real64 TransBackIR;
7903 : Real64 EmissFrontIR;
7904 : Real64 EmissBackIR;
7905 : };
7906 :
7907 : // The calculated blind properties are:
7908 : // The following are solar or visible properties
7909 : // p(1) trans front beam-beam
7910 : // p(2) refl front beam-beam
7911 : // p(3) trans back beam-beam
7912 : // p(4) refl back beam-beam
7913 : // p(5) trans front beam-diff
7914 : // p(6) refl front beam-diff
7915 : // p(7) trans back beam-diff
7916 : // p(8) refl back beam-diff
7917 : // p(9) trans front diff-diff
7918 : // p(10) refl front diff-diff
7919 : // p(11) trans back diff-diff
7920 : // p(12) refl back diff-diff
7921 : // The following are IR properties
7922 : // p(13) IR trans front (same as IR trans back)
7923 : // p(14) IR emissivity front
7924 : // p(15) IR emissivity back
7925 : // p(16) 0.0 (unused)
7926 :
7927 : Real64 phib; // Elevation angle of normal vector to front of slat (0 to pi radians)
7928 : Real64 phis; // Elevation angle of source vector; same as "profile angle" (-pi/2 to pi/2 radians)
7929 : Real64 gamma; // phib - phis (radians)
7930 26788 : Array1D<Real64> j(6); // Slat surface section radiosity vector
7931 26788 : Array1D<Real64> G(6); // Slat surface section irradiance vector
7932 26788 : Array1D<Real64> Q(6); // Slat surface section source vector
7933 26788 : Array2D<Real64> F(6, 6); // View factor array
7934 26788 : Array2D<Real64> X(4, 4); // X*J = Q
7935 26788 : Array2D<Real64> Xinv(4, 4); // J = Xinv*Q
7936 : Real64 fEdge; // Slat edge correction factor
7937 : Real64 fEdge1;
7938 26788 : Array1D_int indx(4); // Indices for LU decomposition
7939 :
7940 26788 : auto &s_mat = state.dataMaterial;
7941 26788 : auto const *matBlind = dynamic_cast<Material::MaterialBlind const *>(s_mat->materials(BlindNum));
7942 :
7943 26788 : p = 0.0;
7944 :
7945 : // Elevation of radiation source; source is assumed to be in a plane that
7946 : // (1) contains the slat outward normal and (2) is perpendicular to plane of the blinds.
7947 26788 : phis = s_el;
7948 :
7949 : // Elevation of slat outward normal
7950 26788 : phib = b_el;
7951 :
7952 : // Loop twice for front and back side properties of blind
7953 80364 : for (int i = 0; i <= 2; i += 2) {
7954 :
7955 : // For back-side properties, reflect the source position so that it is the mirror
7956 : // image of the original source position, where the "mirror" is in the plane of the
7957 : // blinds. This is equivalent to keeping the original source position but rotating
7958 : // the slats so that the original slat angle (e.g., 45 deg) becomes 180 - original slat
7959 : // angle (135 deg).
7960 :
7961 53576 : if (i == 2) {
7962 26788 : phib = Constant::Pi - phib;
7963 : }
7964 :
7965 : // Correction factor that accounts for finite thickness of slats. It is used to modify the
7966 : // blind transmittance and reflectance to account for reflection and absorption by the
7967 : // edge of the slat. fEdge is ratio of area subtended by edge of slat
7968 : // to area between tops of adjacent slats.
7969 :
7970 53576 : fEdge = 0.0;
7971 53576 : fEdge1 = 0.0;
7972 53576 : gamma = phib - phis;
7973 53576 : if (std::abs(std::sin(gamma)) > 0.01) {
7974 53272 : if ((phib > 0.0 && phib <= Constant::PiOvr2 && phis <= phib) ||
7975 26496 : (phib > Constant::PiOvr2 && phib <= Constant::Pi && phis > -(Constant::Pi - phib))) {
7976 39448 : fEdge1 = matBlind->SlatThickness * std::abs(std::sin(gamma)) /
7977 39448 : ((matBlind->SlatSeparation + matBlind->SlatThickness / std::abs(std::sin(phib))) * std::cos(phis));
7978 : }
7979 53272 : fEdge = min(1.0, std::abs(fEdge1));
7980 : }
7981 :
7982 : // Direct-to-direct transmittance (portion of beam that passes between slats without
7983 : // without touching them
7984 :
7985 53576 : p(1 + i) = matBlind->BeamBeamTrans(phis, phib);
7986 : // Direct-to-direct reflectance; this is zero for now since all reflection is assumed to be diffuse.
7987 53576 : p(2 + i) = 0.0;
7988 :
7989 : // View factors between slat sections for calculating direct-to-diffuse transmittance and reflectance
7990 53576 : ViewFac(c(2), c(3), phib, phis, F);
7991 :
7992 : // Set up exchange matrix X for calculating direct-to-diffuse properties
7993 :
7994 160728 : for (int k = 3; k <= 5; k += 2) {
7995 535760 : for (int m = 3; m <= 6; ++m) {
7996 428608 : X(m - 2, k - 2) = -c(12) * F(k, m) - c(10) * F(k + 1, m);
7997 428608 : X(m - 2, k - 1) = -c(10) * F(k, m) - c(11) * F(k + 1, m);
7998 : }
7999 : }
8000 :
8001 267880 : for (int k = 1; k <= 4; ++k) {
8002 214304 : ++X(k, k);
8003 : }
8004 :
8005 53576 : indx = 0;
8006 : // In the following, note that InvertMatrix changes X
8007 53576 : InvertMatrix(state, X, Xinv, indx, 4);
8008 :
8009 : // Set up sources for direct-diffuse slat properties
8010 53576 : if (std::abs(phis - phib) <= Constant::PiOvr2) { // Beam hits front of slat
8011 26892 : Q(3) = c(4) + c(7); // beam-beam trans of slat + beam-diff trans of slat
8012 26892 : Q(4) = c(5) + c(8); // front beam-beam refl of slat + front beam-diff refl of slat
8013 : } else { // Beam hits back of slat
8014 26684 : Q(3) = c(6) + c(9); // back beam-beam refl of slat + back beam-diff refl of slat
8015 26684 : Q(4) = c(4) + c(7); // beam-beam trans of slat + beam-diff trans of slat
8016 : }
8017 :
8018 : // Correct for fraction of beam that is not directly transmitted; 1 - this fraction is
8019 : // the fraction of the incoming beam that is incident on the front or back surfaces of the slats.
8020 53576 : Q(3) *= (1.0 - p(1 + i));
8021 53576 : Q(4) *= (1.0 - p(1 + i));
8022 :
8023 : // Radiosities (radiance of slat sections)
8024 53576 : j(1) = 0.0;
8025 53576 : j(2) = 0.0;
8026 267880 : for (int k = 3; k <= 6; ++k) {
8027 214304 : j(k) = 0.0;
8028 642912 : for (int m = 3; m <= 4; ++m) {
8029 428608 : j(k) += Xinv(m - 2, k - 2) * Q(m);
8030 : }
8031 : }
8032 :
8033 : // Irradiance on slat sections
8034 375032 : for (int k = 1; k <= 6; ++k) {
8035 321456 : G(k) = 0.0;
8036 1607280 : for (int m = 3; m <= 6; ++m) {
8037 1285824 : G(k) += j(m) * F(k, m);
8038 : }
8039 : }
8040 :
8041 : // Direct-to-diffuse transmittance
8042 53576 : p(5 + i) = G(2) * (1.0 - fEdge);
8043 :
8044 : // Direct-to-diffuse reflectance (assuming the edge reflectance is the same as the
8045 : // reflectance of the front side of the slat, C(8))
8046 53576 : p(6 + i) = G(1) * (1.0 - fEdge) + fEdge * c(8);
8047 :
8048 : } // End of loop over front and back side properties of blind
8049 26788 : } // BlindOpticsBeam()
8050 :
8051 : //********************************************************************************************
8052 :
8053 54300 : void ViewFac(Real64 const s, // Slat width (m)
8054 : Real64 const h, // Distance between faces of adjacent slats (m)
8055 : Real64 const phib, // Elevation angle of normal to slat (radians)
8056 : Real64 const phis, // Profile angle of radiation source (radians)
8057 : Array2A<Real64> F // View factor array
8058 : )
8059 : {
8060 :
8061 : // SUBROUTINE INFORMATION:
8062 : // AUTHOR Hans Simmler
8063 : // DATE WRITTEN July-Aug 1995
8064 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
8065 : // Apr 2002 (FCW): prevent sqrt of small negative argument
8066 :
8067 : // PURPOSE OF THIS SUBROUTINE:
8068 : // Calculates the view factors between sections of adjacent slats,
8069 : // where each slat is divided longitudinally into two equal sections whose
8070 : // dimensions depend on source profile angle and slat geometry. The view
8071 : // factors are used in BlindOpticsBeam and BlindOpticsDiffuse to determine blind
8072 : // transmittance and reflectance for short-wave and long-wave radiation.
8073 :
8074 : // METHODOLOGY EMPLOYED:
8075 : // Uses expressions for view factor between flat strips with a common edge
8076 : // and flat strips displaced from one another. See engineering documentation.
8077 :
8078 : // REFERENCES:
8079 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
8080 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
8081 :
8082 : // Argument array dimensioning
8083 54300 : F.dim(6, 6);
8084 :
8085 54300 : Array1D<Real64> L(6); // Length of slat sections: L1 = L2 = h; L3, L5 = length
8086 :
8087 54300 : Real64 h2 = pow_2(h);
8088 54300 : Real64 ht = 2.0 * h;
8089 54300 : Real64 co = std::cos(phis); // Cosine of source profile angle
8090 54300 : if (std::abs(co) < 0.001) co = 0.0;
8091 54300 : Real64 w = ht; // Slat geometry variable (m)
8092 54300 : if (co != 0.0) w = s * std::cos(phib - phis) / co;
8093 54300 : Real64 L3 = s * h / std::abs(w);
8094 54300 : if (L3 > s) L3 = s;
8095 54300 : Real64 L5 = s - L3;
8096 54300 : Real64 a = ht * std::cos(phib); // Intermediate variable (m)
8097 : // MAX(0.,...) in the following prevents small negative argument for sqrt
8098 54300 : Real64 d1 = std::sqrt(max(0.0, s * s + h2 + a * s)); // Slat geometry variables (m)
8099 54300 : Real64 d2 = std::sqrt(max(0.0, s * s + h2 - a * s));
8100 54300 : Real64 d3 = std::sqrt(max(0.0, L3 * L3 + h2 + a * L3));
8101 54300 : Real64 d4 = std::sqrt(max(0.0, L3 * L3 + h2 - a * L3));
8102 54300 : Real64 d5 = std::sqrt(max(0.0, L5 * L5 + h2 - a * L5));
8103 54300 : Real64 d6 = std::sqrt(max(0.0, L5 * L5 + h2 + a * L5));
8104 380100 : for (int i = 1; i <= 6; ++i) {
8105 325800 : F(i, i) = 0.0;
8106 : }
8107 54300 : F(1, 1) = 0.0;
8108 54300 : F(2, 1) = (d1 + d2 - 2.0 * s) / ht;
8109 54300 : F(3, 1) = (h + L3 - d3) / ht;
8110 54300 : F(4, 1) = (h + L3 - d4) / ht;
8111 54300 : F(5, 1) = (L5 + d3 - d1) / ht;
8112 54300 : F(6, 1) = (L5 + d4 - d2) / ht;
8113 54300 : F(3, 2) = (L3 + d5 - d2) / ht;
8114 54300 : F(4, 2) = (L3 + d6 - d1) / ht;
8115 54300 : F(5, 2) = (h + L5 - d5) / ht;
8116 54300 : F(6, 2) = (h + L5 - d6) / ht;
8117 54300 : F(4, 3) = (d3 + d4 - ht) / (2.0 * L3);
8118 54300 : F(5, 3) = 0.0;
8119 54300 : F(6, 3) = (d2 + h - d4 - d5) / (2.0 * L3);
8120 54300 : F(5, 4) = (d1 + h - d3 - d6) / (2.0 * L3);
8121 54300 : F(6, 4) = 0.0;
8122 54300 : F(6, 5) = 0.0;
8123 54300 : if (L5 > 0.0) F(6, 5) = (d5 + d6 - ht) / (2.0 * L5);
8124 54300 : L(1) = h;
8125 54300 : L(2) = h;
8126 54300 : L(3) = L3;
8127 54300 : L(4) = L3; // L4, L6 = length of lower slat
8128 54300 : L(5) = L5;
8129 54300 : L(6) = L5;
8130 325800 : for (int i = 2; i <= 6; ++i) {
8131 1086000 : for (int j = 1; j <= i - 1; ++j) {
8132 814500 : F(j, i) = 0.0;
8133 814500 : if (L(i) > 0.0) F(j, i) = F(i, j) * L(j) / L(i);
8134 : }
8135 : }
8136 54300 : } // ViewFac()
8137 :
8138 : //*****************************************************************************************
8139 :
8140 54662 : void InvertMatrix(EnergyPlusData &state,
8141 : Array2D<Real64> &a, // Matrix to be inverted
8142 : Array2D<Real64> &y, // Inverse of matrix a
8143 : Array1D_int &indx, // Index vector for LU decomposition
8144 : int const n)
8145 : {
8146 :
8147 : // SUBROUTINE INFORMATION:
8148 : // AUTHOR Hans Simmler
8149 : // DATE WRITTEN July-Aug 1995
8150 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
8151 :
8152 : // PURPOSE OF THIS SUBROUTINE:
8153 : // Inverts a matrix.
8154 :
8155 : // METHODOLOGY EMPLOYED:
8156 : // Uses LU decomposition.
8157 :
8158 54662 : Array1D<Real64> tmp(n);
8159 :
8160 : int d;
8161 :
8162 54662 : y = 0.0;
8163 273310 : for (int i = 1; i <= n; ++i) {
8164 218648 : y(i, i) = 1.0;
8165 : }
8166 54662 : indx = 0;
8167 :
8168 54662 : LUdecomposition(state, a, n, indx, d);
8169 :
8170 273310 : for (int j = 1; j <= n; ++j) {
8171 218648 : tmp = 0.0;
8172 218648 : tmp(j) = 1;
8173 218648 : LUsolution(state, a, n, indx, tmp);
8174 1093240 : for (int i = 1; i <= n; ++i)
8175 874592 : y(j, i) = tmp(i);
8176 : }
8177 54662 : } // InvertMatrix()
8178 :
8179 : // added for custom solar or visible spectrum
8180 :
8181 111 : void CheckAndReadCustomSprectrumData(EnergyPlusData &state)
8182 : {
8183 :
8184 : // SUBROUTINE INFORMATION:
8185 : // AUTHOR T. Hong
8186 : // DATE WRITTEN August 2013
8187 :
8188 : // PURPOSE OF THIS SUBROUTINE:
8189 : // Check, read, and assign the custom solar or visible spectrum to:
8190 : // solar: nume, wle(nume), e(nume). nume = 107
8191 : // visible: numt3, wlt3(numt3), y30(numt3). numt3 = 81
8192 : // Three related IDD objects:
8193 : // EnergyManagementSystem:ConstructionIndexVariable
8194 : // Site:SolarAndVisibleSpectrum, Site:SpectrumData
8195 :
8196 : // METHODOLOGY EMPLOYED:
8197 : // Overwriting the default values
8198 :
8199 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8200 111 : bool ErrorsFound(false); // If errors detected in input
8201 : int NumAlphas; // Number of Alphas for each GetobjectItem call
8202 : int NumNumbers; // Number of Numbers for each GetobjectItem call
8203 : int NumArgs;
8204 111 : Array1D_string cAlphaArgs; // Alpha input items for object
8205 111 : Array1D<Real64> rNumericArgs; // Numeric input items for object
8206 :
8207 111 : auto const &wm = state.dataWindowManager;
8208 :
8209 111 : if (wm->RunMeOnceFlag) return;
8210 :
8211 : // Step 1 - check whether there is custom solar or visible spectrum
8212 111 : std::string cCurrentModuleObject = "Site:SolarAndVisibleSpectrum";
8213 111 : int NumSiteSpectrum = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8214 :
8215 : // no custom spectrum data, done!
8216 111 : if (NumSiteSpectrum == 0) {
8217 111 : wm->RunMeOnceFlag = true;
8218 111 : return;
8219 : }
8220 :
8221 : // read custom spectrum data from Site:SolarAndVisibleSpectrum
8222 0 : if (NumSiteSpectrum > 1) { // throw error
8223 0 : ShowSevereError(state, format("Only one {} object is allowed", cCurrentModuleObject));
8224 0 : ErrorsFound = true;
8225 : }
8226 :
8227 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
8228 0 : cAlphaArgs.allocate(NumAlphas);
8229 0 : rNumericArgs.dimension(NumNumbers, 0.0);
8230 :
8231 0 : if (NumSiteSpectrum == 1) {
8232 : int IOStatus;
8233 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8234 : cCurrentModuleObject,
8235 : 1,
8236 0 : state.dataIPShortCut->cAlphaArgs,
8237 : NumAlphas,
8238 0 : state.dataIPShortCut->rNumericArgs,
8239 : NumNumbers,
8240 : IOStatus);
8241 :
8242 : // use default spectrum data, done!
8243 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "Default")) {
8244 0 : wm->RunMeOnceFlag = true;
8245 0 : return;
8246 : }
8247 :
8248 : // now read custom solar and visible spectrum data
8249 0 : std::string cSolarSpectrum = state.dataIPShortCut->cAlphaArgs(3);
8250 0 : std::string cVisibleSpectrum = state.dataIPShortCut->cAlphaArgs(4);
8251 :
8252 0 : cCurrentModuleObject = "Site:SpectrumData";
8253 0 : NumSiteSpectrum = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8254 0 : if (NumSiteSpectrum == 0) { // throw error
8255 0 : ShowSevereError(state, format("No {} object is found", cCurrentModuleObject));
8256 0 : ErrorsFound = true;
8257 : }
8258 :
8259 0 : cAlphaArgs.deallocate();
8260 0 : rNumericArgs.deallocate();
8261 :
8262 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
8263 0 : cAlphaArgs.allocate(NumAlphas);
8264 0 : rNumericArgs.dimension(NumNumbers, 0.0);
8265 :
8266 0 : int iSolarSpectrum = 0;
8267 0 : int iVisibleSpectrum = 0;
8268 0 : for (int Loop = 1; Loop <= NumSiteSpectrum; ++Loop) {
8269 : // Step 2 - read user-defined spectrum data
8270 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8271 : cCurrentModuleObject,
8272 : Loop,
8273 0 : state.dataIPShortCut->cAlphaArgs,
8274 : NumAlphas,
8275 0 : state.dataIPShortCut->rNumericArgs,
8276 : NumNumbers,
8277 : IOStatus);
8278 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), cSolarSpectrum)) {
8279 0 : iSolarSpectrum = Loop;
8280 : // overwrite the default solar spectrum
8281 0 : if (NumNumbers > 2 * nume) {
8282 0 : ShowSevereError(
8283 : state,
8284 0 : format("Solar spectrum data pair is more than 107 - {} - {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
8285 0 : ErrorsFound = true;
8286 : } else {
8287 : // Step 3 - overwrite default solar spectrum data
8288 0 : for (int iTmp = 1; iTmp <= nume; ++iTmp) {
8289 0 : if (iTmp <= NumNumbers / 2) {
8290 0 : wm->wle[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp - 1);
8291 0 : wm->e[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp);
8292 : } else {
8293 0 : wm->wle[iTmp - 1] = 0.0;
8294 0 : wm->e[iTmp - 1] = 0.0;
8295 : }
8296 : }
8297 : }
8298 : }
8299 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), cVisibleSpectrum)) {
8300 0 : iVisibleSpectrum = Loop;
8301 : // overwrite the default solar spectrum
8302 0 : if (NumNumbers > 2 * numt3) {
8303 0 : ShowSevereError(state,
8304 0 : format("Visible spectrum data pair is more than 81 - {} - {}",
8305 : cCurrentModuleObject,
8306 0 : state.dataIPShortCut->cAlphaArgs(1)));
8307 0 : ErrorsFound = true;
8308 : } else {
8309 : // Step 3 - overwrite default visible spectrum data
8310 0 : for (int iTmp = 1; iTmp <= numt3; ++iTmp) {
8311 0 : if (iTmp <= NumNumbers / 2) {
8312 0 : wm->wlt3[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp - 1);
8313 0 : wm->y30[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp);
8314 : } else {
8315 0 : wm->wlt3[iTmp - 1] = 0.0;
8316 0 : wm->y30[iTmp - 1] = 0.0;
8317 : }
8318 : }
8319 : }
8320 : }
8321 0 : if ((iSolarSpectrum > 0) && (iVisibleSpectrum > 0)) break;
8322 : }
8323 0 : }
8324 :
8325 0 : cAlphaArgs.deallocate();
8326 0 : rNumericArgs.deallocate();
8327 :
8328 0 : if (ErrorsFound) {
8329 0 : ShowFatalError(state, "Errors found in processing input for user-defined solar/visible spectrum");
8330 : }
8331 :
8332 0 : wm->RunMeOnceFlag = true;
8333 333 : } // CheckAndReadCustomSpectrumData()
8334 :
8335 : //*****************************************************************************************
8336 :
8337 211 : void initWindowModel(EnergyPlusData &state)
8338 : {
8339 211 : const std::string objectName = "WindowsCalculationEngine";
8340 211 : auto const &wm = state.dataWindowManager;
8341 211 : wm->inExtWindowModel = CWindowModel::WindowModelFactory(state, objectName);
8342 211 : wm->winOpticalModel = CWindowOpticalModel::WindowOpticalModelFactory(state);
8343 211 : } // InitWindowModel()
8344 :
8345 : //*****************************************************************************************
8346 :
8347 : } // namespace Window
8348 :
8349 : } // namespace EnergyPlus
|