Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, 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 : #include <ObjexxFCL/Fmath.hh>
58 :
59 : // EnergyPlus Headers
60 : #include <EnergyPlus/Construction.hh>
61 : #include <EnergyPlus/ConvectionCoefficients.hh>
62 : #include <EnergyPlus/CurveManager.hh>
63 : #include <EnergyPlus/Data/EnergyPlusData.hh>
64 : #include <EnergyPlus/DataBSDFWindow.hh>
65 : #include <EnergyPlus/DataEnvironment.hh>
66 : #include <EnergyPlus/DataHeatBalSurface.hh>
67 : #include <EnergyPlus/DataHeatBalance.hh>
68 : #include <EnergyPlus/DataIPShortCuts.hh>
69 : #include <EnergyPlus/DataLoopNode.hh>
70 : #include <EnergyPlus/DataSurfaces.hh>
71 : #include <EnergyPlus/DataWindowEquivalentLayer.hh>
72 : #include <EnergyPlus/DataZoneEquipment.hh>
73 : #include <EnergyPlus/General.hh>
74 : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
75 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
76 : #include <EnergyPlus/Material.hh>
77 : #include <EnergyPlus/Psychrometrics.hh>
78 : #include <EnergyPlus/ScheduleManager.hh>
79 : #include <EnergyPlus/UtilityRoutines.hh>
80 : #include <EnergyPlus/WindowComplexManager.hh>
81 : #include <EnergyPlus/WindowEquivalentLayer.hh>
82 : #include <EnergyPlus/WindowManager.hh>
83 : #include <EnergyPlus/WindowManagerExteriorOptical.hh>
84 : #include <EnergyPlus/WindowManagerExteriorThermal.hh>
85 : #include <EnergyPlus/WindowModel.hh>
86 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
87 :
88 : namespace EnergyPlus {
89 :
90 : namespace Window {
91 :
92 : // MODULE INFORMATION
93 : // AUTHOR Fred Winkelmann
94 : // DATE WRITTEN September 1999
95 : // MODIFIED August 2001 (FW): add window shade thermal calculation;
96 : // add window blind optical and thermal model.
97 : // February 2003 (FW/LKL): Name changed to WindowManager
98 : // RE-ENGINEERED na
99 :
100 : // PURPOSE OF THIS MODULE:
101 : // Manages the window optical and thermal calculations derived
102 : // from WINDOW 4 and WINDOW 5.
103 :
104 : // METHODOLOGY EMPLOYED:
105 :
106 : // REFERENCES:
107 : // WINDOW 4:
108 : // D.Arasteh, M.Reilly and M.Rubin. A versative procedure for
109 : // calculating heat transfer through windows. ASHRAE Trans. 1989, Vol. 95, Pt. 2.
110 :
111 : // E.Finlayson, D.Arasteh, C.Huizenga, M.Rubin, and M.Reilly. WINDOW 4.0:
112 : // Documentation of calculation procedures. LBL-33943. July 1993.
113 :
114 : // WINDOW 5:
115 : // ASHRAE Standard 142P (draft 1/13/98): Standard method for determining and expressing
116 : // the heat transfer and total optical properties of fenestration products.
117 :
118 : // Shade and blind thermal model:
119 : // ISO/DIS 15099, Thermal Performance of Windows, Doors and Shading Devices,
120 : // Detailed Calculations, 1/12/00.
121 :
122 : // Blind optical model:
123 : // H. Simmler, U. Fischer and Frederick Winkelmann, Solar-Thermal Window Blind Model
124 : // for DOE-2, Lawrence Berkeley National Laboratory, Jan. 1996.
125 :
126 : // Using/Aliasing
127 : using namespace DataEnvironment;
128 : using namespace DataHeatBalance;
129 : using namespace DataSurfaces;
130 :
131 : // SUBROUTINE SPECIFICATIONS FOR MODULE WindowManager:
132 : // Optical Calculation Routines
133 : // Heat Balance Routines
134 :
135 796 : void InitWindowOpticalCalculations(EnergyPlusData &state)
136 : {
137 : // SUBROUTINE INFORMATION:
138 : // AUTHOR Simon Vidanovic
139 : // DATE WRITTEN September 2016
140 : // MODIFIED na
141 : // RE-ENGINEERED na
142 :
143 : // PURPOSE OF THIS SUBROUTINE:
144 : // Manages if optical calculation will be performed with internal or external routines
145 :
146 : // check and read custom solar and/or visible spectrum data if any
147 796 : CheckAndReadCustomSprectrumData(state);
148 :
149 : // allocate surface level adj ratio data member
150 796 : state.dataHeatBalSurf->SurfWinCoeffAdjRatio.dimension(state.dataSurface->TotSurfaces, 1.0);
151 :
152 796 : if (state.dataWindowManager->inExtWindowModel->isExternalLibraryModel()) {
153 3 : InitWCE_SimplifiedOpticalData(state);
154 : } else {
155 793 : InitGlassOpticalCalculations(state);
156 : }
157 796 : }
158 :
159 793 : void InitGlassOpticalCalculations(EnergyPlusData &state)
160 : {
161 :
162 : // SUBROUTINE INFORMATION:
163 : // AUTHOR F. Winkelmann
164 : // DATE WRITTEN August 1999
165 : // MODIFIED May 2001 (FW): add window blinds
166 : // Jan 2002 (FW): add blinds with variable slat angle
167 : // Jan 2003 (FW): add between-glass shade/blind
168 : // May 2006 (RR): add exterior window screen
169 : // Aug 2010 (TH): allow spectral data for between-glass shade/blind
170 : // Aug 2013 (TH): allow user defined solar and visible spectrum data
171 : // RE-ENGINEERED na
172 :
173 : // PURPOSE OF THIS SUBROUTINE:
174 : // Manages the calculation of the solar and visible properties of a multi-layer glazing
175 : // system from the properties of the individual glazing and shading layers
176 :
177 : // Using/Aliasing
178 : using namespace Vectors;
179 :
180 : using WindowEquivalentLayer::InitEquivalentLayerWindowCalculations;
181 :
182 : int CoefNum; // Polynomial coefficient number
183 : int j; // Wavelength counter
184 : int TotLay; // Total solid and gas layers in a window construction
185 : int ConstrNum; // Construction number
186 : int ConstrNumSh; // Shaded construction number
187 : int ShadeLayNum; // Layer number for shade or blind, if present
188 : int ShadeLayPtr; // Material number for shade or blind
189 : bool lquasi; // True if one or more glass layers have no spectral data
190 : bool AllGlassIsSpectralAverage; // True if all glazing in a construction is spectral average
191 : bool IntShade; // True if construction has an interior,exterior or between-glass shade
192 : bool ExtShade;
193 : bool BGShade;
194 : bool IntBlind; // True if construction has an interior,exterior or between-glass blind
195 : bool ExtBlind;
196 : bool BGBlind;
197 : bool ExtScreen; // True if construction has an exterior screen
198 : bool ScreenOn; // True if construction has an exterior screen
199 : bool BlindOn; // True if IntBlind, ExtBlind or BGBlind is true
200 : bool ShadeOn; // True if IntShade, ExtShade or BGShade is true
201 : int BlNum; // Blind number
202 :
203 793 : auto &wm = state.dataWindowManager;
204 793 : Array1D<Real64> sabsPhi(nume); // Glazing system absorptance for a glass layer
205 : // and angle of incidence, for each wavelength
206 : // glass layer for an angle of incidence, for each wavelength
207 : // Glazing system layer solar absorptance for each glass layer
208 793 : Array1D<Real64> solabsDiff(maxGlassLayers);
209 : // Glazing system solar absorptance for a layer at each incidence angle
210 793 : Array1D<Real64> solabsPhiLay(maxIncidentAngles);
211 : // Glazing system solar transmittance from fit at each incidence angle
212 793 : Array1D<Real64> tsolPhiFit(maxIncidentAngles);
213 : // Glazing system visible transmittance from fit at each incidence angle
214 793 : Array1D<Real64> tvisPhiFit(maxIncidentAngles);
215 : // Isolated glass solar transmittance for each incidence angle
216 1586 : Array2D<Real64> tBareSolPhi(maxGlassLayers, maxIncidentAngles);
217 : Real64 t1; // = tBareSolPhi(,1)(,2)
218 : Real64 t2;
219 : // Isolated glass visible transmittance for each incidence angle
220 1586 : Array2D<Real64> tBareVisPhi(maxGlassLayers, maxIncidentAngles);
221 : Real64 t1v; // = tBareVisPhi(,1)(,2)
222 : Real64 t2v;
223 : // Isolated glass front solar reflectance for each incidence angle
224 1586 : Array2D<Real64> rfBareSolPhi(maxGlassLayers, maxIncidentAngles);
225 : // Isolated glass front visible reflectance for each incidence angle
226 1586 : Array2D<Real64> rfBareVisPhi(maxGlassLayers, maxIncidentAngles);
227 : // Isolated glass back solar reflectance for each incidence angle
228 1586 : Array2D<Real64> rbBareSolPhi(maxGlassLayers, maxIncidentAngles);
229 : // Isolated glass back visible reflectance for each incidence angle
230 1586 : Array2D<Real64> rbBareVisPhi(maxGlassLayers, maxIncidentAngles);
231 : // Isolated glass front solar absorptance for each incidence angle
232 1586 : Array2D<Real64> afBareSolPhi(maxGlassLayers, maxIncidentAngles);
233 : Real64 af1; // = afBareSolPhi(,1)(,2)
234 : Real64 af2;
235 : Real64 rbmf2; // Isolated glass #2 front beam reflectance
236 : // Isolated glass back solar absorptance for each incidence angle
237 1586 : Array2D<Real64> abBareSolPhi(maxGlassLayers, maxIncidentAngles);
238 : // Glazing system solar absorptance for each angle of incidence
239 1586 : Array2D<Real64> solabsPhi(maxGlassLayers, maxIncidentAngles);
240 : // Glazing system back solar absorptance for each angle of incidence
241 1586 : Array2D<Real64> solabsBackPhi(maxGlassLayers, maxIncidentAngles);
242 : // Glazing system interior shade solar absorptance for each angle of incidence
243 793 : Array1D<Real64> solabsShadePhi(maxIncidentAngles);
244 :
245 : // These need to stay as Array1D for a little longer because changing them spreads into many source files
246 793 : Array1D<Real64> tsolPhi(maxIncidentAngles); // Glazing system solar transmittance for each angle of incidence
247 793 : Array1D<Real64> rfsolPhi(maxIncidentAngles); // Glazing system solar front reflectance for each angle of incidence
248 793 : Array1D<Real64> rbsolPhi(maxIncidentAngles); // Glazing system solar back reflectance for each angle of incidence
249 793 : Array1D<Real64> tvisPhi(maxIncidentAngles); // Glazing system visible transmittance for each angle of incidence
250 793 : Array1D<Real64> rfvisPhi(maxIncidentAngles); // Glazing system visible front reflectance for each angle of incidence
251 793 : Array1D<Real64> rbvisPhi(maxIncidentAngles); // Glazing system visible back reflectance for each angle of incidence
252 793 : Array1D<Real64> CosPhiIndepVar(maxIncidentAngles); // Cos of incidence angles at 10-deg increments for curve fits
253 :
254 : Real64 ab1; // = abBareSolPhi(,1)(,2)
255 : Real64 ab2;
256 : Real64 td1; // Isolated glass diffuse solar transmittance
257 : Real64 td2;
258 : Real64 td3;
259 : Real64 td1v; // Isolated glass diffuse visible transmittance
260 : Real64 td2v;
261 : Real64 td3v;
262 : Real64 rf1; // Isolated glass diffuse solar front reflectance
263 : Real64 rf2;
264 : Real64 rf3;
265 : Real64 rf1v; // Isolated glass diffuse visible front reflectance
266 : Real64 rf2v;
267 : Real64 rf3v;
268 : Real64 rb1; // Isolated glass diffuse solar back reflectance
269 : Real64 rb2;
270 : Real64 rb3;
271 : Real64 rb1v; // Isolated glass diffuse visible back reflectance
272 : Real64 rb2v;
273 : Real64 rb3v;
274 : Real64 afd1; // Isolated glass diffuse solar front absorptance
275 : Real64 afd2;
276 : Real64 afd3;
277 : Real64 abd1; // Isolated glass diffuse solar back absorptance
278 : Real64 abd2;
279 : Real64 abd3;
280 : Real64 TauShIR; // IR transmittance of isolated shade
281 : Real64 EpsShIR; // IR absorptance of isolated shade
282 : Real64 RhoShIR; // IR reflectance of isolated shade
283 : Real64 EpsGlIR; // IR absorptance of front or back of isolated glass
284 : Real64 RhoGlIR; // IR reflectance of inside face of inside glass
285 : int NGlass; // Number of glass layers in a construction
286 : int LayNum; // Layer number for a glass layer
287 : int LayPtr; // Material number corresponding to LayNum
288 : Real64 Phi; // Incidence angle (deg)
289 : Real64 CosPhi; // Cosine of incidence angle
290 : int ILam; // Wavelength counter
291 : Real64 tsolDiff; // Glazing system diffuse solar transmittance
292 : Real64 tvisDiff; // Glazing system diffuse visible transmittance
293 : int IGlassBack; // Glass layer number counted from back of window
294 : Real64 ShadeAbs; // Solar absorptance of isolated shade
295 : Real64 ash; // = ShadeAbs
296 : Real64 afsh; // Diffuse solar front absorptance of isolated blind
297 : Real64 afshGnd; // Ground and sky diffuse solar front absorptance of isolated blind
298 : Real64 afshSky;
299 : Real64 absh; // Diffuse solar back absorptance of isolated blind
300 : Real64 ShadeTrans; // Solar transmittance of isolated shade/blind
301 : Real64 ShadeTransGnd; // Diffuse-diffuse transmittance of isolated vertical blind with
302 : // horizontal slats for isotropic ground solar
303 : Real64 ShadeTransSky; // Diffuse-diffuse transmittance of isolated vertical blind with
304 : // horizontal slats for isotropic sky solar
305 : Real64 tsh; // = ShadeTrans
306 : Real64 tshGnd; // = ShadeTransGnd,ShadeTransSky
307 : Real64 tshSky;
308 : Real64 tsh2; // = tsh**2
309 : Real64 ShadeRefl; // Solar reflectance of isolated shade
310 : Real64 ShadeReflGnd; // Front blind reflectance for ground diffuse solar
311 : Real64 ShadeReflSky; // Front blind reflectance for sky diffuse solar
312 : Real64 rsh; // = ShadeRefl
313 : Real64 rfsh; // Diffuse solar front reflectance of isolated blind
314 : Real64 rfshGnd; // Ground and sky diffuse solar front reflectance of isolated blind
315 : Real64 rfshSky;
316 : Real64 rbsh; // Diffuse solar back reflectance of isolated blind
317 : Real64 ShadeReflFac; // Shade/blind solar reflection factor
318 : Real64 ShadeTransVis; // Visible transmittance of isolated shade/blind
319 : Real64 tshv; // = ShadeTransVis
320 : Real64 tshv2; // = tshv**2
321 : Real64 ShadeReflVis; // Visible reflectance of isolated shade
322 : Real64 rshv; // = ShadeReflVis
323 : Real64 rfshv; // Diffuse visible front reflectance of isolated blind
324 : Real64 rbshv; // Diffuse visible back reflectance of isolated blind
325 : Real64 ShadeReflFacVis; // Shade/blind visible reflection factor
326 : int SpecDataNum; // Spectral data set number
327 : int numptDAT; // Number of wavelengths in a spectral data set
328 : bool StormWinConst; // True if a construction with a storm window
329 : bool Triangle; // True if window is triangular
330 : bool Rectangle; // True if window is rectangular
331 793 : Vector3<Real64> W1; // Window vertices (m)
332 793 : Vector3<Real64> W2;
333 793 : Vector3<Real64> W3;
334 793 : Vector3<Real64> W21; // W1-W2, W3-W2, resp. (m)
335 793 : Vector3<Real64> W23;
336 :
337 : // Spectral data wavelengths for each glass layer in a glazing system
338 793 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> wlt = {0.0};
339 :
340 : // Following data, Spectral data for each layer for each wavelength in wlt
341 793 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> t = {0.0}; // normal transmittance
342 793 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rff = {0.0}; // normal front reflectance
343 793 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbb = {0.0}; // normal back reflectance
344 793 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> tPhi = {0.0}; // transmittance at angle of incidence
345 793 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rfPhi = {0.0}; // front reflectance at angle of incidence
346 793 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbPhi = {0.0}; // back reflectance at angle of incidence
347 :
348 : // Number of spectral data wavelengths for each layer; =2 if no spectra data for a layer
349 793 : std::array<int, maxGlassLayers> numpt = {0};
350 :
351 793 : W5InitGlassParameters(state);
352 :
353 : // Calculate optical properties of blind-type layers entered with MATERIAL:WindowBlind
354 793 : if (state.dataHeatBal->TotBlinds > 0) CalcWindowBlindProperties(state);
355 :
356 : // Initialize SurfaceScreen structure
357 793 : if (state.dataHeatBal->NumScreens > 0) CalcWindowScreenProperties(state);
358 :
359 : // Get glazing system optical properties of constructions with glass or glass plus
360 : // shade, screen or blind
361 : // Loop over constructions and find those that are glazing constructions
362 6820 : for (int ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
363 6027 : auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
364 6043 : if (!thisConstruct.TypeIsWindow) continue;
365 1364 : if (thisConstruct.WindowTypeBSDF) continue; // Skip Complex Fenestrations, they have separate
366 1351 : if (thisConstruct.WindowTypeEQL) continue; // skip Equivalent Layer Fenestration
367 : // handling of optical properties
368 :
369 14828 : for (int IPhi = 1; IPhi <= 10; ++IPhi) {
370 13480 : CosPhiIndepVar(IPhi) = std::cos((IPhi - 1) * 10.0 * Constant::DegToRadians);
371 : }
372 :
373 1348 : TotLay = thisConstruct.TotLayers;
374 :
375 1348 : auto const *mat = state.dataMaterial->Material(thisConstruct.LayerPoint(1));
376 :
377 : // First layer must be glass, shade, screen or blind to be a glazing construction
378 1348 : if (mat->group != Material::Group::WindowGlass && mat->group != Material::Group::Shade && mat->group != Material::Group::Screen &&
379 134 : mat->group != Material::Group::WindowBlind && mat->group != Material::Group::WindowSimpleGlazing)
380 0 : continue;
381 :
382 1348 : ShadeLayNum = 0;
383 1348 : ExtShade = false;
384 1348 : IntShade = false;
385 1348 : BGShade = false;
386 1348 : ExtBlind = false;
387 1348 : IntBlind = false;
388 1348 : BGBlind = false;
389 1348 : ExtScreen = false;
390 1348 : StormWinConst = false;
391 1348 : wm->lSimpleGlazingSystem = false;
392 :
393 1348 : if (mat->group == Material::Group::WindowSimpleGlazing) {
394 132 : auto const *matWin = dynamic_cast<Material::MaterialChild const *>(mat);
395 132 : assert(matWin != nullptr);
396 :
397 : // what if outside layer is shade, blind, or screen?
398 132 : wm->lSimpleGlazingSystem = true;
399 132 : wm->SimpleGlazingSHGC = matWin->SimpleWindowSHGC;
400 132 : wm->SimpleGlazingU = matWin->SimpleWindowUfactor;
401 : }
402 :
403 1348 : if (has_prefix(thisConstruct.Name, "BARECONSTRUCTIONWITHSTORMWIN") || has_prefix(thisConstruct.Name, "SHADEDCONSTRUCTIONWITHSTORMWIN"))
404 1 : StormWinConst = true;
405 :
406 : // Get layer number of shade/blind
407 1348 : if (mat->group == Material::Group::Shade) {
408 3 : ExtShade = true;
409 3 : ShadeLayNum = 1;
410 1345 : } else if (state.dataMaterial->Material(thisConstruct.LayerPoint(TotLay))->group == Material::Group::Shade) {
411 24 : IntShade = true;
412 24 : ShadeLayNum = TotLay;
413 1321 : } else if (thisConstruct.TotLayers == 5) {
414 68 : if (state.dataMaterial->Material(thisConstruct.LayerPoint(3))->group == Material::Group::Shade) {
415 1 : BGShade = true;
416 1 : ShadeLayNum = 3;
417 : }
418 1253 : } else if (thisConstruct.TotLayers == 7) {
419 8 : if (state.dataMaterial->Material(thisConstruct.LayerPoint(5))->group == Material::Group::Shade) {
420 1 : BGShade = true;
421 1 : ShadeLayNum = 5;
422 : }
423 : }
424 :
425 1348 : if (mat->group == Material::Group::WindowBlind) {
426 2 : ExtBlind = true;
427 2 : ShadeLayNum = 1;
428 2 : BlNum = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)))->BlindDataPtr;
429 1346 : } else if (state.dataMaterial->Material(thisConstruct.LayerPoint(TotLay))->group == Material::Group::WindowBlind) {
430 12 : IntBlind = true;
431 12 : ShadeLayNum = TotLay;
432 12 : BlNum = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)))->BlindDataPtr;
433 1334 : } else if (thisConstruct.TotLayers == 5) {
434 68 : if (state.dataMaterial->Material(thisConstruct.LayerPoint(3))->group == Material::Group::WindowBlind) {
435 2 : BGBlind = true;
436 2 : ShadeLayNum = 3;
437 2 : BlNum =
438 2 : dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)))->BlindDataPtr;
439 : }
440 1266 : } else if (thisConstruct.TotLayers == 7) {
441 8 : if (state.dataMaterial->Material(thisConstruct.LayerPoint(5))->group == Material::Group::WindowBlind) {
442 1 : BGBlind = true;
443 1 : ShadeLayNum = 5;
444 1 : BlNum =
445 1 : dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)))->BlindDataPtr;
446 : }
447 : }
448 :
449 1348 : if (mat->group == Material::Group::Screen) {
450 2 : ShadeLayNum = 1;
451 2 : ExtScreen = true;
452 : }
453 :
454 1348 : ScreenOn = ExtScreen;
455 1348 : BlindOn = IntBlind || ExtBlind || BGBlind;
456 1348 : ShadeOn = IntShade || ExtShade || BGShade;
457 1348 : wm->BGFlag = BGBlind || BGShade;
458 :
459 : // For construction with interior or exterior shade, get shade thermal absorptance (emissivity)
460 : // (accounting for inter-reflection with glazing) and correct the inside glass InsideAbsorpThermal
461 : // for presence of interior shade. Assumes inner and outer glass layers have zero thermal transmittance.
462 :
463 1348 : if (IntShade || ExtShade || ExtScreen) {
464 29 : ShadeLayPtr = thisConstruct.LayerPoint(ShadeLayNum);
465 29 : auto const *matShade = state.dataMaterial->Material(ShadeLayPtr);
466 29 : if (ExtScreen) {
467 2 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(matShade);
468 2 : assert(matScreen != nullptr);
469 2 : TauShIR = matScreen->DfTrans;
470 : } else {
471 27 : TauShIR = matShade->TransThermal;
472 : }
473 29 : EpsShIR = matShade->AbsorpThermal;
474 29 : RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
475 29 : if (ExtShade || ExtScreen) { // Exterior shade or screen
476 5 : EpsGlIR = state.dataMaterial->Material(thisConstruct.LayerPoint(2))->AbsorpThermalFront;
477 : } else { // Interior shade
478 24 : EpsGlIR = state.dataMaterial->Material(thisConstruct.LayerPoint(TotLay - 1))->AbsorpThermalBack;
479 : }
480 29 : RhoGlIR = max(0.0, 1.0 - EpsGlIR);
481 29 : thisConstruct.ShadeAbsorpThermal = EpsShIR * (1.0 + TauShIR * RhoGlIR / (1.0 - RhoShIR * RhoGlIR));
482 29 : if (IntShade) thisConstruct.InsideAbsorpThermal *= TauShIR / (1.0 - RhoShIR * RhoGlIR);
483 : }
484 :
485 : // From the individual glass layer properties, get the glazing system optical properties
486 : // for BARE GLASS (i.e., interior, exterior or between-glass shade or blind, or exterior screen, if present, not in place).
487 : // Get one set of system properties for solar incident on front of
488 : // window and a second set for solar incident on back of window. (The back-incident
489 : // properties are used with interior short-wave radiation striking the window from inside.)
490 :
491 : // After the front and back system optical properties are calculated for bare glass,
492 : // a correction is made for the effect of a shade, screen or blind if one of these
493 : // is present in the construction.
494 :
495 1348 : NGlass = thisConstruct.TotGlassLayers;
496 :
497 : //--------------------------------------------------------------------------------------------
498 : // Front calculation (solar incident from outside of room); bare glass portion of construction
499 : //--------------------------------------------------------------------------------------------
500 :
501 1348 : lquasi = false;
502 1348 : AllGlassIsSpectralAverage = true;
503 1348 : int constexpr TotalIPhi = 10;
504 1348 : wm->LayerNum = {0};
505 :
506 : // Loop over glass layers in the construction
507 3361 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
508 2013 : LayNum = 1 + 2 * (IGlass - 1);
509 2013 : if (ExtShade || ExtBlind || ExtScreen) LayNum = 2 + 2 * (IGlass - 1);
510 2013 : if (BGShade || BGBlind) {
511 12 : LayNum = 1;
512 12 : if (NGlass == 2) {
513 6 : if (IGlass == 2) LayNum = 5;
514 : } else { // NGlass = 3
515 6 : if (IGlass == 2) LayNum = 3;
516 6 : if (IGlass == 3) LayNum = 7;
517 : }
518 : }
519 :
520 2013 : wm->LayerNum[IGlass - 1] = LayNum;
521 2013 : LayPtr = thisConstruct.LayerPoint(LayNum);
522 2013 : auto *thisMaterial = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(LayPtr));
523 2013 : assert(thisMaterial != nullptr);
524 2013 : SpecDataNum = thisMaterial->GlassSpectralDataPtr;
525 2013 : if (SpecDataNum != 0) {
526 213 : if (!wm->BGFlag) AllGlassIsSpectralAverage = false;
527 :
528 : // Get the spectral data for the transmittance, front reflectance and
529 : // back reflectance (all at normal incidence) for this layer.
530 : // In this case, "front" means incident from the outside and "back"
531 : // means incident from the inside.
532 213 : numptDAT = state.dataHeatBal->SpectralData(SpecDataNum).NumOfWavelengths;
533 213 : numpt[IGlass - 1] = numptDAT;
534 :
535 42312 : for (int ILam = 1; ILam <= numptDAT; ++ILam) {
536 42099 : wlt[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).WaveLength(ILam);
537 42099 : t[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).Trans(ILam);
538 42099 : if ((IGlass == 1 || (IGlass == 2 && StormWinConst)) && (!wm->BGFlag))
539 6549 : t[IGlass - 1][ILam - 1] *= thisMaterial->GlassTransDirtFactor;
540 42099 : rff[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).ReflFront(ILam);
541 42099 : rbb[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).ReflBack(ILam);
542 : }
543 :
544 : // If there is spectral data for between-glass shades or blinds, calc the average spectral properties for use.
545 213 : if (wm->BGFlag) {
546 : // Add warning message for the glazing defined with full spectral data.
547 0 : ShowWarningError(
548 : state,
549 0 : format(
550 : "Window glazing material \"{}\" was defined with full spectral data and has been converted to average spectral data",
551 0 : thisMaterial->Name));
552 0 : ShowContinueError(
553 : state,
554 0 : format("due to its use with between-glass shades or blinds of the window construction \"{}\".", thisConstruct.Name));
555 0 : ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage.");
556 0 : ShowContinueError(state,
557 : "If this material is also used in other window constructions without between-glass shades or blinds,");
558 0 : ShowContinueError(state,
559 : "then make a duplicate material (with new name) if you want to model those windows (and reference the new "
560 : "material) using the full spectral data.");
561 : // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack
562 : // assuming wlt same as wle
563 0 : wm->tmpTrans = solarSpectrumAverage(state, t[0]);
564 0 : wm->tmpReflectSolBeamFront = solarSpectrumAverage(state, rff[0]);
565 0 : wm->tmpReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]);
566 :
567 : // visible properties
568 0 : wm->tmpTransVis = visibleSpectrumAverage(state, t[0]);
569 0 : wm->tmpReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]);
570 0 : wm->tmpReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]);
571 :
572 : // set this material to average spectral data
573 0 : thisMaterial->GlassSpectralDataPtr = 0;
574 0 : thisMaterial->Trans = wm->tmpTrans;
575 0 : thisMaterial->TransVis = wm->tmpTransVis;
576 0 : thisMaterial->ReflectSolBeamFront = wm->tmpReflectSolBeamFront;
577 0 : thisMaterial->ReflectSolBeamBack = wm->tmpReflectSolBeamBack;
578 0 : thisMaterial->ReflectVisBeamFront = wm->tmpReflectVisBeamFront;
579 0 : thisMaterial->ReflectVisBeamBack = wm->tmpReflectVisBeamBack;
580 0 : SpecDataNum = 0;
581 : }
582 : }
583 :
584 2013 : if (SpecDataNum == 0 && !thisMaterial->GlassSpectralAndAngle) { // No spectral data for this layer; use spectral average values
585 1798 : lquasi = true;
586 1798 : numpt[IGlass - 1] = 2;
587 1798 : t[IGlass - 1][0] = thisMaterial->Trans;
588 1798 : if (IGlass == 1 || (IGlass == 2 && StormWinConst)) t[IGlass - 1][0] *= thisMaterial->GlassTransDirtFactor;
589 1798 : t[IGlass - 1][1] = thisMaterial->TransVis;
590 1798 : if (IGlass == 1 || (IGlass == 2 && StormWinConst)) t[IGlass - 1][1] *= thisMaterial->GlassTransDirtFactor;
591 1798 : rff[IGlass - 1][0] = thisMaterial->ReflectSolBeamFront;
592 1798 : rbb[IGlass - 1][0] = thisMaterial->ReflectSolBeamBack;
593 1798 : rff[IGlass - 1][1] = thisMaterial->ReflectVisBeamFront;
594 1798 : rbb[IGlass - 1][1] = thisMaterial->ReflectVisBeamBack;
595 : }
596 2013 : if (thisMaterial->GlassSpectralAndAngle) {
597 2 : if (!wm->BGFlag) AllGlassIsSpectralAverage = false;
598 2 : numptDAT = wm->wle.size();
599 2 : numpt[IGlass - 1] = numptDAT;
600 2 : if (wm->BGFlag) {
601 : // 5/16/2012 CR 8793. Add warning message for the glazing defined with full spectral data.
602 0 : ShowWarningError(state,
603 0 : format("Window glazing material \"{}\" was defined with full spectral and angular data and has been "
604 : "converted to average spectral data",
605 0 : thisMaterial->Name));
606 0 : ShowContinueError(
607 : state,
608 0 : format("due to its use with between-glass shades or blinds of the window construction \"{}\".", thisConstruct.Name));
609 0 : ShowContinueError(state, "All occurrences of this glazing material will be modeled as SpectralAverage.");
610 0 : ShowContinueError(state,
611 : "If this material is also used in other window constructions without between-glass shades or blinds,");
612 0 : ShowContinueError(state,
613 : "then make a duplicate material (with new name) if you want to model those windows (and reference the new "
614 : "material) using the full spectral data.");
615 : // calc Trans, TransVis, ReflectSolBeamFront, ReflectSolBeamBack, ReflectVisBeamFront, ReflectVisBeamBack
616 : // assuming wlt same as wle
617 0 : for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
618 0 : Real64 lam = wm->wle[ILam - 1];
619 0 : wlt[IGlass - 1][ILam - 1] = lam;
620 0 : t[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngTransDataPtr, 0.0, lam);
621 0 : rff[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngFRefleDataPtr, 0.0, lam);
622 0 : rbb[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngBRefleDataPtr, 0.0, lam);
623 : }
624 0 : wm->tmpTrans = solarSpectrumAverage(state, t[0]);
625 0 : wm->tmpReflectSolBeamFront = solarSpectrumAverage(state, rff[0]);
626 0 : wm->tmpReflectSolBeamBack = solarSpectrumAverage(state, rbb[0]);
627 :
628 : // visible properties
629 0 : wm->tmpTransVis = visibleSpectrumAverage(state, t[0]);
630 0 : wm->tmpReflectVisBeamFront = visibleSpectrumAverage(state, rff[0]);
631 0 : wm->tmpReflectVisBeamBack = visibleSpectrumAverage(state, rbb[0]);
632 :
633 : // set this material to average spectral data
634 0 : thisMaterial->GlassSpectralAndAngle = false;
635 0 : thisMaterial->Trans = wm->tmpTrans;
636 0 : thisMaterial->TransVis = wm->tmpTransVis;
637 0 : thisMaterial->ReflectSolBeamFront = wm->tmpReflectSolBeamFront;
638 0 : thisMaterial->ReflectSolBeamBack = wm->tmpReflectSolBeamBack;
639 0 : thisMaterial->ReflectVisBeamFront = wm->tmpReflectVisBeamFront;
640 0 : thisMaterial->ReflectVisBeamBack = wm->tmpReflectVisBeamBack;
641 0 : SpecDataNum = 0;
642 : }
643 : }
644 : } // End of loop over glass layers in the construction for front calculation
645 :
646 : if (TotalIPhi > maxIncidentAngles) {
647 : ShowSevereError(state,
648 : format("WindowManage::InitGlassOpticalCalculations = {}, Invalid maximum value of common incidet angles = {}.",
649 : thisConstruct.Name,
650 : TotalIPhi));
651 : ShowContinueError(
652 : state,
653 : format("The maximum number of incident angles for each construct is {}. Please rearrange the dataset.", maxIncidentAngles));
654 : ShowFatalError(state, "Errors found getting inputs. Previous error(s) cause program termination.");
655 : }
656 :
657 : // Loop over incidence angle from 0 to 90 deg in 10 deg increments.
658 : // Get glass layer properties, then glazing system properties (which include the
659 : // effect of inter-reflection among glass layers) at each incidence angle.
660 :
661 14828 : for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
662 : // 10 degree increment for incident angle is only value for a construction without a layer = SpectralAndAngle
663 13480 : Phi = double(IPhi - 1) * 10.0;
664 13480 : CosPhi = std::cos(Phi * Constant::DegToRadians);
665 13480 : if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
666 :
667 : // For each wavelength, get glass layer properties at this angle of incidence
668 : // from properties at normal incidence
669 33610 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
670 20130 : LayPtr = thisConstruct.LayerPoint(wm->LayerNum[IGlass - 1]);
671 20130 : auto *thisMaterial = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(LayPtr));
672 20130 : assert(thisMaterial != nullptr);
673 20130 : if (!thisMaterial->GlassSpectralAndAngle) {
674 477060 : for (int ILam = 1; ILam <= numpt[IGlass - 1]; ++ILam) {
675 456950 : TransAndReflAtPhi(CosPhi,
676 456950 : t[IGlass - 1][ILam - 1],
677 456950 : rff[IGlass - 1][ILam - 1],
678 456950 : rbb[IGlass - 1][ILam - 1],
679 456950 : tPhi[IGlass - 1][ILam - 1],
680 456950 : rfPhi[IGlass - 1][ILam - 1],
681 456950 : rbPhi[IGlass - 1][ILam - 1],
682 456950 : wm->lSimpleGlazingSystem,
683 456950 : wm->SimpleGlazingSHGC,
684 456950 : wm->SimpleGlazingU);
685 : }
686 : } else {
687 2160 : for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
688 2140 : Real64 lam = wm->wle[ILam - 1];
689 2140 : wlt[IGlass - 1][ILam - 1] = lam;
690 2140 : tPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngTransDataPtr, Phi, lam);
691 2140 : rfPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngFRefleDataPtr, Phi, lam);
692 2140 : rbPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngBRefleDataPtr, Phi, lam);
693 : }
694 : }
695 : // For use with between-glass shade/blind, save angular properties of isolated glass
696 : // for case that all glass layers were input with spectral-average properties
697 : // only used by between-glass shades or blinds
698 20130 : if (AllGlassIsSpectralAverage) {
699 17620 : tBareSolPhi(IGlass, IPhi) = tPhi[IGlass - 1][0];
700 17620 : tBareVisPhi(IGlass, IPhi) = tPhi[IGlass - 1][1];
701 17620 : rfBareSolPhi(IGlass, IPhi) = rfPhi[IGlass - 1][0];
702 17620 : rfBareVisPhi(IGlass, IPhi) = rfPhi[IGlass - 1][1];
703 17620 : rbBareSolPhi(IGlass, IPhi) = rbPhi[IGlass - 1][0];
704 17620 : rbBareVisPhi(IGlass, IPhi) = rbPhi[IGlass - 1][1];
705 17620 : afBareSolPhi(IGlass, IPhi) = max(0.0, 1.0 - (tBareSolPhi(IGlass, IPhi) + rfBareSolPhi(IGlass, IPhi)));
706 17620 : abBareSolPhi(IGlass, IPhi) = max(0.0, 1.0 - (tBareSolPhi(IGlass, IPhi) + rbBareSolPhi(IGlass, IPhi)));
707 : }
708 : }
709 :
710 : // For each wavelength in the solar spectrum, calculate system properties
711 : // stPhi, srfPhi, srbPhi and saPhi at this angle of incidence.
712 : // In the following the argument "1" indicates that spectral average solar values
713 : // should be used for layers without spectral data.
714 :
715 13480 : std::array<Real64, nume> stPhi = {0.0}; // Glazing system transmittance at angle of incidence for each wavelength in wle
716 13480 : std::array<Real64, nume> srfPhi = {0.0}; // Glazing system front reflectance at angle of incidence for each wavelength in wle
717 13480 : std::array<Real64, nume> srbPhi = {0.0}; // Glazing system back reflectance at angle of incidence for each wavelenth in wle
718 : // For each layer, glazing system absorptance at angle of incidence
719 26960 : Array2D<Real64> saPhi(maxGlassLayers, nume, 0.0);
720 :
721 13480 : SystemSpectralPropertiesAtPhi(state, 1, NGlass, 0.0, 2.54, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
722 :
723 : // Get solar properties of system by integrating over solar irradiance spectrum.
724 : // For now it is assumed that the exterior and interior irradiance spectra are the same.
725 13480 : tsolPhi(IPhi) = solarSpectrumAverage(state, stPhi);
726 13480 : rfsolPhi(IPhi) = solarSpectrumAverage(state, srfPhi);
727 13480 : rbsolPhi(IPhi) = solarSpectrumAverage(state, srbPhi);
728 :
729 33610 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
730 2174040 : for (int ILam = 1; ILam <= nume; ++ILam) {
731 2153910 : sabsPhi(ILam) = saPhi(IGlass, ILam);
732 : }
733 20130 : solabsPhi(IGlass, IPhi) = solarSpectrumAverage(state, sabsPhi);
734 : }
735 :
736 : // Get visible properties of system by integrating over solar irradiance
737 : // spectrum weighted by photopic response.
738 : // Need to redo the calculation of system spectral properties here only if
739 : // one or more glass layers have no spectral data (lquasi = .TRUE.); in this
740 : // case the spectral average visible properties will be used for the layers
741 : // without spectral data, as indicated by the argument "2".
742 :
743 13480 : if (lquasi) SystemSpectralPropertiesAtPhi(state, 2, NGlass, 0.37, 0.78, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
744 13480 : tvisPhi(IPhi) = visibleSpectrumAverage(state, stPhi);
745 13480 : rfvisPhi(IPhi) = visibleSpectrumAverage(state, srfPhi);
746 13480 : rbvisPhi(IPhi) = visibleSpectrumAverage(state, srbPhi);
747 :
748 13480 : } // End of loop over incidence angles for front calculation
749 :
750 : // only used by between-glass shades or blinds
751 1348 : if (AllGlassIsSpectralAverage) {
752 3013 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
753 1762 : W5LsqFit(CosPhiIndepVar, tBareSolPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.tBareSolCoef(IGlass));
754 1762 : W5LsqFit(CosPhiIndepVar, tBareVisPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.tBareVisCoef(IGlass));
755 1762 : W5LsqFit(CosPhiIndepVar, rfBareSolPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.rfBareSolCoef(IGlass));
756 1762 : W5LsqFit(CosPhiIndepVar, rfBareVisPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.rfBareVisCoef(IGlass));
757 1762 : W5LsqFit(CosPhiIndepVar, rbBareSolPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.rbBareSolCoef(IGlass));
758 1762 : W5LsqFit(CosPhiIndepVar, rbBareVisPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.rbBareVisCoef(IGlass));
759 1762 : W5LsqFit(CosPhiIndepVar, afBareSolPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.afBareSolCoef(IGlass));
760 1762 : W5LsqFit(CosPhiIndepVar, abBareSolPhi(IGlass, _), 6, 1, TotalIPhi, thisConstruct.abBareSolCoef(IGlass));
761 : }
762 : }
763 :
764 1348 : thisConstruct.ReflectSolDiffFront = DiffuseAverage(rfsolPhi);
765 1348 : thisConstruct.ReflectSolDiffBack = DiffuseAverage(rbsolPhi);
766 1348 : thisConstruct.ReflectVisDiffFront = DiffuseAverage(rfvisPhi);
767 1348 : thisConstruct.ReflectVisDiffBack = DiffuseAverage(rbvisPhi);
768 :
769 1348 : tsolDiff = DiffuseAverage(tsolPhi);
770 1348 : tvisDiff = DiffuseAverage(tvisPhi);
771 1348 : thisConstruct.TransDiff = tsolDiff;
772 1348 : thisConstruct.TransDiffVis = tvisDiff;
773 3361 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
774 2013 : solabsPhiLay({1, TotalIPhi}) = solabsPhi(IGlass, {1, TotalIPhi});
775 2013 : solabsDiff(IGlass) = DiffuseAverage(solabsPhiLay);
776 2013 : thisConstruct.AbsDiff(IGlass) = solabsDiff(IGlass);
777 :
778 : // For use with between-glass shade/blind, get diffuse properties of isolated glass for case when
779 : // all glass layers were input with spectral-average properties
780 : // only used by between-glass shades or blinds
781 2013 : if (AllGlassIsSpectralAverage) {
782 1762 : thisConstruct.tBareSolDiff(IGlass) = DiffuseAverage(tBareSolPhi(IGlass, {1, TotalIPhi}));
783 1762 : thisConstruct.tBareVisDiff(IGlass) = DiffuseAverage(tBareVisPhi(IGlass, {1, TotalIPhi}));
784 1762 : thisConstruct.rfBareSolDiff(IGlass) = DiffuseAverage(rfBareSolPhi(IGlass, {1, TotalIPhi}));
785 1762 : thisConstruct.rfBareVisDiff(IGlass) = DiffuseAverage(rfBareVisPhi(IGlass, {1, TotalIPhi}));
786 1762 : thisConstruct.rbBareSolDiff(IGlass) = DiffuseAverage(rbBareSolPhi(IGlass, {1, TotalIPhi}));
787 1762 : thisConstruct.rbBareVisDiff(IGlass) = DiffuseAverage(rbBareVisPhi(IGlass, {1, TotalIPhi}));
788 1762 : thisConstruct.afBareSolDiff(IGlass) = max(0.0, 1.0 - (thisConstruct.tBareSolDiff(IGlass) + thisConstruct.rfBareSolDiff(IGlass)));
789 1762 : thisConstruct.abBareSolDiff(IGlass) = max(0.0, 1.0 - (thisConstruct.tBareSolDiff(IGlass) + thisConstruct.rbBareSolDiff(IGlass)));
790 : }
791 : }
792 :
793 : //------------------------------------------------------------------------------------------
794 : // Back calculation (solar incident from inside of room); bare glass portion of construction
795 : //------------------------------------------------------------------------------------------
796 :
797 1348 : lquasi = false;
798 1348 : wm->LayerNum = {0};
799 :
800 : // Loop over glass layers in the construction.
801 3361 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
802 2013 : LayNum = 1 + (NGlass - IGlass) * 2;
803 2013 : if (ExtShade || ExtBlind || ExtScreen) LayNum = 2 + (NGlass - IGlass) * 2;
804 2013 : if (BGShade || BGBlind) {
805 12 : if (NGlass == 2) {
806 6 : if (IGlass == 1) LayNum = 5;
807 6 : if (IGlass == 2) LayNum = 1;
808 : } else { // NGlass = 3
809 6 : if (IGlass == 1) LayNum = 7;
810 6 : if (IGlass == 2) LayNum = 3;
811 6 : if (IGlass == 3) LayNum = 1;
812 : }
813 : }
814 2013 : wm->LayerNum[IGlass - 1] = LayNum;
815 2013 : LayPtr = thisConstruct.LayerPoint(LayNum);
816 2013 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(LayPtr));
817 2013 : assert(thisMaterial != nullptr);
818 :
819 2013 : SpecDataNum = thisMaterial->GlassSpectralDataPtr;
820 2013 : if (SpecDataNum != 0) {
821 :
822 : // Get the spectral data for the transmittance, front reflectance and
823 : // back reflectance (all at normal incidence) for this layer.
824 : // In this case, "front" means incident from the inside and "back"
825 : // means incident from the outside.
826 :
827 213 : numptDAT = state.dataHeatBal->SpectralData(SpecDataNum).NumOfWavelengths;
828 213 : numpt[IGlass - 1] = numptDAT;
829 :
830 42312 : for (int ILam = 1; ILam <= numptDAT; ++ILam) {
831 42099 : wlt[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).WaveLength(ILam);
832 42099 : t[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).Trans(ILam);
833 42099 : if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst))
834 6549 : t[IGlass - 1][ILam - 1] *= thisMaterial->GlassTransDirtFactor;
835 42099 : rff[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).ReflBack(ILam);
836 42099 : rbb[IGlass - 1][ILam - 1] = state.dataHeatBal->SpectralData(SpecDataNum).ReflFront(ILam);
837 : }
838 :
839 : } else { // No spectral data for this layer; use spectral average values
840 1800 : if (!thisMaterial->GlassSpectralAndAngle) {
841 1798 : lquasi = true;
842 1798 : numpt[IGlass - 1] = 2;
843 1798 : t[IGlass - 1][0] = thisMaterial->Trans;
844 1798 : if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) t[IGlass - 1][0] *= thisMaterial->GlassTransDirtFactor;
845 1798 : t[IGlass - 1][1] = thisMaterial->TransVis;
846 1798 : if (IGlass == NGlass || (IGlass == (NGlass - 1) && StormWinConst)) t[IGlass - 1][1] *= thisMaterial->GlassTransDirtFactor;
847 1798 : rff[IGlass - 1][0] = thisMaterial->ReflectSolBeamBack;
848 1798 : rbb[IGlass - 1][0] = thisMaterial->ReflectSolBeamFront;
849 1798 : rff[IGlass - 1][1] = thisMaterial->ReflectVisBeamBack;
850 1798 : rbb[IGlass - 1][1] = thisMaterial->ReflectVisBeamFront;
851 : }
852 : }
853 2013 : if (thisMaterial->GlassSpectralAndAngle) {
854 2 : numptDAT = wm->wle.size();
855 2 : numpt[IGlass - 1] = numptDAT;
856 : }
857 : } // End of loop over glass layers in the construction for back calculation
858 :
859 : // Loop over incidence angle from 0 to 90 deg in 10 deg increments.
860 : // Get bare glass layer properties, then glazing system properties at each incidence angle.
861 : // The glazing system properties include the effect of inter-reflection among glass layers,
862 : // but exclude the effect of a shade or blind if present in the construction.
863 : // When a construction has a layer = SpectralAndAngle, the 10 degree increment will be overridden.
864 14828 : for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
865 13480 : Phi = double(IPhi - 1) * 10.0;
866 13480 : CosPhi = std::cos(Phi * Constant::DegToRadians);
867 13480 : if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
868 :
869 : // For each wavelength, get glass layer properties at this angle of incidence
870 : // from properties at normal incidence
871 33610 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
872 20130 : LayPtr = thisConstruct.LayerPoint(wm->LayerNum[IGlass - 1]);
873 20130 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(LayPtr));
874 20130 : assert(thisMaterial != nullptr);
875 20130 : if (!thisMaterial->GlassSpectralAndAngle) {
876 477060 : for (int ILam = 1; ILam <= numpt[IGlass - 1]; ++ILam) {
877 :
878 456950 : TransAndReflAtPhi(CosPhi,
879 456950 : t[IGlass - 1][ILam - 1],
880 456950 : rff[IGlass - 1][ILam - 1],
881 456950 : rbb[IGlass - 1][ILam - 1],
882 456950 : tPhi[IGlass - 1][ILam - 1],
883 456950 : rfPhi[IGlass - 1][ILam - 1],
884 456950 : rbPhi[IGlass - 1][ILam - 1],
885 456950 : wm->lSimpleGlazingSystem,
886 456950 : wm->SimpleGlazingSHGC,
887 456950 : wm->SimpleGlazingU);
888 : }
889 : } else {
890 2160 : for (int ILam = 1; ILam <= (int)wm->wle.size(); ++ILam) {
891 2140 : Real64 lam = wm->wle[ILam - 1];
892 2140 : wlt[IGlass - 1][ILam - 1] = lam;
893 2140 : tPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngTransDataPtr, Phi, lam);
894 2140 : rfPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngFRefleDataPtr, Phi, lam);
895 2140 : rbPhi[IGlass - 1][ILam - 1] = Curve::CurveValue(state, thisMaterial->GlassSpecAngBRefleDataPtr, Phi, lam);
896 : }
897 : }
898 : }
899 :
900 : // For each wavelength in the solar spectrum, calculate system properties
901 : // stPhi, srfPhi, srbPhi and saPhi at this angle of incidence
902 13480 : std::array<Real64, nume> stPhi = {0.0}; // Glazing system transmittance at angle of incidence for each wavelength in wle
903 13480 : std::array<Real64, nume> srfPhi = {0.0}; // Glazing system front reflectance at angle of incidence for each wavelength in wle
904 13480 : std::array<Real64, nume> srbPhi = {0.0}; // Glazing system back reflectance at angle of incidence for each wavelenth in wle
905 : // For each layer, glazing system absorptance at angle of incidence
906 26960 : Array2D<Real64> saPhi(maxGlassLayers, nume, 0.0);
907 :
908 13480 : SystemSpectralPropertiesAtPhi(state, 1, NGlass, 0.0, 2.54, numpt, wlt, tPhi, rfPhi, rbPhi, stPhi, srfPhi, srbPhi, saPhi);
909 :
910 : // Get back absorptance properties of system by integrating over solar irradiance spectrum.
911 : // For now it is assumed that the exterior and interior irradiance spectra are the same.
912 :
913 33610 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
914 2174040 : for (int j = 1; j <= nume; ++j) {
915 2153910 : sabsPhi(j) = saPhi(IGlass, j);
916 : }
917 20130 : solabsBackPhi(IGlass, IPhi) = solarSpectrumAverage(state, sabsPhi);
918 : }
919 :
920 13480 : } // End of loop over incidence angles for back calculation
921 :
922 3361 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
923 2013 : IGlassBack = NGlass - IGlass + 1;
924 2013 : thisConstruct.AbsDiffBack(IGlass) = DiffuseAverage(solabsBackPhi(IGlassBack, {1, 10}));
925 : }
926 :
927 : //-----------------------------------------------------------------------
928 : // Correction for effect of shade, screen or blind if present in the construction
929 : //-----------------------------------------------------------------------
930 :
931 : // For construction with shade, screen or blind, get system shading device absorptance
932 : // and correct the system glass layer absorptances for the effect of reflection
933 : // and transmission by shade, screen or blind. Get system reflectance (front and back,
934 : // solar and visible)
935 :
936 1348 : if (ShadeOn || BlindOn || ScreenOn) {
937 :
938 : // Solar and visible properties of isolated shade or blind
939 : // (Note: for shades or screen we go through the following loop over slat angles only once.)
940 :
941 48 : Real64 const tsolDiff_2(pow_2(tsolDiff));
942 48 : Real64 const tvisDiff_2(pow_2(tvisDiff));
943 591 : for (int ISlatAng = 1; ISlatAng <= Material::MaxSlatAngs; ++ISlatAng) {
944 :
945 588 : if (ShadeOn) {
946 : auto const *thisMaterialSh =
947 29 : dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)));
948 29 : assert(thisMaterialSh != nullptr);
949 29 : ShadeAbs = thisMaterialSh->AbsorpSolar;
950 29 : ShadeTrans = thisMaterialSh->Trans;
951 29 : ShadeTransVis = thisMaterialSh->TransVis;
952 29 : ShadeRefl = thisMaterialSh->ReflectShade;
953 29 : ShadeReflVis = thisMaterialSh->ReflectShadeVis;
954 29 : rsh = ShadeRefl;
955 29 : rshv = ShadeReflVis;
956 29 : tsh = ShadeTrans;
957 29 : tshv = ShadeTransVis;
958 29 : ash = ShadeAbs;
959 559 : } else if (IntBlind || ExtBlind) {
960 554 : auto const &blind = state.dataMaterial->Blind(BlNum);
961 554 : ShadeTrans = blind.SolFrontDiffDiffTrans(ISlatAng);
962 554 : ShadeTransGnd = blind.SolFrontDiffDiffTransGnd(ISlatAng);
963 554 : ShadeTransSky = blind.SolFrontDiffDiffTransSky(ISlatAng);
964 554 : ShadeTransVis = blind.VisFrontDiffDiffTrans(ISlatAng);
965 554 : if (IntBlind) { // Interior blind
966 372 : ShadeAbs = blind.SolFrontDiffAbs(ISlatAng);
967 372 : ShadeRefl = blind.SolFrontDiffDiffRefl(ISlatAng);
968 372 : ShadeReflGnd = blind.SolFrontDiffDiffReflGnd(ISlatAng);
969 372 : ShadeReflSky = blind.SolFrontDiffDiffReflSky(ISlatAng);
970 372 : ShadeReflVis = blind.VisFrontDiffDiffRefl(ISlatAng);
971 : } else { // Exterior blind
972 182 : ShadeAbs = blind.SolBackDiffAbs(ISlatAng);
973 182 : ShadeRefl = blind.SolBackDiffDiffRefl(ISlatAng);
974 182 : ShadeReflVis = blind.VisBackDiffDiffRefl(ISlatAng);
975 : }
976 559 : } else if (BGBlind) {
977 3 : auto const &blind = state.dataMaterial->Blind(BlNum);
978 3 : tsh = blind.SolFrontDiffDiffTrans(ISlatAng);
979 3 : tshGnd = blind.SolFrontDiffDiffTransGnd(ISlatAng);
980 3 : tshSky = blind.SolFrontDiffDiffTransSky(ISlatAng);
981 3 : tshv = blind.VisFrontDiffDiffTrans(ISlatAng);
982 3 : rfsh = blind.SolFrontDiffDiffRefl(ISlatAng);
983 3 : rfshGnd = blind.SolFrontDiffDiffReflGnd(ISlatAng);
984 3 : rfshSky = blind.SolFrontDiffDiffReflSky(ISlatAng);
985 3 : rfshv = blind.VisFrontDiffDiffRefl(ISlatAng);
986 3 : rbsh = blind.SolBackDiffDiffRefl(ISlatAng);
987 3 : rbshv = blind.VisBackDiffDiffRefl(ISlatAng);
988 3 : afsh = blind.SolFrontDiffAbs(ISlatAng);
989 3 : afshGnd = blind.SolFrontDiffAbsGnd(ISlatAng);
990 3 : afshSky = blind.SolFrontDiffAbsSky(ISlatAng);
991 3 : absh = blind.SolBackDiffAbs(ISlatAng);
992 2 : } else if (ScreenOn) {
993 : // diffuse screen properties are calculated during initialization (quarter-hemispherical integration of beam properties)
994 : auto const *matScreen =
995 2 : dynamic_cast<Material::MaterialScreen const *>(state.dataMaterial->Material(thisConstruct.LayerPoint(ShadeLayNum)));
996 2 : assert(matScreen != nullptr);
997 :
998 2 : ShadeAbs = matScreen->DfAbs;
999 2 : ShadeTrans = matScreen->DfTrans;
1000 2 : ShadeTransVis = matScreen->DfTransVis;
1001 2 : ShadeRefl = matScreen->DfRef;
1002 2 : ShadeReflVis = matScreen->DfRefVis;
1003 2 : rsh = ShadeRefl;
1004 2 : rshv = ShadeReflVis;
1005 2 : tsh = ShadeTrans;
1006 2 : tshv = ShadeTransVis;
1007 2 : ash = ShadeAbs;
1008 : }
1009 :
1010 : // Correction factors for inter-reflections between glass and shading device
1011 :
1012 588 : if (ExtShade || ExtBlind || ExtScreen) {
1013 187 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * thisConstruct.ReflectSolDiffFront);
1014 187 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * thisConstruct.ReflectVisDiffFront);
1015 401 : } else if (IntShade || IntBlind) {
1016 396 : ShadeReflFac = 1.0 / (1.0 - ShadeRefl * thisConstruct.ReflectSolDiffBack);
1017 396 : ShadeReflFacVis = 1.0 / (1.0 - ShadeReflVis * thisConstruct.ReflectVisDiffBack);
1018 : }
1019 :
1020 588 : if (ExtShade || ExtBlind || ExtScreen) { // Exterior shade or blind
1021 :
1022 : // Front incident solar, beam, exterior shade, screen or blind
1023 :
1024 187 : if (ExtShade) {
1025 33 : for (int IPhi = 1; IPhi <= 10; ++IPhi) {
1026 80 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1027 50 : solabsPhi(IGlass, IPhi) = ShadeTrans * solabsDiff(IGlass) * ShadeReflFac;
1028 : }
1029 30 : tsolPhi(IPhi) = ShadeTrans * ShadeReflFac * tsolDiff;
1030 30 : tvisPhi(IPhi) = ShadeTransVis * ShadeReflFacVis * tvisDiff;
1031 30 : solabsShadePhi(IPhi) = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffFront);
1032 : }
1033 : }
1034 :
1035 : // Front incident solar, diffuse, exterior shade/screen/blind
1036 :
1037 377 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1038 190 : if (ExtBlind) {
1039 182 : thisConstruct.BlAbsDiff(ISlatAng, IGlass) = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
1040 182 : thisConstruct.BlAbsDiffGnd(ISlatAng, IGlass) = ShadeTransGnd * ShadeReflFac * solabsDiff(IGlass);
1041 182 : thisConstruct.BlAbsDiffSky(ISlatAng, IGlass) = ShadeTransSky * ShadeReflFac * solabsDiff(IGlass);
1042 : }
1043 190 : if (ExtShade || ExtScreen) thisConstruct.AbsDiff(IGlass) = ShadeTrans * ShadeReflFac * solabsDiff(IGlass);
1044 : }
1045 187 : if (ExtBlind) {
1046 182 : auto const &blind = state.dataMaterial->Blind(BlNum);
1047 364 : thisConstruct.AbsDiffBlind(ISlatAng) =
1048 182 : blind.SolFrontDiffAbs(ISlatAng) + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
1049 364 : thisConstruct.AbsDiffBlindGnd(ISlatAng) =
1050 182 : blind.SolFrontDiffAbsGnd(ISlatAng) + ShadeTransGnd * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
1051 364 : thisConstruct.AbsDiffBlindSky(ISlatAng) =
1052 182 : blind.SolFrontDiffAbsSky(ISlatAng) + ShadeTransSky * ShadeReflFac * thisConstruct.ReflectSolDiffFront * ShadeAbs;
1053 182 : thisConstruct.BlTransDiff(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTrans;
1054 182 : thisConstruct.BlTransDiffGnd(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTransGnd;
1055 182 : thisConstruct.BlTransDiffSky(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTransSky;
1056 182 : thisConstruct.BlTransDiffVis(ISlatAng) = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1057 364 : thisConstruct.BlReflectSolDiffFront(ISlatAng) =
1058 182 : ShadeRefl + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffFront * ShadeReflFac;
1059 182 : thisConstruct.BlReflectVisDiffFront(ISlatAng) =
1060 182 : ShadeReflVis + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffFront * ShadeReflFacVis;
1061 : }
1062 187 : if (ExtShade || ExtScreen) {
1063 5 : thisConstruct.AbsDiffShade = ShadeAbs * (1.0 + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffFront);
1064 5 : thisConstruct.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
1065 5 : thisConstruct.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1066 5 : thisConstruct.ReflectSolDiffFront = ShadeRefl + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffFront * ShadeReflFac;
1067 5 : thisConstruct.ReflectVisDiffFront =
1068 5 : ShadeReflVis + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffFront * ShadeReflFacVis;
1069 : }
1070 :
1071 : // Back incident solar, diffuse, exterior shade/blind
1072 :
1073 187 : if (ExtBlind) {
1074 364 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1075 182 : thisConstruct.BlAbsDiffBack(ISlatAng, IGlass) =
1076 182 : thisConstruct.AbsDiffBack(IGlass) + tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
1077 : }
1078 182 : thisConstruct.AbsDiffBackBlind(ISlatAng) = tsolDiff * ShadeReflFac * ShadeAbs;
1079 182 : thisConstruct.BlReflectSolDiffBack(ISlatAng) = thisConstruct.ReflectSolDiffBack + tsolDiff_2 * ShadeRefl * ShadeReflFac;
1080 182 : thisConstruct.BlReflectVisDiffBack(ISlatAng) =
1081 182 : thisConstruct.ReflectVisDiffBack + tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1082 : }
1083 187 : if (ExtShade || ExtScreen) {
1084 13 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1085 8 : thisConstruct.AbsDiffBack(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
1086 : }
1087 5 : thisConstruct.AbsDiffBackShade = tsolDiff * ShadeReflFac * ShadeAbs;
1088 5 : thisConstruct.ReflectSolDiffBack += tsolDiff_2 * ShadeRefl * ShadeReflFac;
1089 5 : thisConstruct.ReflectVisDiffBack += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1090 : }
1091 :
1092 : } // End check if exterior shade, screen or blind
1093 :
1094 588 : if (IntShade || IntBlind) { // Interior shade or blind
1095 :
1096 : // Front incident solar, beam, interior shade
1097 :
1098 396 : if (IntShade) {
1099 264 : for (int IPhi = 1; IPhi <= 10; ++IPhi) {
1100 620 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1101 380 : solabsPhi(IGlass, IPhi) += tsolPhi(IPhi) * ShadeRefl * ShadeReflFac * thisConstruct.AbsDiffBack(IGlass);
1102 : }
1103 240 : solabsShadePhi(IPhi) = tsolPhi(IPhi) * ShadeReflFac * ShadeAbs;
1104 240 : tsolPhi(IPhi) *= ShadeReflFac * ShadeTrans;
1105 240 : tvisPhi(IPhi) *= ShadeReflFacVis * ShadeTransVis;
1106 : }
1107 : } // End of check if interior shade
1108 :
1109 : // Front incident solar, diffuse, interior blind
1110 :
1111 396 : if (IntBlind) {
1112 744 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1113 744 : thisConstruct.BlAbsDiff(ISlatAng, IGlass) =
1114 372 : thisConstruct.AbsDiff(IGlass) + tsolDiff * ShadeRefl * ShadeReflFac * thisConstruct.AbsDiffBack(IGlass);
1115 744 : thisConstruct.BlAbsDiffGnd(ISlatAng, IGlass) =
1116 372 : thisConstruct.AbsDiff(IGlass) + tsolDiff * ShadeReflGnd * ShadeReflFac * thisConstruct.AbsDiffBack(IGlass);
1117 372 : thisConstruct.BlAbsDiffSky(ISlatAng, IGlass) =
1118 372 : thisConstruct.AbsDiff(IGlass) + tsolDiff * ShadeReflSky * ShadeReflFac * thisConstruct.AbsDiffBack(IGlass);
1119 : }
1120 :
1121 372 : auto const &blind = state.dataMaterial->Blind(BlNum);
1122 372 : thisConstruct.AbsDiffBlind(ISlatAng) = tsolDiff * ShadeReflFac * ShadeAbs;
1123 372 : thisConstruct.AbsDiffBlindGnd(ISlatAng) = tsolDiff * ShadeReflFac * blind.SolFrontDiffAbsGnd(ISlatAng);
1124 372 : thisConstruct.AbsDiffBlindSky(ISlatAng) = tsolDiff * ShadeReflFac * blind.SolFrontDiffAbsSky(ISlatAng);
1125 372 : thisConstruct.BlTransDiff(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTrans;
1126 372 : thisConstruct.BlTransDiffGnd(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTransGnd;
1127 372 : thisConstruct.BlTransDiffSky(ISlatAng) = tsolDiff * ShadeReflFac * ShadeTransSky;
1128 372 : thisConstruct.BlTransDiffVis(ISlatAng) = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1129 372 : thisConstruct.BlReflectSolDiffFront(ISlatAng) = thisConstruct.ReflectSolDiffFront + tsolDiff_2 * ShadeRefl * ShadeReflFac;
1130 744 : thisConstruct.BlReflectVisDiffFront(ISlatAng) =
1131 372 : thisConstruct.ReflectVisDiffFront + tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1132 :
1133 : // Back incident solar, diffuse, interior blind
1134 :
1135 744 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1136 372 : thisConstruct.BlAbsDiffBack(ISlatAng, IGlass) = thisConstruct.AbsDiffBack(IGlass) * ShadeTrans * ShadeReflFac;
1137 : }
1138 :
1139 744 : thisConstruct.AbsDiffBackBlind(ISlatAng) =
1140 372 : blind.SolBackDiffAbs(ISlatAng) + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffBack * ShadeAbs;
1141 744 : thisConstruct.BlReflectSolDiffBack(ISlatAng) =
1142 372 : blind.SolBackDiffDiffRefl(ISlatAng) + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffBack * ShadeReflFac;
1143 372 : thisConstruct.BlReflectVisDiffBack(ISlatAng) =
1144 372 : blind.VisBackDiffDiffRefl(ISlatAng) + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffBack * ShadeReflFacVis;
1145 : } // End of check if interior blind
1146 :
1147 : // Front incident solar, diffuse, interior shade
1148 :
1149 396 : if (IntShade) {
1150 62 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1151 38 : thisConstruct.AbsDiff(IGlass) += tsolDiff * ShadeRefl * ShadeReflFac * solabsDiff(IGlass);
1152 : }
1153 :
1154 24 : thisConstruct.AbsDiffShade = tsolDiff * ShadeReflFac * ShadeAbs;
1155 24 : thisConstruct.TransDiff = tsolDiff * ShadeReflFac * ShadeTrans;
1156 24 : thisConstruct.TransDiffVis = tvisDiff * ShadeReflFacVis * ShadeTransVis;
1157 24 : thisConstruct.ReflectSolDiffFront += tsolDiff_2 * ShadeRefl * ShadeReflFac;
1158 24 : thisConstruct.ReflectVisDiffFront += tvisDiff_2 * ShadeReflVis * ShadeReflFacVis;
1159 :
1160 : // Back incident solar, diffuse, interior shade
1161 :
1162 62 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1163 38 : thisConstruct.AbsDiffBack(IGlass) *= ShadeTrans * ShadeReflFac;
1164 : }
1165 :
1166 24 : thisConstruct.AbsDiffBackShade = ShadeAbs * (1 + ShadeTrans * ShadeReflFac * thisConstruct.ReflectSolDiffBack);
1167 24 : thisConstruct.ReflectSolDiffBack = ShadeRefl + pow_2(ShadeTrans) * thisConstruct.ReflectSolDiffBack * ShadeReflFac;
1168 24 : thisConstruct.ReflectVisDiffBack =
1169 24 : ShadeReflVis + pow_2(ShadeTransVis) * thisConstruct.ReflectVisDiffBack * ShadeReflFacVis;
1170 : } // End of check if interior shade
1171 :
1172 : } // End check if interior shade or blind
1173 :
1174 588 : if (BGShade || BGBlind) { // Between-glass shade/blind; assumed to be between glass #2 and glass #3
1175 :
1176 5 : tsh2 = pow_2(tsh);
1177 5 : tshv2 = pow_2(tshv);
1178 5 : td1 = thisConstruct.tBareSolDiff(1);
1179 5 : td2 = thisConstruct.tBareSolDiff(2);
1180 5 : td1v = thisConstruct.tBareVisDiff(1);
1181 5 : td2v = thisConstruct.tBareVisDiff(2);
1182 5 : afd1 = thisConstruct.afBareSolDiff(1);
1183 5 : afd2 = thisConstruct.afBareSolDiff(2);
1184 5 : abd1 = thisConstruct.abBareSolDiff(1);
1185 5 : abd2 = thisConstruct.abBareSolDiff(2);
1186 5 : rb1 = thisConstruct.rbBareSolDiff(1);
1187 5 : rb2 = thisConstruct.rbBareSolDiff(2);
1188 5 : rb1v = thisConstruct.rbBareVisDiff(1);
1189 5 : rb2v = thisConstruct.rbBareVisDiff(2);
1190 5 : rf1 = thisConstruct.rfBareSolDiff(1);
1191 5 : rf2 = thisConstruct.rfBareSolDiff(2);
1192 5 : rf1v = thisConstruct.rfBareVisDiff(1);
1193 5 : rf2v = thisConstruct.rfBareVisDiff(2);
1194 :
1195 5 : if (BGShade) {
1196 2 : if (NGlass == 2) {
1197 :
1198 : // Front incident solar, beam, between-glass shade, NGlass = 2
1199 :
1200 11 : for (int IPhi = 1; IPhi <= 10; ++IPhi) {
1201 10 : t1 = tBareSolPhi(1, IPhi);
1202 10 : t1v = tBareVisPhi(1, IPhi);
1203 10 : af1 = afBareSolPhi(1, IPhi);
1204 10 : ab1 = abBareSolPhi(1, IPhi);
1205 10 : tsolPhi(IPhi) = t1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * td2;
1206 10 : tvisPhi(IPhi) = t1v * (tshv + rshv * rb1v * tshv + tshv * rf2v * rshv) * td2v;
1207 10 : solabsShadePhi(IPhi) = t1 * (ash + rsh * rb1 + tsh * rf2) * ash;
1208 10 : solabsPhi(1, IPhi) = af1 + t1 * (rsh + rsh * rb1 * rsh + tsh * rf2 * tsh) * abd1;
1209 10 : solabsPhi(2, IPhi) = t1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * afd2;
1210 : } // End of loop over incidence angles
1211 :
1212 : // Front incident solar, diffuse, between-glass shade, NGlass = 2
1213 :
1214 1 : thisConstruct.TransDiff = td1 * (tsh + rsh * rb1 * tsh + tsh * rb2 * rsh) * td2;
1215 1 : thisConstruct.TransDiffVis = td1v * (tshv + rshv * rb1v * tshv + tshv * rb2v * rshv) * td2v;
1216 1 : thisConstruct.AbsDiffShade = td1 * (ash + rsh * rb1 * ash + tsh * rf2 * ash);
1217 1 : thisConstruct.AbsDiff(1) = afd1 + td1 * (rsh + tsh * rb2 * tsh) * abd1;
1218 1 : thisConstruct.AbsDiff(2) = td1 * (tsh + rsh * rb1 * tsh + tsh * rf2 * rsh) * afd2;
1219 1 : thisConstruct.ReflectSolDiffFront = rf1 + td1 * (rsh + rsh * rb1 * rsh + tsh * rf2 * tsh) * td1;
1220 1 : thisConstruct.ReflectVisDiffFront = rf1v + td1v * (rshv + rshv * rb1v * rshv + tshv * rf2v * tshv) * td1v;
1221 :
1222 : // Back incident solar, diffuse, between-glass shade, NGlass = 2
1223 :
1224 1 : thisConstruct.AbsDiffBackShade = td2 * (ash + rsh * rf2 * ash + tsh * rb1 * ash);
1225 1 : thisConstruct.AbsDiffBack(1) = td2 * (tsh + rsh * rf2 * tsh + tsh * rb1 * rsh) * abd1;
1226 1 : thisConstruct.AbsDiffBack(2) = abd2 + td2 * (rsh + rsh * rf2 * rsh + tsh * rb1 * tsh) * afd2;
1227 1 : thisConstruct.ReflectSolDiffBack = rb2 + td2 * (rsh + rsh * rf2 * rsh + tsh * rb1 * tsh) * td2;
1228 1 : thisConstruct.ReflectVisDiffBack = rb2v + td2v * (rshv + rshv * rf2v * rshv + tshv * rb1v * tshv) * td2v;
1229 :
1230 : } // End of check if NGlass = 2
1231 :
1232 2 : if (NGlass == 3) {
1233 :
1234 1 : td3 = thisConstruct.tBareSolDiff(3);
1235 1 : td3v = thisConstruct.tBareVisDiff(3);
1236 1 : afd3 = thisConstruct.afBareSolDiff(3);
1237 1 : abd3 = thisConstruct.abBareSolDiff(3);
1238 1 : rb3 = thisConstruct.rbBareSolDiff(3);
1239 1 : rb3v = thisConstruct.rbBareVisDiff(3);
1240 1 : rf3 = thisConstruct.rfBareSolDiff(3);
1241 1 : rf3v = thisConstruct.rfBareVisDiff(3);
1242 :
1243 : // Front incident solar, beam, between-glass shade, NGlass = 3
1244 :
1245 11 : for (int IPhi = 1; IPhi <= 10; ++IPhi) {
1246 10 : t1 = tBareSolPhi(1, IPhi);
1247 10 : t1v = tBareVisPhi(1, IPhi);
1248 10 : t2 = tBareSolPhi(2, IPhi);
1249 10 : t2v = tBareVisPhi(2, IPhi);
1250 10 : af1 = afBareSolPhi(1, IPhi);
1251 10 : af2 = afBareSolPhi(2, IPhi);
1252 10 : ab1 = abBareSolPhi(1, IPhi);
1253 10 : ab2 = abBareSolPhi(2, IPhi);
1254 10 : rbmf2 = max(0.0, 1.0 - (t2 + af2));
1255 :
1256 10 : tsolPhi(IPhi) = t1 * t2 * (tsh + tsh * rf3 * rsh + rsh * td2 * rb1 * td2 * tsh + rsh * rb2 * tsh) * td3;
1257 20 : tvisPhi(IPhi) =
1258 10 : t1v * t2v * (tshv + tshv * rf3v * rshv + rshv * td2v * rb1v * td2v * tshv + rshv * rb2v * tshv) * td3v;
1259 10 : solabsShadePhi(IPhi) = t1 * t2 * (1 + rsh * td2 * rb1 * td2 + rsh * rb2) * ash;
1260 20 : solabsPhi(1, IPhi) =
1261 10 : af1 + rbmf2 * ab1 + t1 * t2 * rsh * (1 + rf3 * tsh + rb2 * rsh + td2 * rb1 * td2 * rsh) * td2 * abd1;
1262 20 : solabsPhi(2, IPhi) =
1263 10 : t1 * af2 + t1 * t2 * ((rsh + tsh * rf3 * tsh + rsh * rb2 * rsh) * abd2 + rsh * td2 * rb1 * afd2);
1264 10 : solabsPhi(3, IPhi) = t1 * t2 * (tsh + rsh * (rb2 * tsh + td2 * rb2 * td2 * tsh + rf3 * rsh)) * afd3;
1265 : } // End of loop over incidence angle
1266 :
1267 : // Front incident solar, diffuse, between-glass shade, NGlass = 3
1268 :
1269 1 : thisConstruct.TransDiff = td1 * td2 * (tsh + rsh * td2 * rb1 * td2 * tsh + rsh * rb2 * tsh + tsh * rf3 * rsh) * td3;
1270 1 : thisConstruct.TransDiffVis =
1271 1 : td1v * td2v * (tshv + rshv * td2v * rb1v * td2v * tshv + rshv * rb2v * tshv + tshv * rf3v * rshv) * td3v;
1272 1 : thisConstruct.AbsDiffShade = td1 * td2 * (ash * (1 + rsh * td2 * rb1 * td2 + rsh * rb2 * ash) + tsh * rf3 * ash);
1273 2 : thisConstruct.AbsDiff(1) =
1274 1 : afd1 + td1 * (rf2 + td2 * (rsh + rsh * rb2 * rsh + tsh * rf3 * tsh + rsh * td2 * rb1 * td2 * rsh) * td2) * abd1;
1275 1 : thisConstruct.AbsDiff(2) = td1 * (afd2 + td2 * (rsh + rsh * rb2 * rsh + tsh * rf3 * tsh) * abd2);
1276 1 : thisConstruct.AbsDiff(3) = td1 * td2 * (tsh + rsh * rb2 * tsh + rsh * td2 * rb1 * td2 * tsh + tsh * rf3 * rsh) * afd3;
1277 1 : thisConstruct.ReflectSolDiffFront =
1278 1 : rf1 + td1 * rf2 * td1 +
1279 1 : td1 * td2 * (rsh + tsh * rf3 * tsh + rsh * rb2 * rsh + rsh * td2 * rb1 * td2 * rsh) * td2 * td1;
1280 1 : thisConstruct.ReflectVisDiffFront =
1281 1 : rf1v + td1v * rf2v * td1v +
1282 1 : td1v * td2v * (rshv + tshv * rf3v * tshv + rshv * rb2v * rshv + rshv * td2v * rb1v * td2v * rshv) * td2v * td1v;
1283 :
1284 : // Back incident solar, diffuse, between-glass shade, NGlass = 3
1285 :
1286 1 : thisConstruct.AbsDiffBackShade = td3 * ((1 + rsh * rf3) * ash + (tsh * td2 * rb1 * td2 + tsh * rb2) * ash);
1287 2 : thisConstruct.AbsDiffBack(1) =
1288 1 : td3 * (tsh + rsh * rf3 * tsh + tsh * rb2 * rsh + tsh * td2 * rb1 * td2 * rsh) * td2 * abd1;
1289 1 : thisConstruct.AbsDiffBack(2) = td3 * ((tsh + rsh * rf3 * tsh) * abd2 + (tsh * td2 * rb1 * td2 + tsh * rb2) * afd2);
1290 1 : thisConstruct.AbsDiffBack(3) = abd3 + td3 * (rsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * afd3;
1291 1 : thisConstruct.ReflectSolDiffBack =
1292 1 : rb3 + td3 * (rsh + rsh * rf3 * rsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * td3;
1293 1 : thisConstruct.ReflectVisDiffBack =
1294 1 : rb3v + td3v * (rshv + rshv * rf3 * rshv + tshv * rb2v * tshv + tshv * td2v * rb1v * td2v * tshv) * td3v;
1295 :
1296 : } // End of check if NGlass = 3
1297 :
1298 : } // End of check if between-glass shade
1299 :
1300 5 : if (BGBlind) {
1301 :
1302 3 : if (NGlass == 2) {
1303 :
1304 : // Front incident solar, diffuse, between-glass blind, NGlass = 2
1305 :
1306 2 : thisConstruct.BlAbsDiff(ISlatAng, 1) = afd1 + td1 * (rfsh + rfsh * rb1 * rfsh + tsh * rb2 * tsh) * abd1;
1307 4 : thisConstruct.BlAbsDiffGnd(ISlatAng, 1) =
1308 2 : afd1 + td1 * (rfshGnd + rfshGnd * rb1 * rfshGnd + tshGnd * rb2 * tsh) * abd1;
1309 4 : thisConstruct.BlAbsDiffSky(ISlatAng, 1) =
1310 2 : afd1 + td1 * (rfshSky + rfshSky * rb1 * rfshSky + tshSky * rb2 * tsh) * abd1;
1311 2 : thisConstruct.BlAbsDiff(ISlatAng, 2) = td1 * (tsh + rfsh * rb1 * tsh + tsh * rf2 * rbsh) * afd2;
1312 2 : thisConstruct.BlAbsDiffGnd(ISlatAng, 2) = td1 * (tshGnd + rfshGnd * rb1 * tsh + tshGnd * rf2 * rbsh) * afd2;
1313 2 : thisConstruct.BlAbsDiffSky(ISlatAng, 2) = td1 * (tshSky + rfshSky * rb1 * tsh + tshSky * rf2 * rbsh) * afd2;
1314 2 : thisConstruct.AbsDiffBlind(ISlatAng) = td1 * (afsh + rfsh * rb1 * afsh + tsh * rf2 * absh);
1315 2 : thisConstruct.AbsDiffBlindGnd(ISlatAng) = td1 * (afshGnd + rfsh * rb1 * afsh + tshGnd * rf2 * absh);
1316 2 : thisConstruct.AbsDiffBlindSky(ISlatAng) = td1 * (afshSky + rfsh * rb1 * afsh + tshSky * rf2 * absh);
1317 2 : thisConstruct.BlTransDiff(ISlatAng) = td1 * (tsh + rfsh * rb1 * tsh + tsh * rb2 * rbsh) * td2;
1318 2 : thisConstruct.BlTransDiffGnd(ISlatAng) = td1 * (tshGnd + rfsh * rb1 * tshGnd + tshGnd * rb2 * rbsh) * td2;
1319 2 : thisConstruct.BlTransDiffSky(ISlatAng) = td1 * (tshSky + rfsh * rb1 * tshSky + tshSky * rb2 * rbsh) * td2;
1320 2 : thisConstruct.BlTransDiffVis(ISlatAng) = td1v * (tshv + rfshv * rb1v * tshv + tshv * rb2v * rbshv) * td2v;
1321 2 : thisConstruct.BlReflectSolDiffFront(ISlatAng) = rf1 + td1 * (rfsh + rfsh * rb1 * rfsh + tsh * rf2 * tsh) * td1;
1322 4 : thisConstruct.BlReflectVisDiffFront(ISlatAng) =
1323 2 : rf1v + td1v * (rfshv + rfshv * rb1v * rfshv + tshv * rf2v * tshv) * td1v;
1324 :
1325 : // Back incident solar, diffuse, between-glass blind, NGlass = 2
1326 :
1327 2 : thisConstruct.BlAbsDiffBack(ISlatAng, 1) = td2 * (tsh + rbsh * rf2 * tsh + tsh * rb1 * rfsh) * abd1;
1328 2 : thisConstruct.BlAbsDiffBack(ISlatAng, 2) = abd2 + td2 * (rbsh + rbsh * rf2 * rbsh + tsh * rb1 * tsh) * afd2;
1329 2 : thisConstruct.AbsDiffBackBlind(ISlatAng) = td2 * (absh + rbsh * rf2 * absh + tsh * rb1 * afsh);
1330 2 : thisConstruct.BlReflectSolDiffBack(ISlatAng) = rb2 + td2 * (rbsh + rbsh * rf2 * rbsh + tsh * rb1 * tsh) * td2;
1331 2 : thisConstruct.BlReflectVisDiffBack(ISlatAng) =
1332 2 : rb2v + td2v * (rbshv + rbshv * rf2v * rbshv + tshv * rb1v * tshv) * td2v;
1333 :
1334 : } // End of check if NGlass = 2
1335 :
1336 3 : if (NGlass == 3) {
1337 :
1338 1 : td3 = thisConstruct.tBareSolDiff(3);
1339 1 : td3v = thisConstruct.tBareVisDiff(3);
1340 1 : afd3 = thisConstruct.afBareSolDiff(3);
1341 1 : abd3 = thisConstruct.abBareSolDiff(3);
1342 1 : rb3 = thisConstruct.rbBareSolDiff(3);
1343 1 : rb3v = thisConstruct.rbBareVisDiff(3);
1344 1 : rf3 = thisConstruct.rfBareSolDiff(3);
1345 1 : rf3v = thisConstruct.rfBareVisDiff(3);
1346 :
1347 : // Front incident solar, diffuse, between-glass blind, NGlass = 3
1348 :
1349 2 : thisConstruct.BlAbsDiff(ISlatAng, 1) =
1350 1 : afd1 +
1351 1 : td1 * (rf2 + td2 * (rfsh + rfsh * rb2 * rfsh + tsh * rf3 * tsh + rfsh * td2 * rb1 * td2 * rfsh) * td2) * abd1;
1352 2 : thisConstruct.BlAbsDiffGnd(ISlatAng, 1) =
1353 1 : afd1 +
1354 1 : td1 *
1355 1 : (rf2 + td2 * (rfshGnd + rfshGnd * rb2 * rfsh + tshGnd * rf3 * tsh + rfshGnd * td2 * rb1 * td2 * rfsh) * td2) *
1356 : abd1;
1357 2 : thisConstruct.BlAbsDiffSky(ISlatAng, 1) =
1358 1 : afd1 +
1359 1 : td1 *
1360 1 : (rf2 + td2 * (rfshSky + rfshSky * rb2 * rfsh + tshSky * rf3 * tsh + rfshSky * td2 * rb1 * td2 * rfsh) * td2) *
1361 : abd1;
1362 1 : thisConstruct.BlAbsDiff(ISlatAng, 2) = td1 * (afd2 + td2 * (rfsh + rfsh * rb2 * rfsh + tsh * rf3 * tsh) * abd2);
1363 2 : thisConstruct.BlAbsDiffGnd(ISlatAng, 2) =
1364 1 : td1 * (afd2 + td2 * (rfshGnd + rfshGnd * rb2 * rfsh + tshGnd * rf3 * tsh) * abd2);
1365 2 : thisConstruct.BlAbsDiffSky(ISlatAng, 2) =
1366 1 : td1 * (afd2 + td2 * (rfshSky + rfshSky * rb2 * rfsh + tshSky * rf3 * tsh) * abd2);
1367 2 : thisConstruct.BlAbsDiff(ISlatAng, 3) =
1368 1 : td1 * td2 * (tsh + rfsh * rb2 * tsh + rfsh * td2 * rb1 * td2 * tsh + tsh * rf3 * rbsh) * afd3;
1369 2 : thisConstruct.BlAbsDiffGnd(ISlatAng, 3) =
1370 1 : td1 * td2 * (tshGnd + rfshGnd * rb2 * tsh + rfshGnd * td2 * rb1 * td2 * tsh + tshGnd * rf3 * rbsh) * afd3;
1371 2 : thisConstruct.BlAbsDiffSky(ISlatAng, 3) =
1372 1 : td1 * td2 * (tshSky + rfshSky * rb2 * tsh + rfshSky * td2 * rb1 * td2 * tsh + tshSky * rf3 * rbsh) * afd3;
1373 2 : thisConstruct.AbsDiffBlind(ISlatAng) =
1374 1 : td1 * td2 * (afsh * (1 + rfsh * td2 * rb1 * td2) + rfsh * rb2 * afsh + tsh * rf3 * absh);
1375 2 : thisConstruct.AbsDiffBlindGnd(ISlatAng) =
1376 1 : td1 * td2 * (afshGnd + afsh * rfsh * (td2 * rb1 * td2 + rb2) + tshGnd * rf3 * absh);
1377 2 : thisConstruct.AbsDiffBlindSky(ISlatAng) =
1378 1 : td1 * td2 * (afshSky + afsh * rfsh * (td2 * rb1 * td2 + rb2) + tshSky * rf3 * absh);
1379 2 : thisConstruct.BlTransDiff(ISlatAng) =
1380 1 : td1 * td2 * (tsh + rfsh * td2 * rb1 * td2 * tsh + rfsh * rb2 * tsh + tsh * rf3 * rbsh) * td3;
1381 2 : thisConstruct.BlTransDiffGnd(ISlatAng) =
1382 1 : td1 * td2 * (tshGnd + rfsh * td2 * rb1 * td2 * tshGnd + rfsh * rb2 * tshGnd + tshGnd * rf3 * rbsh) * td3;
1383 2 : thisConstruct.BlTransDiffSky(ISlatAng) =
1384 1 : td1 * td2 * (tshSky + rfsh * td2 * rb1 * td2 * tshSky + rfsh * rb2 * tshSky + tshSky * rf3 * rbsh) * td3;
1385 2 : thisConstruct.BlTransDiffVis(ISlatAng) =
1386 1 : td1v * td2v * (tshv + rfshv * td2v * rb1v * td2v * tshv + rfshv * rb2v * tshv + tshv * rf3v * rbshv) * td3v;
1387 2 : thisConstruct.BlReflectSolDiffFront(ISlatAng) =
1388 1 : rf1 + td1 * rf2 * td1 +
1389 1 : td1 * td2 * (rfsh + tsh * rf3 * tsh + rfsh * rb2 * rfsh + rfsh * td2 * rb1 * td2 * rfsh) * td2 * td1;
1390 2 : thisConstruct.BlReflectVisDiffFront(ISlatAng) =
1391 1 : rf1v + td1v * rf2v * td1v +
1392 1 : td1v * td2v * (rfshv + tshv * rf3v * tshv + rfshv * rb2v * rfshv + rfshv * td2v * rb1v * td2v * rfshv) * td2v *
1393 : td1v;
1394 :
1395 : // Back incident solar, diffuse, between-glass blind, NGlass = 3
1396 :
1397 2 : thisConstruct.BlAbsDiffBack(ISlatAng, 1) =
1398 1 : td3 * (tsh + rbsh * rf3 * tsh + tsh * rb2 * rfsh + tsh * td2 * rb1 * td2 * rfsh) * td2 * abd1;
1399 2 : thisConstruct.BlAbsDiffBack(ISlatAng, 2) =
1400 1 : td3 * ((tsh + rbsh * rf3 * tsh) * abd2 + (tsh * td2 * rb1 * td2 + tsh * rb2) * afd2);
1401 1 : thisConstruct.BlAbsDiffBack(ISlatAng, 3) = abd3 + td3 * (rbsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * afd3;
1402 2 : thisConstruct.AbsDiffBackBlind(ISlatAng) =
1403 1 : td3 * ((1 + rbsh * rf3) * absh + (tsh * td2 * rb1 * td2 + tsh * rb2) * afsh);
1404 2 : thisConstruct.BlReflectSolDiffBack(ISlatAng) =
1405 1 : rb3 + td3 * (rbsh + rbsh * rf3 * rbsh + tsh * rb2 * tsh + tsh * td2 * rb1 * td2 * tsh) * td3;
1406 1 : thisConstruct.BlReflectVisDiffBack(ISlatAng) =
1407 1 : rb3v + td3v * (rbshv + rbshv * rf3v * rbshv + tshv * rb2v * tshv + tshv * td2v * rb1v * td2v * tshv) * td3v;
1408 :
1409 : } // End of check if NGlass = 3
1410 :
1411 : } // End of check if between-glass blind
1412 :
1413 : } // End of check if between-glass shade or blind
1414 :
1415 : // Continue loop over slat angles only for blinds with variable slat angle
1416 588 : if (ShadeOn || ScreenOn) break;
1417 557 : if (BlindOn) {
1418 557 : auto const &blind = state.dataMaterial->Blind(BlNum);
1419 557 : if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) break;
1420 : }
1421 : } // End of slat angle loop
1422 : } // End of check if construction has a shade or blind
1423 :
1424 : // Curve fits to get solar transmittance, reflectance, layer absorptance and
1425 : // visible transmittance as polynomials in cosine of incidence angle
1426 :
1427 1348 : if (!BlindOn && !ScreenOn) { // Bare glass or shade on
1428 1329 : W5LsqFit(CosPhiIndepVar, tsolPhi, 6, 1, TotalIPhi, thisConstruct.TransSolBeamCoef);
1429 1329 : W5LsqFit(CosPhiIndepVar, rfsolPhi, 6, 1, TotalIPhi, thisConstruct.ReflSolBeamFrontCoef);
1430 1329 : W5LsqFit(CosPhiIndepVar, rbsolPhi, 6, 1, TotalIPhi, thisConstruct.ReflSolBeamBackCoef);
1431 1329 : W5LsqFit(CosPhiIndepVar, tvisPhi, 6, 1, TotalIPhi, thisConstruct.TransVisBeamCoef);
1432 1329 : Array1D<Real64> DepVarCurveFit(TotalIPhi);
1433 1329 : Array1D<Real64> CoeffsCurveFit(6);
1434 :
1435 3318 : for (int IGlass = 1; IGlass <= NGlass; ++IGlass) {
1436 : // Front absorptance coefficients for glass layers
1437 1989 : DepVarCurveFit = solabsPhi(IGlass, {1, TotalIPhi});
1438 1989 : W5LsqFit(CosPhiIndepVar, DepVarCurveFit, 6, 1, TotalIPhi, CoeffsCurveFit);
1439 1989 : thisConstruct.AbsBeamCoef(IGlass) = CoeffsCurveFit;
1440 : // Back absorptance coefficients for glass layers
1441 1989 : IGlassBack = NGlass - IGlass + 1;
1442 1989 : DepVarCurveFit = solabsBackPhi(IGlassBack, {1, TotalIPhi});
1443 1989 : W5LsqFit(CosPhiIndepVar, DepVarCurveFit, 6, 1, TotalIPhi, CoeffsCurveFit);
1444 1989 : thisConstruct.AbsBeamBackCoef(IGlass) = CoeffsCurveFit;
1445 : }
1446 :
1447 : // To check goodness of fit //Tuned
1448 :
1449 14619 : for (int IPhi = 1; IPhi <= TotalIPhi; ++IPhi) {
1450 13290 : tsolPhiFit(IPhi) = 0.0;
1451 13290 : tvisPhiFit(IPhi) = 0.0;
1452 :
1453 13290 : Phi = double(IPhi - 1) * 10.0;
1454 13290 : CosPhi = std::cos(Phi * Constant::DegToRadians);
1455 13290 : if (std::abs(CosPhi) < 0.0001) CosPhi = 0.0;
1456 13290 : Real64 cos_pow(1.0);
1457 93030 : for (int CoefNum = 1; CoefNum <= 6; ++CoefNum) {
1458 79740 : cos_pow *= CosPhi;
1459 79740 : tsolPhiFit(IPhi) += thisConstruct.TransSolBeamCoef(CoefNum) * cos_pow;
1460 79740 : tvisPhiFit(IPhi) += thisConstruct.TransVisBeamCoef(CoefNum) * cos_pow;
1461 : }
1462 : }
1463 1329 : }
1464 :
1465 1348 : if (ShadeOn) W5LsqFit(CosPhiIndepVar, solabsShadePhi, 6, 1, TotalIPhi, thisConstruct.AbsBeamShadeCoef);
1466 :
1467 : } // End of loop over constructions
1468 :
1469 : // Get effective glass and shade/blind emissivities for windows that have interior blind or
1470 : // shade. These are used to calculate zone MRT contribution from window when
1471 : // interior blind/shade is deployed.
1472 :
1473 : // Loop for ordinary windows
1474 46816 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1475 46023 : auto const &surf = state.dataSurface->Surface(SurfNum);
1476 46023 : if (!surf.HeatTransSurf) continue;
1477 44369 : if (!state.dataConstruction->Construct(surf.Construction).TypeIsWindow) continue;
1478 6216 : if (state.dataSurface->SurfWinWindowModelType(SurfNum) == WindowModel::BSDF) continue; // Irrelevant for Complex Fen
1479 6216 : if (state.dataConstruction->Construct(surf.Construction).WindowTypeEQL) continue; // not required
1480 6213 : ConstrNumSh = surf.activeShadedConstruction;
1481 6213 : if (ConstrNumSh == 0) continue;
1482 149 : TotLay = state.dataConstruction->Construct(ConstrNumSh).TotLayers;
1483 149 : IntShade = false;
1484 149 : IntBlind = false;
1485 149 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild *>(
1486 149 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay)));
1487 149 : assert(thisMaterial != nullptr);
1488 149 : if (thisMaterial->group == Material::Group::Shade) {
1489 48 : IntShade = true;
1490 48 : ShadeLayPtr = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay);
1491 : }
1492 149 : if (thisMaterial->group == Material::Group::WindowBlind) {
1493 34 : IntBlind = true;
1494 34 : BlNum = thisMaterial->BlindDataPtr;
1495 : }
1496 :
1497 149 : if (IntShade || IntBlind) {
1498 444 : for (int ISlatAng = 1; ISlatAng <= Material::MaxSlatAngs; ++ISlatAng) {
1499 442 : if (IntShade || IntBlind) {
1500 442 : EpsGlIR = dynamic_cast<Material::MaterialChild const *>(
1501 442 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNumSh).LayerPoint(TotLay - 1)))
1502 : ->AbsorpThermalBack;
1503 442 : RhoGlIR = 1 - EpsGlIR;
1504 : }
1505 442 : if (IntShade) {
1506 48 : auto const *thisMaterialShade = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(ShadeLayPtr));
1507 48 : TauShIR = thisMaterialShade->TransThermal;
1508 48 : EpsShIR = thisMaterialShade->AbsorpThermal;
1509 48 : RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
1510 48 : state.dataSurface->SurfaceWindow(SurfNum).EffShBlindEmiss[1] =
1511 48 : EpsShIR * (1.0 + RhoGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR));
1512 48 : state.dataSurface->SurfaceWindow(SurfNum).EffGlassEmiss[1] = EpsGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR);
1513 : }
1514 442 : if (IntBlind) {
1515 394 : auto const &blind = state.dataMaterial->Blind(BlNum);
1516 394 : TauShIR = blind.IRFrontTrans(ISlatAng);
1517 394 : EpsShIR = blind.IRBackEmiss(ISlatAng);
1518 394 : RhoShIR = max(0.0, 1.0 - TauShIR - EpsShIR);
1519 394 : state.dataSurface->SurfaceWindow(SurfNum).EffShBlindEmiss[ISlatAng] =
1520 394 : EpsShIR * (1.0 + RhoGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR));
1521 394 : state.dataSurface->SurfaceWindow(SurfNum).EffGlassEmiss[ISlatAng] = EpsGlIR * TauShIR / (1.0 - RhoGlIR * RhoShIR);
1522 : }
1523 : // Loop over remaining slat angles only if blind with movable slats
1524 442 : if (IntShade) break; // Loop over remaining slat angles only if blind
1525 394 : if (IntBlind) {
1526 394 : auto const &blind = state.dataMaterial->Blind(BlNum);
1527 :
1528 394 : if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) break;
1529 : }
1530 : } // End of slat angle loop
1531 : } // End of check if interior shade or interior blind
1532 : } // End of surface loop
1533 :
1534 46816 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1535 46023 : auto const &surf = state.dataSurface->Surface(SurfNum);
1536 46023 : if (surf.Construction <= 0) continue;
1537 44387 : auto const &construct = state.dataConstruction->Construct(surf.Construction);
1538 44387 : if (!construct.TypeIsWindow) continue;
1539 :
1540 : // Total thickness of glazing system (used in calculation of inside reveal reflection/absorption
1541 6216 : state.dataSurface->SurfWinTotGlazingThickness(SurfNum) = 0.0;
1542 16548 : for (int LayNum = 1; LayNum <= construct.TotLayers; ++LayNum) {
1543 10332 : state.dataSurface->SurfWinTotGlazingThickness(SurfNum) += state.dataMaterial->Material(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 6216 : Rectangle = false;
1559 6216 : Triangle = false;
1560 6216 : if (surf.Sides == 3) Triangle = true;
1561 6216 : if (surf.Sides == 4) Rectangle = true;
1562 6216 : 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 6214 : W3 = surf.Vertex(2);
1566 6214 : W2 = surf.Vertex(3);
1567 6214 : W1 = surf.Vertex(4);
1568 2 : } else if (Triangle) {
1569 2 : W3 = surf.Vertex(2);
1570 2 : W2 = surf.Vertex(3);
1571 2 : W1 = surf.Vertex(1);
1572 : }
1573 6216 : W21 = W1 - W2;
1574 6216 : W23 = W3 - W2;
1575 6216 : if (Rectangle) {
1576 6214 : state.dataSurface->SurfaceWindow(SurfNum).WinCenter = W2 + (W23 + W21) / 2.0;
1577 2 : } else if (Triangle) {
1578 2 : state.dataSurface->SurfaceWindow(SurfNum).WinCenter = W2 + (W23 + W21) / 3.0;
1579 : }
1580 : } // End of surface loop
1581 :
1582 793 : ReportGlass(state);
1583 793 : } // InitGlassOpticalCalculations()
1584 :
1585 : //*****************************************************************************************
1586 :
1587 793 : void W5InitGlassParameters(EnergyPlusData &state)
1588 : {
1589 : // Initializes variables used in the window optical and thermal calculation.
1590 :
1591 : int ConstrNum; // Construction number
1592 : int FrDivNum; // Pointer to frame/divider
1593 : Real64 FrWidth; // Window frame width {m}
1594 : Real64 FrEdgeWidth; // Frame edge width {m}
1595 : Real64 DivWidth; // Window divider width {m}
1596 : Real64 DivEdgeWidth; // Divider edge width {m}
1597 : Real64 GlHeight; // Height of glazed part of window {m}
1598 : Real64 GlWidth; // Width of glazed part of window {m}
1599 : int NumHorDividers; // Number of horizontal divider elements
1600 : int NumVertDividers; // Number of vertical divider elements
1601 : int BaseSurfNum; // Base surface number
1602 : int MatNum; // Material number
1603 : int DifOverrideCount; // Count the number of SolarDiffusing material overrides
1604 :
1605 793 : auto &wm = state.dataWindowManager;
1606 :
1607 6820 : for (int ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
1608 6027 : auto &thisConstruct = state.dataConstruction->Construct(ConstrNum);
1609 6027 : if (thisConstruct.FromWindow5DataFile) continue;
1610 6022 : if (thisConstruct.WindowTypeBSDF) continue;
1611 6009 : thisConstruct.TransDiff = 0.0;
1612 6009 : thisConstruct.TransDiffVis = 0.0;
1613 6009 : thisConstruct.AbsDiffBackShade = 0.0;
1614 6009 : thisConstruct.ShadeAbsorpThermal = 0.0;
1615 6009 : thisConstruct.ReflectSolDiffBack = 0.0;
1616 6009 : thisConstruct.ReflectSolDiffFront = 0.0;
1617 6009 : thisConstruct.ReflectVisDiffFront = 0.0;
1618 6009 : thisConstruct.AbsBeamShadeCoef = 0.0;
1619 6009 : thisConstruct.TransSolBeamCoef = 0.0;
1620 6009 : thisConstruct.ReflSolBeamFrontCoef = 0.0;
1621 6009 : thisConstruct.ReflSolBeamBackCoef = 0.0;
1622 6009 : thisConstruct.TransVisBeamCoef = 0.0;
1623 6009 : thisConstruct.AbsDiff = 0.0;
1624 6009 : thisConstruct.AbsDiffBack = 0.0;
1625 48244 : for (int Layer = 1; Layer <= state.dataHeatBal->MaxSolidWinLayers; ++Layer) {
1626 295645 : for (int index = 1; index <= DataSurfaces::MaxPolyCoeff; ++index) {
1627 253410 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).AbsBeamCoef(Layer)(index) = 0.0;
1628 253410 : state.dataConstruction->Construct(state.dataHeatBal->TotConstructs).AbsBeamBackCoef(Layer)(index) = 0.0;
1629 : }
1630 : }
1631 : }
1632 :
1633 46816 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1634 : // For a window with shading device, get number of shaded construction and, if window
1635 : // has a blind (interior, exterior or between glass), get blind data pointer.
1636 46023 : auto const &surf = state.dataSurface->Surface(SurfNum);
1637 46023 : if (surf.HasShadeControl) {
1638 294 : for (int winShadCtrl : surf.windowShadingControlList) {
1639 153 : WinShadingType ShadingType = state.dataSurface->WindowShadingControl(winShadCtrl).ShadingType;
1640 153 : if (ShadingType == WinShadingType::ExtScreen) {
1641 : // Count number of exterior window screens, initialize in InitGlassOpticalCalculations after returning
1642 : // from this subroutine. The blind structure is initialized first and then the screen structure is initialized.
1643 8 : ++state.dataHeatBal->NumScreens;
1644 8 : break; // only need to find the first window shading control since they should be identical
1645 : }
1646 149 : }
1647 : }
1648 : }
1649 :
1650 : // Set some static exterior-window frame and divider SurfaceWindow values
1651 : // from values in FrameDivider derived type
1652 46816 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1653 46023 : auto const &surf = state.dataSurface->Surface(SurfNum);
1654 46023 : if (surf.FrameDivider == 0) continue;
1655 :
1656 381 : auto &surfWin = state.dataSurface->SurfaceWindow(SurfNum);
1657 381 : auto const &frdiv = state.dataSurface->FrameDivider(surf.FrameDivider);
1658 :
1659 381 : FrWidth = frdiv.FrameWidth;
1660 381 : GlHeight = surf.Height;
1661 381 : GlWidth = surf.Width;
1662 381 : NumVertDividers = frdiv.VertDividers;
1663 381 : NumHorDividers = frdiv.HorDividers;
1664 381 : BaseSurfNum = surf.BaseSurf;
1665 381 : state.dataSurface->SurfWinFrameConductance(SurfNum) = frdiv.FrameConductance;
1666 381 : state.dataSurface->SurfWinFrameSolAbsorp(SurfNum) = frdiv.FrameSolAbsorp;
1667 381 : state.dataSurface->SurfWinFrameVisAbsorp(SurfNum) = frdiv.FrameVisAbsorp;
1668 381 : state.dataSurface->SurfWinFrameEmis(SurfNum) = frdiv.FrameEmis;
1669 381 : state.dataSurface->SurfWinFrEdgeToCenterGlCondRatio(SurfNum) = frdiv.FrEdgeToCenterGlCondRatio;
1670 381 : state.dataSurface->SurfWinDividerType(SurfNum) = DataSurfaces::FrameDividerType::DividedLite;
1671 381 : if (frdiv.DividerType == DataSurfaces::FrameDividerType::Suspended)
1672 11 : state.dataSurface->SurfWinDividerType(SurfNum) = DataSurfaces::FrameDividerType::Suspended;
1673 381 : DivWidth = frdiv.DividerWidth;
1674 381 : state.dataSurface->SurfWinDividerConductance(SurfNum) = frdiv.DividerConductance;
1675 381 : state.dataSurface->SurfWinDividerSolAbsorp(SurfNum) = frdiv.DividerSolAbsorp;
1676 381 : state.dataSurface->SurfWinDividerVisAbsorp(SurfNum) = frdiv.DividerVisAbsorp;
1677 381 : state.dataSurface->SurfWinDividerEmis(SurfNum) = frdiv.DividerEmis;
1678 381 : state.dataSurface->SurfWinDivEdgeToCenterGlCondRatio(SurfNum) = frdiv.DivEdgeToCenterGlCondRatio;
1679 :
1680 381 : state.dataSurface->SurfWinOutsideRevealSolAbs(SurfNum) = frdiv.OutsideRevealSolAbs;
1681 381 : state.dataSurface->SurfWinInsideSillDepth(SurfNum) = frdiv.InsideSillDepth;
1682 381 : state.dataSurface->SurfWinInsideReveal(SurfNum) = frdiv.InsideReveal;
1683 381 : state.dataSurface->SurfWinInsideSillSolAbs(SurfNum) = frdiv.InsideSillSolAbs;
1684 381 : state.dataSurface->SurfWinInsideRevealSolAbs(SurfNum) = frdiv.InsideRevealSolAbs;
1685 :
1686 381 : FrEdgeWidth = frdiv.FrameEdgeWidth;
1687 381 : DivEdgeWidth = frdiv.DividerEdgeWidth;
1688 381 : state.dataSurface->SurfWinFrameEdgeArea(SurfNum) =
1689 381 : 2 * FrEdgeWidth * (GlHeight - FrEdgeWidth - NumHorDividers * DivWidth + GlWidth - FrEdgeWidth - NumVertDividers * DivWidth);
1690 381 : state.dataSurface->SurfWinDividerEdgeArea(SurfNum) =
1691 762 : 2 * DivEdgeWidth * (NumHorDividers * (GlWidth - 2 * FrEdgeWidth) + NumVertDividers * (GlHeight - 2 * FrEdgeWidth)) -
1692 381 : NumHorDividers * NumVertDividers * (4 * pow_2(DivEdgeWidth) + 4 * FrEdgeWidth * DivWidth);
1693 381 : surfWin.centerGlassArea =
1694 381 : surf.Area - state.dataSurface->SurfWinFrameEdgeArea(SurfNum) - state.dataSurface->SurfWinDividerEdgeArea(SurfNum);
1695 381 : surfWin.edgeGlassCorrFac =
1696 381 : (state.dataSurface->SurfWinFrameEdgeArea(SurfNum) * state.dataSurface->SurfWinFrEdgeToCenterGlCondRatio(SurfNum) +
1697 381 : state.dataSurface->SurfWinDividerEdgeArea(SurfNum) * state.dataSurface->SurfWinDivEdgeToCenterGlCondRatio(SurfNum) +
1698 762 : surfWin.centerGlassArea) /
1699 381 : (state.dataSurface->SurfWinFrameEdgeArea(SurfNum) + state.dataSurface->SurfWinDividerEdgeArea(SurfNum) + surfWin.centerGlassArea);
1700 : } // for (SurfNum)
1701 :
1702 : // Set SolarDiffusing to true for exterior windows that have a construction with an innermost diffusing glass layer
1703 793 : DifOverrideCount = 0;
1704 46816 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
1705 46023 : auto const &surf = state.dataSurface->Surface(SurfNum);
1706 46023 : state.dataSurface->SurfWinSolarDiffusing(SurfNum) = false;
1707 52223 : if (surf.Class != SurfaceClass::Window || surf.ExtBoundCond != ExternalEnvironment ||
1708 6200 : state.dataSurface->SurfWinStormWinConstr(SurfNum) != 0)
1709 39824 : continue;
1710 :
1711 6199 : ConstrNum = surf.Construction;
1712 6199 : MatNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(state.dataConstruction->Construct(ConstrNum).TotLayers);
1713 6199 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(MatNum));
1714 6199 : assert(thisMaterial != nullptr);
1715 :
1716 6199 : if (!thisMaterial->SolarDiffusing) continue;
1717 :
1718 0 : if (!surf.HasShadeControl) {
1719 0 : state.dataSurface->SurfWinSolarDiffusing(SurfNum) = true;
1720 : } else { // There is a shading control
1721 0 : if (state.dataSurface->WindowShadingControl(surf.activeWindowShadingControl).ShadingType == WinShadingType::SwitchableGlazing) {
1722 0 : state.dataSurface->SurfWinSolarDiffusing(SurfNum) = true;
1723 : } else {
1724 0 : state.dataSurface->SurfWinSolarDiffusing(SurfNum) = false;
1725 0 : ++DifOverrideCount;
1726 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1727 0 : ShowWarningError(state,
1728 0 : format("W5InitGlassParameters: Window=\"{}\" has interior material with Solar Diffusing=Yes, but "
1729 : "existing Window Shading Device sets Diffusing=No.",
1730 0 : surf.Name));
1731 : }
1732 : }
1733 : }
1734 : } // for (SurfNum)
1735 :
1736 793 : if (DifOverrideCount > 0) {
1737 0 : if (!state.dataGlobal->DisplayExtraWarnings) {
1738 0 : ShowWarningError(state,
1739 0 : format("W5InitGlassParameters: {} Windows had Solar Diffusing=Yes overridden by presence of Window Shading Device.",
1740 : DifOverrideCount));
1741 : } else {
1742 0 : ShowMessage(state,
1743 0 : format("W5InitGlassParameters: {} Windows had Solar Diffusing=Yes overridden by presence of Window Shading Device.",
1744 : DifOverrideCount));
1745 : }
1746 : }
1747 793 : } // W5InitGlassParameters()
1748 :
1749 : //****************************************************************************
1750 : // WINDOW 5 Optical Calculation Subroutines
1751 : //****************************************************************************
1752 :
1753 39830 : void SystemSpectralPropertiesAtPhi(EnergyPlusData &state,
1754 : int const iquasi, // When there is no spectral data, this is the wavelength
1755 : int const ngllayer, // Number of glass layers in construction
1756 : Real64 const wlbot, // Lowest and highest wavelength considered
1757 : Real64 const wltop,
1758 : std::array<int, maxGlassLayers> const &numpt,
1759 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &wlt,
1760 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &tPhi,
1761 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &rfPhi,
1762 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> const &rbPhi,
1763 : std::array<Real64, nume> &stPhi,
1764 : std::array<Real64, nume> &srfPhi,
1765 : std::array<Real64, nume> &srbPhi,
1766 : Array2D<Real64> &saPhi)
1767 : {
1768 :
1769 : // SUBROUTINE INFORMATION:
1770 : // AUTHOR Adapted by F.Winkelmann from WINDOW 5
1771 : // subroutine opcalc
1772 : // DATE WRITTEN August 1999
1773 : // MODIFIED na
1774 : // RE-ENGINEERED na
1775 :
1776 : // PURPOSE OF THIS SUBROUTINE:
1777 : // For a particular angle of incidence, calculates system properties
1778 : // for a multi-layer glazing for each wavelength in the solar spectrum.
1779 : // Handles the special case of one or more layers that do not have spectral data.
1780 :
1781 : // Returns, for a particular angle of incidence:
1782 : // stPhi transmissivity of system at each wavelength in swl
1783 : // srfPhi front reflectance of system at each wavelength in swl
1784 : // srbPhi back reflectance of system at each wavelength in swl
1785 : // sabsPhi absorptance by layer at each wavelength in swl
1786 :
1787 39830 : Array1D<Real64> sabsPhi(5); // System solar absorptance in each glass layer for
1788 : // particular angle of incidence
1789 :
1790 : // transmittance at angle of incidence
1791 39830 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> tadjPhi = {0.0};
1792 : // front reflectance at angle of incidence
1793 39830 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rfadjPhi = {0.0};
1794 : // back reflectance at angle of incidence
1795 39830 : std::array<std::array<Real64, maxSpectralDataElements>, maxGlassLayers> rbadjPhi = {0.0};
1796 :
1797 39830 : auto &wm = state.dataWindowManager;
1798 : // For each glass layer find tPhi, rfPhi, and rbPhi at each wavelength
1799 :
1800 98430 : for (int in = 1; in <= ngllayer; ++in) {
1801 6328800 : for (int iwl = 1; iwl <= nume; ++iwl) {
1802 6270200 : Real64 wl = wm->wle[iwl - 1];
1803 6270200 : if (wl < wlbot || wl > wltop) continue;
1804 : // In the following numpt is the number of spectral data points for each layer;
1805 : // numpt = 2 if there is no spectral data for a layer.
1806 4949720 : if (numpt[in - 1] <= 2) {
1807 4477020 : tadjPhi[in - 1][iwl - 1] = tPhi[in - 1][iquasi - 1];
1808 4477020 : rfadjPhi[in - 1][iwl - 1] = rfPhi[in - 1][iquasi - 1];
1809 4477020 : rbadjPhi[in - 1][iwl - 1] = rbPhi[in - 1][iquasi - 1];
1810 : } else {
1811 : // Interpolate to get properties at the solar spectrum wavelengths
1812 472700 : tadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], tPhi[in - 1], numpt[in - 1], wl);
1813 472700 : rfadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], rfPhi[in - 1], numpt[in - 1], wl);
1814 472700 : rbadjPhi[in - 1][iwl - 1] = Interpolate(wlt[in - 1], rbPhi[in - 1], numpt[in - 1], wl);
1815 : }
1816 : }
1817 : }
1818 :
1819 : // Calculate system properties at each wavelength
1820 4301640 : for (int j = 1; j <= nume; ++j) {
1821 4261810 : Real64 wl = wm->wle[j - 1];
1822 4261810 : if (wl < wlbot || wl > wltop) continue;
1823 :
1824 : // Set diagonal of matrix for subroutine SystemPropertiesAtLambdaAndPhi
1825 8284890 : for (int i = 1; i <= ngllayer; ++i) {
1826 4949720 : wm->top[i - 1][i - 1] = tadjPhi[i - 1][j - 1];
1827 4949720 : wm->rfop[i - 1][i - 1] = rfadjPhi[i - 1][j - 1];
1828 4949720 : wm->rbop[i - 1][i - 1] = rbadjPhi[i - 1][j - 1];
1829 : }
1830 :
1831 : // Calculate glazing system properties
1832 3335170 : if (ngllayer == 1) { // Single-layer system
1833 1899520 : stPhi[j - 1] = wm->top[0][0];
1834 1899520 : srfPhi[j - 1] = wm->rfop[0][0];
1835 1899520 : srbPhi[j - 1] = wm->rbop[0][0];
1836 1899520 : sabsPhi(1) = 1.0 - stPhi[j - 1] - srfPhi[j - 1];
1837 : } else { // Multilayer system
1838 : // Get glazing system properties stPhi, etc., at this wavelength and incidence angle
1839 1435650 : SystemPropertiesAtLambdaAndPhi(state, ngllayer, stPhi[j - 1], srfPhi[j - 1], srbPhi[j - 1], sabsPhi);
1840 : }
1841 :
1842 8284890 : for (int i = 1; i <= ngllayer; ++i) {
1843 4949720 : saPhi(i, j) = sabsPhi(i);
1844 : }
1845 :
1846 : } // End of wavelength loop
1847 39830 : } // SystemSpectralPropertiesAtPhi()
1848 :
1849 : //************************************************************************
1850 :
1851 1435650 : void SystemPropertiesAtLambdaAndPhi(EnergyPlusData &state,
1852 : int const n, // Number of glass layers
1853 : Real64 &tt, // System transmittance
1854 : Real64 &rft, // System front and back reflectance
1855 : Real64 &rbt,
1856 : Array1A<Real64> aft // System absorptance of each glass layer
1857 : )
1858 : {
1859 :
1860 : // SUBROUTINE INFORMATION:
1861 : // AUTHOR Adapted by F. Winkelmann from WINDOW 5
1862 : // subroutine op
1863 : // DATE WRITTEN August 1999
1864 : // MODIFIED na
1865 : // RE-ENGINEERED na
1866 :
1867 : // PURPOSE OF THIS SUBROUTINE:
1868 : // For a given angle of incidence, finds the overall properties of
1869 : // of a series of layers at a particular wavelength
1870 :
1871 : // Argument array dimensioning
1872 1435650 : aft.dim(5);
1873 :
1874 : Real64 denom; // Intermediate variables
1875 : Real64 denom1;
1876 : Real64 denom2;
1877 : Real64 t0; // Transmittance, back reflectance and front
1878 : Real64 rb0;
1879 : Real64 rf0;
1880 : // reflectance variables
1881 : Real64 af; // Front and back absorptance variables
1882 : Real64 ab;
1883 :
1884 1435650 : auto &wm = state.dataWindowManager;
1885 : // Calculate perimeter elements of rt matrix
1886 3050200 : for (int i = 1; i <= n - 1; ++i) {
1887 3422940 : for (int j = i + 1; j <= n; ++j) {
1888 1808390 : denom = 1.0 - wm->rfop[j - 1][j - 1] * wm->rbop[i - 1][j - 2];
1889 1808390 : if (denom == 0.0) {
1890 180839 : wm->top[j - 1][i - 1] = 0.0;
1891 180839 : wm->rfop[j - 1][i - 1] = 1.0;
1892 180839 : wm->rbop[i - 1][j - 1] = 1.0;
1893 : } else {
1894 1627551 : wm->top[j - 1][i - 1] = wm->top[j - 2][i - 1] * wm->top[j - 1][j - 1] / denom;
1895 1627551 : 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;
1896 1627551 : 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;
1897 : }
1898 : }
1899 : }
1900 : // System properties: transmittance, front and back reflectance
1901 1435650 : tt = wm->top[n - 1][0];
1902 1435650 : rft = wm->rfop[n - 1][0];
1903 1435650 : rbt = wm->rbop[0][n - 1];
1904 :
1905 : // Absorptance in each layer
1906 4485850 : for (int j = 1; j <= n; ++j) {
1907 3050200 : if (j == 1) {
1908 1435650 : t0 = 1.0;
1909 1435650 : rb0 = 0.0;
1910 : } else {
1911 1614550 : t0 = wm->top[j - 2][0];
1912 1614550 : rb0 = wm->rbop[0][j - 2];
1913 : }
1914 :
1915 3050200 : if (j == n) {
1916 1435650 : rf0 = 0.0;
1917 : } else {
1918 1614550 : rf0 = wm->rfop[n - 1][j];
1919 : }
1920 :
1921 3050200 : af = 1.0 - wm->top[j - 1][j - 1] - wm->rfop[j - 1][j - 1];
1922 3050200 : ab = 1.0 - wm->top[j - 1][j - 1] - wm->rbop[j - 1][j - 1];
1923 3050200 : denom1 = 1.0 - wm->rfop[n - 1][j - 1] * rb0;
1924 3050200 : denom2 = 1.0 - wm->rbop[0][j - 1] * rf0;
1925 :
1926 3050200 : if (denom1 == 0.0 || denom2 == 0.0) {
1927 305020 : aft(j) = 0.0;
1928 : } else {
1929 2745180 : aft(j) = (t0 * af) / denom1 + (wm->top[j - 1][0] * rf0 * ab) / denom2;
1930 : }
1931 : }
1932 1435650 : } // SystemPropertiesAtLambdaAndPhi()
1933 :
1934 80700 : Real64 solarSpectrumAverage(EnergyPlusData &state, gsl::span<Real64 const> p)
1935 : {
1936 80700 : Real64 num = 0.0;
1937 80700 : Real64 denom = 0.0;
1938 80700 : auto &wm = state.dataWindowManager;
1939 :
1940 8634900 : for (int i = 1; i <= nume - 1; ++i) {
1941 8554200 : Real64 const esol = (wm->wle[i] - wm->wle[i - 1]) * 0.5 * (wm->e[i - 1] + wm->e[i]);
1942 8554200 : num += 0.5 * (p[i - 1] + p[i]) * esol;
1943 8554200 : denom += esol;
1944 : }
1945 80700 : return num / denom; // dangerous, doesn't check for zero denominator
1946 : }
1947 :
1948 40440 : Real64 visibleSpectrumAverage(EnergyPlusData &state, gsl::span<Real64 const> p)
1949 : {
1950 : // AUTHOR Adapted by F.Winkelmann from WINDOW 5
1951 : // subroutine w4vis
1952 : // DATE WRITTEN August 1999
1953 :
1954 : // Calculates visible average of property p by weighting with solar
1955 : // spectral irradiance, e, and photopic response, y30
1956 :
1957 40440 : Real64 num = 0.0;
1958 40440 : Real64 denom = 0.0;
1959 40440 : Real64 y30new = 0.0;
1960 40440 : Real64 y30ils1 = 0.0;
1961 :
1962 40440 : auto &wm = state.dataWindowManager;
1963 :
1964 4327080 : for (int i = 2; i <= nume; ++i) { // Autodesk:BoundsViolation e|wle|p(i-1) @ i=1: Changed start index from 1 to 2: wle
1965 : // values prevented this violation from occurring in practice
1966 : // Restrict to visible range
1967 4286640 : if (wm->wle[i - 1] >= 0.37 && wm->wle[i - 1] <= 0.78) {
1968 1415400 : y30new = Interpolate(wm->wlt3, wm->y30, numt3, wm->wle[i - 1]);
1969 1415400 : Real64 evis = wm->e[i - 2] * 0.5 * (y30new + y30ils1) * (wm->wle[i - 1] - wm->wle[i - 2]);
1970 1415400 : num += 0.5 * (p[i - 1] + p[i - 2]) * evis;
1971 1415400 : denom += evis;
1972 1415400 : y30ils1 = y30new;
1973 : }
1974 : }
1975 40440 : return num / denom; // dangerous, doesn't check for zero denominator
1976 : }
1977 :
1978 2833500 : Real64 Interpolate(gsl::span<Real64 const> x, // Array of data points for independent variable
1979 : gsl::span<Real64 const> y, // Array of data points for dependent variable
1980 : int const npts, // Number of data pairs
1981 : Real64 const xin // Given value of x
1982 : )
1983 : {
1984 :
1985 : // SUBROUTINE INFORMATION:
1986 : // AUTHOR Adapted by F.Winkelmann from WINDOW 5 subroutine interp
1987 : // DATE WRITTEN August 1999
1988 : // MODIFIED na
1989 : // RE-ENGINEERED na
1990 :
1991 : // PURPOSE OF THIS SUBROUTINE:
1992 : // Linearly interpolates between data points. Outputs yout, interpolated
1993 : // value of y corresponding to xin
1994 :
1995 170882220 : for (int i = 1; i <= npts; ++i) {
1996 170869440 : if (xin <= x[i - 1]) {
1997 2820720 : if (i - 1 == 0) {
1998 93780 : return y[0];
1999 : } else {
2000 2726940 : return y[i - 2] + (y[i - 1] - y[i - 2]) * (xin - x[i - 2]) / (x[i - 1] - x[i - 2]);
2001 : }
2002 : }
2003 : }
2004 :
2005 : // Past the end of the array, so return endpoint
2006 12780 : return y[npts - 1];
2007 : }
2008 :
2009 : //***********************************************************************************
2010 : // Window Thermal Calculation Subroutines
2011 : //***********************************************************************************
2012 :
2013 24123715 : void CalcWindowHeatBalance(EnergyPlusData &state,
2014 : int const SurfNum, // Surface number
2015 : Real64 const HextConvCoeff, // Outside air film conductance coefficient
2016 : Real64 &SurfInsideTemp, // Inside window surface temperature
2017 : Real64 &SurfOutsideTemp // Outside surface temperature (C)
2018 : )
2019 : {
2020 : // SUBROUTINE INFORMATION:
2021 : // AUTHOR S. Vidanovic
2022 : // DATE WRITTEN June 2016
2023 : // MODIFIED na
2024 : // RE-ENGINEERED na
2025 : //
2026 : // PURPOSE OF THIS SUBROUTINE:
2027 : // Subroutine to direct whether to use exterior or interior window routines
2028 24123715 : auto &wm = state.dataWindowManager;
2029 :
2030 24123715 : if (state.dataGlobal->KickOffSizing || state.dataGlobal->KickOffSimulation) return;
2031 :
2032 24014701 : if (wm->inExtWindowModel->isExternalLibraryModel()) {
2033 4032 : CalcWindowHeatBalanceExternalRoutines(state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp);
2034 : } else {
2035 24010669 : CalcWindowHeatBalanceInternalRoutines(state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp);
2036 : }
2037 : }
2038 :
2039 24010669 : void CalcWindowHeatBalanceInternalRoutines(EnergyPlusData &state,
2040 : int const SurfNum, // Surface number
2041 : Real64 const HextConvCoeff, // Outside air film conductance coefficient
2042 : Real64 &SurfInsideTemp, // Inside window surface temperature
2043 : Real64 &SurfOutsideTemp // Outside surface temperature (C)
2044 : )
2045 : {
2046 :
2047 : // SUBROUTINE INFORMATION:
2048 : // AUTHOR F. Winkelmann
2049 : // DATE WRITTEN November 1999
2050 : // MODIFIED FW, July 2000 (call better solution method)
2051 : // FW, June 2001 (handle window blinds)
2052 : // FW, Dec 2002 (add between-glass shades and blinds)
2053 : // FW, Mar 2003 (extend condensation flag to airflow windows)
2054 : // CC, Jul 2003 (set the reference temperatures for inside surface heat balance
2055 : // depending on convection algorithms and/or air models used)
2056 : // FW, Sep 2003 (increment ZoneWinHeatGain only for exterior windows)
2057 : // RR, May 2006 (add exterior window screen)
2058 : // TH, Dec 2008 (add thermochromic windows)
2059 : // RE-ENGINEERED na
2060 :
2061 : // PURPOSE OF THIS SUBROUTINE:
2062 : // Sets up information needed to calculate the window thermal behavior.
2063 : // Calls SolveForWindowTemperatures, which calculates the inside and outside
2064 : // face temperature of each glass layer by solving the heat balance
2065 : // equations on each face. Also calls CalcWinFrameAndDividerTemps,
2066 : // which calculates the outside and inside face temperatures of the
2067 : // window frame and divider if either of these are present.
2068 : // The resulting inside face temperature of the inner glass pane and the
2069 : // inside surface temperatures of frame and divider are used in the zone
2070 : // heat balance calculation. The inside face temperature of an interior shade
2071 : // or blind, if present, and the natural convection air flow between the
2072 : // shade/blind and inside glass face also appear in the zone heat balance calculation.
2073 : // The logical variable NRSolution is currently set to false, which means
2074 : // that the Newton-Raphson solution method for the glass layer heat balance
2075 : // is not used (because it sometimes didn't converge for 3- and 4-pane
2076 : // constructions with one or more low-emissivity layers). Instead, a more
2077 : // robust solution method is used that successively solves linearized heat
2078 : // balance equations until convergence is reached (see SolveForWindowTemperatures).
2079 : // CalcWindowHeatBalance is called by CalcHeatBalanceInsideSurface once each
2080 : // time step for each window.
2081 :
2082 : // Using/Aliasing
2083 : using namespace DataBSDFWindow;
2084 : using Psychrometrics::PsyCpAirFnW;
2085 : using Psychrometrics::PsyTdpFnWPb;
2086 : // unused0909 USE DataEnvironment, ONLY: CurMnDyHr
2087 : using ScheduleManager::GetCurrentScheduleValue;
2088 : using WindowComplexManager::CalcComplexWindowThermal;
2089 : using WindowEquivalentLayer::EQLWindowSurfaceHeatBalance;
2090 :
2091 : // SUBROUTINE ARGUMENT DEFINITIONS:
2092 : // (temperature of innermost face) [C]
2093 :
2094 : int BlNum; // Window blind number
2095 : int SurfNumAdj; // An interzone surface's number in the adjacent zone
2096 : int ZoneNumAdj; // An interzone surface's adjacent zone number
2097 : int TotLay; // Total number of layers in a construction
2098 : // (sum of solid layers and gap layers)
2099 : int TotGlassLay; // Total number of glass layers in a construction
2100 : int Lay; // Layer number
2101 : int LayPtr; // Material number for a layer
2102 : WinShadingType ShadeFlag; // Flag indicating whether shade or blind is on, and shade/blind position
2103 : int k; // Layer counter
2104 : // REAL(r64) :: tsky ! Sky temperature [K]
2105 : int ShadeLayPtr; // Material number corresponding to a shade layer
2106 : Real64 dth1; // Temperature difference across glass layers [K]
2107 : Real64 dth2;
2108 : Real64 dth3;
2109 : Real64 dth4;
2110 : Real64 EffShBlEmiss; // Effective interior shade or blind emissivity
2111 : Real64 EffGlEmiss; // Effective inside glass emissivity when interior shade or blind
2112 : Real64 RoomHumRat; // Room air humidity ratio
2113 : Real64 RoomDewPoint; // Room air dewpoint temperature (C)
2114 : Real64 InsideGlassTemp; // Temperature of room side of innermost glass layer (C)
2115 : Real64 Tleft; // For airflow windows, temperature of the glass faces adjacent
2116 : Real64 Tright;
2117 :
2118 : Real64 SrdSurfTempAbs; // Absolute temperature of a surrounding surface
2119 : Real64 OutSrdIR; // LWR from surrouding srfs
2120 :
2121 : // New variables for thermochromic windows calc
2122 : Real64 locTCSpecTemp; // The temperature corresponding to the specified optical properties of the TC layer
2123 : Real64 locTCLayerTemp; // TC layer temperature at each time step. C
2124 :
2125 24010669 : auto &wm = state.dataWindowManager;
2126 :
2127 24010669 : Real64 dT0(0.0);
2128 24010669 : Real64 dT1(0.0);
2129 : Real64 SurfOutsideEmiss; // temporary for result of outside surface emissivity
2130 : Real64 Tsout; // temporary for result of outside surface temp in Kelvin
2131 : int temp;
2132 :
2133 24010669 : Array1D<Real64> deltaTemp(100, 0.0);
2134 24010669 : Array1D_int iMinDT(1, 0);
2135 24010669 : Array1D_int IDConst(100, 0);
2136 :
2137 : // Shorthand references
2138 24010669 : auto &window = state.dataSurface->SurfaceWindow(SurfNum);
2139 24010669 : auto &surface = state.dataSurface->Surface(SurfNum);
2140 24010669 : int ConstrNum = state.dataSurface->SurfActiveConstruction(SurfNum);
2141 24010669 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(surface.Zone);
2142 :
2143 24010669 : if (state.dataSurface->SurfWinWindowModelType(SurfNum) == WindowModel::BSDF) {
2144 :
2145 37968 : temp = 0;
2146 :
2147 : // Simon: Complex fenestration state works only with tarcog
2148 37968 : CalcComplexWindowThermal(
2149 : state, SurfNum, temp, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp, SurfOutsideEmiss, DataBSDFWindow::Condition::Invalid);
2150 :
2151 37968 : TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
2152 37968 : wm->ngllayer = state.dataConstruction->Construct(ConstrNum).TotSolidLayers; // Simon: This is necessary to keep for frame calculations
2153 : // Simon: need to transfer surface temperatures because of frames calculation
2154 :
2155 250992 : for (int i = 1; i <= 2 * state.dataConstruction->Construct(ConstrNum).TotSolidLayers; ++i) {
2156 213024 : wm->thetas[i - 1] = window.thetaFace[i];
2157 : }
2158 37968 : wm->hcout = HextConvCoeff;
2159 37968 : wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
2160 37968 : wm->tin = thisZoneHB.MAT + Constant::Kelvin; // Inside air temperature
2161 :
2162 : // This is code repeating and it is necessary to calculate report variables. Do not know
2163 : // how to solve this in more elegant way :(
2164 37968 : if (surface.ExtWind) { // Window is exposed to wind (and possibly rain)
2165 37968 : if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
2166 0 : wm->tout = state.dataSurface->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
2167 : } else { // Dry
2168 37968 : wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2169 : }
2170 : } else { // Window not exposed to wind
2171 0 : wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2172 : }
2173 :
2174 37968 : wm->Ebout = Constant::StefanBoltzmann * pow_4(wm->tout);
2175 37968 : wm->Outir = surface.ViewFactorSkyIR *
2176 37968 : (state.dataSurface->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(state.dataEnvrn->SkyTempKelvin) +
2177 37968 : (1.0 - state.dataSurface->SurfAirSkyRadSplit(SurfNum)) * wm->Ebout) +
2178 37968 : surface.ViewFactorGroundIR * wm->Ebout;
2179 :
2180 23972701 : } else if (state.dataSurface->SurfWinWindowModelType(SurfNum) == WindowModel::EQL) {
2181 :
2182 8064 : EQLWindowSurfaceHeatBalance(
2183 : state, SurfNum, HextConvCoeff, SurfInsideTemp, SurfOutsideTemp, SurfOutsideEmiss, DataBSDFWindow::Condition::Invalid);
2184 8064 : wm->hcout = HextConvCoeff;
2185 : // Required for report variables calculations.
2186 8064 : if (surface.ExtWind) { // Window is exposed to wind (and possibly rain)
2187 8064 : if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
2188 0 : wm->tout = state.dataSurface->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
2189 : } else { // Dry
2190 8064 : wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2191 : }
2192 : } else { // Window not exposed to wind
2193 0 : wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2194 : }
2195 :
2196 : } else { // regular window, not BSDF, not EQL Window
2197 : // Added for thermochromic windows
2198 23964637 : wm->locTCFlag = (state.dataConstruction->Construct(ConstrNum).TCFlag == 1);
2199 :
2200 23964637 : if (wm->locTCFlag) {
2201 : auto const *thisMaterial =
2202 4032 : dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).TCLayer));
2203 4032 : assert(thisMaterial != nullptr);
2204 4032 : locTCSpecTemp = thisMaterial->SpecTemp;
2205 4032 : state.dataSurface->SurfWinSpecTemp(SurfNum) = locTCSpecTemp;
2206 : // Check to see whether needs to switch to a new TC window construction
2207 4032 : locTCLayerTemp = state.dataSurface->SurfWinTCLayerTemp(SurfNum);
2208 4032 : dT0 = std::abs(locTCLayerTemp - locTCSpecTemp);
2209 4032 : if (dT0 >= 1) {
2210 : // Find the TC construction that is closed to the TCLayerTemp
2211 2509 : int i = 0;
2212 2509 : deltaTemp = 0.0;
2213 2509 : IDConst = 0;
2214 82797 : for (int k = 1; k <= state.dataHeatBal->TotConstructs; ++k) {
2215 80288 : if (state.dataConstruction->Construct(k).TCMasterConst == state.dataConstruction->Construct(ConstrNum).TCMasterConst) {
2216 50180 : dT1 = std::abs(locTCLayerTemp - dynamic_cast<Material::MaterialChild *>(
2217 50180 : state.dataMaterial->Material(state.dataConstruction->Construct(k).TCLayer))
2218 50180 : ->SpecTemp);
2219 50180 : if (dT1 < dT0) {
2220 327 : ++i;
2221 327 : deltaTemp(i) = dT1;
2222 327 : IDConst(i) = k;
2223 : }
2224 : }
2225 : }
2226 2509 : if (i >= 1) {
2227 : // Find the closest item
2228 313 : iMinDT = minloc(deltaTemp, deltaTemp > 0.0);
2229 : // Use the new TC window construction
2230 313 : ConstrNum = IDConst(iMinDT(1));
2231 313 : surface.Construction = ConstrNum;
2232 313 : state.dataSurface->SurfActiveConstruction(SurfNum) = ConstrNum;
2233 313 : state.dataSurface->SurfWinSpecTemp(SurfNum) =
2234 313 : dynamic_cast<Material::MaterialChild *>(
2235 313 : state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).TCLayer))
2236 313 : ->SpecTemp;
2237 : }
2238 : }
2239 : }
2240 : // end new TC code
2241 :
2242 23964637 : TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
2243 23964637 : TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
2244 23964637 : wm->ngllayer = TotGlassLay;
2245 23964637 : wm->nglface = 2 * wm->ngllayer;
2246 23964637 : ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
2247 23964637 : wm->tilt = surface.Tilt;
2248 23964637 : wm->tiltr = wm->tilt * Constant::DegToRadians;
2249 23964637 : SurfNumAdj = surface.ExtBoundCond;
2250 23964637 : wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum); // Room-side surface convective film conductance
2251 23964637 : Real64 RefAirTemp = state.dataSurface->Surface(SurfNum).getInsideAirTemperature(state, SurfNum);
2252 23964637 : state.dataHeatBal->SurfTempEffBulkAir(SurfNum) = RefAirTemp;
2253 23964637 : wm->tin = RefAirTemp + Constant::Kelvin; // Inside air temperature
2254 :
2255 : // Reset hcin if necessary since too small a value sometimes causes non-convergence
2256 : // of window layer heat balance solution.
2257 23964637 : if (state.dataSurface->surfIntConv(SurfNum).model == Convect::HcInt::SetByZone) {
2258 : // may be redundent now, check is also in HeatBalanceConvectionCoeffs.cc
2259 23964637 : if (wm->hcin <= state.dataHeatBal->LowHConvLimit) {
2260 : // hcin = 3.076d0 !BG this is rather high value and abrupt change. changed to set to lower limit
2261 23159 : wm->hcin = state.dataHeatBal->LowHConvLimit;
2262 23159 : state.dataHeatBalSurf->SurfHConvInt(SurfNum) = wm->hcin; // store for accurate reporting.
2263 : }
2264 : }
2265 :
2266 : // IR incident on window from zone surfaces and high-temp radiant sources
2267 23964637 : wm->Rmir = state.dataSurface->SurfWinIRfromParentZone(SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum);
2268 :
2269 : // Short-wave radiation (from interior and exterior solar and zone lights)
2270 : // absorbed at each face. Assumes equal split between faces of short-wave absorbed in glass layer.
2271 :
2272 54910169 : for (int IGlass = 1; IGlass <= TotGlassLay; ++IGlass) {
2273 30945532 : wm->AbsRadGlassFace[2 * IGlass - 2] = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, IGlass) / 2.0;
2274 30945532 : wm->AbsRadGlassFace[2 * IGlass - 1] = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, IGlass) / 2.0;
2275 : }
2276 :
2277 : // IR from zone internal gains (lights, equipment and people) absorbed on zone-side face
2278 : // (assumes inside glass layer is opaque to IR, so no contribution to other layers)
2279 23964637 : wm->AbsRadGlassFace[2 * TotGlassLay - 1] += state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNum);
2280 :
2281 : // Fill the layer properties needed for the thermal calculation.
2282 : // For switchable glazing it is assumed that thermal properties, such
2283 : // as surface emissivity, are the same for the unswitched and switched state,
2284 : // so the thermal properties of the unswitched state are used.
2285 : // For windows with a blind or shade it is assumed
2286 : // that the blind or shade does not affect the thermal properties of the glazing,
2287 : // so the thermal properties of the construction without the blind or shade are used.
2288 :
2289 : // The layer and face numbering are as follows (for the triple glazing case):
2290 : // Glass layers are 1,2 and 3, where 1 is the outside (outside environment facing)
2291 : // layer and 3 is the inside (room-facing) layer;
2292 : // Faces (also called surfaces) are 1,2,3,4,5 and 6, where face 1 is the
2293 : // outside (front) face of glass layer 1, face 2 is the inside (back)
2294 : // face of glass layer 1, face 3 is the outer face of glass layer 2, face 4 is the
2295 : // inner face of glass layer 2, etc.
2296 : // Gap layers are 1 and 2, where gap layer 1 is between glass layers 1 and 2
2297 : // and gap layer 2 is between glass layers 2 and 3.
2298 : // If an exterior, interior or between-glass blind or shade is in place, 7 and 8
2299 : // are the blind/shade faces, from outside to inside. If an exterior or interior
2300 : // blind/shade is in place, gap layer 3 is between the blind/shade and adjacent
2301 : // glass layer and is assumed to be air.
2302 : // Between-glass blind/shade is modeled only for double and triple glazing.
2303 : // For double glazing, gap 1 is between glass 1 and blind/shade and gap 2 is between
2304 : // blind/shade and glass 2.
2305 : // For triple glazing, the blind/shade is assumed to be between the inner two glass
2306 : // layers, i.e., between glass layers 2 and 3. In this case gap 1 is between glass 1
2307 : // and glass 2, gap 2 is between glass 2 and blind/shade, and gap 3 is between
2308 : // blind/shade and glass 3.
2309 :
2310 23964637 : int IConst = ConstrNum;
2311 23964637 : if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
2312 186115 : IConst = state.dataSurface->SurfWinActiveShadedConstruction(SurfNum);
2313 : }
2314 23964637 : TotLay = state.dataConstruction->Construct(IConst).TotLayers;
2315 23964637 : int IGlass = 0;
2316 23964637 : int IGap = 0;
2317 :
2318 : // Fill window layer properties needed for window layer heat balance calculation
2319 :
2320 62094049 : for (int Lay = 1; Lay <= TotLay; ++Lay) {
2321 38129412 : LayPtr = state.dataConstruction->Construct(IConst).LayerPoint(Lay);
2322 38129412 : auto const *mat = state.dataMaterial->Material(LayPtr);
2323 :
2324 38129412 : if ((mat->group == Material::Group::WindowGlass) || (mat->group == Material::Group::WindowSimpleGlazing)) {
2325 30945532 : ++IGlass;
2326 30945532 : wm->thick[IGlass - 1] = mat->Thickness;
2327 30945532 : wm->scon[IGlass - 1] = mat->Conductivity / mat->Thickness;
2328 30945532 : wm->emis[2 * IGlass - 2] = mat->AbsorpThermalFront;
2329 30945532 : wm->emis[2 * IGlass - 1] = mat->AbsorpThermalBack;
2330 30945532 : wm->tir[2 * IGlass - 2] = mat->TransThermal;
2331 30945532 : wm->tir[2 * IGlass - 1] = mat->TransThermal;
2332 : }
2333 :
2334 38129412 : if (mat->group == Material::Group::Shade || mat->group == Material::Group::WindowBlind || mat->group == Material::Group::Screen) {
2335 186115 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag))
2336 147791 : ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(state.dataConstruction->Construct(IConst).TotLayers);
2337 186115 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(1);
2338 186115 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
2339 16870 : ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(3);
2340 16870 : if (TotGlassLay == 3) ShadeLayPtr = state.dataConstruction->Construct(IConst).LayerPoint(5);
2341 : }
2342 186115 : auto const *matShade = state.dataMaterial->Material(ShadeLayPtr);
2343 186115 : assert(matShade != nullptr);
2344 186115 : if (ANY_SHADE_SCREEN(ShadeFlag)) {
2345 : // Shade or screen on
2346 49460 : if (state.dataGlobal
2347 49460 : ->AnyEnergyManagementSystemInModel) { // check to make sure the user hasn't messed up the shade control values
2348 0 : if (matShade->group == Material::Group::WindowBlind) {
2349 0 : ShowSevereError(
2350 : state,
2351 0 : format("CalcWindowHeatBalance: ShadeFlag indicates Shade but Blind=\"{}\" is being used.", matShade->Name));
2352 0 : ShowContinueError(state, "This is most likely a fault of the EMS values for shading control.");
2353 0 : ShowFatalError(state, "Preceding condition terminates program.");
2354 : }
2355 : }
2356 49460 : wm->thick[TotGlassLay] = matShade->Thickness;
2357 49460 : wm->scon[TotGlassLay] = matShade->Conductivity / matShade->Thickness;
2358 49460 : if (ShadeFlag == WinShadingType::ExtScreen) {
2359 5376 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(matShade);
2360 5376 : assert(matScreen != nullptr);
2361 5376 : wm->emis[wm->nglface] = matScreen->AbsorpThermalFront;
2362 5376 : wm->tir[wm->nglface] = matScreen->DfTrans;
2363 5376 : wm->tir[wm->nglface + 1] = matScreen->DfTrans;
2364 : } else {
2365 44084 : wm->emis[wm->nglface] = matShade->AbsorpThermal;
2366 44084 : wm->tir[wm->nglface] = matShade->TransThermal;
2367 44084 : wm->tir[wm->nglface + 1] = matShade->TransThermal;
2368 : }
2369 49460 : wm->emis[wm->nglface + 1] = matShade->AbsorpThermal;
2370 :
2371 : } else {
2372 136655 : if (state.dataGlobal
2373 136655 : ->AnyEnergyManagementSystemInModel) { // check to make sure the user hasn't messed up the shade control values
2374 123047 : if (matShade->group == Material::Group::Shade || matShade->group == Material::Group::Screen) {
2375 0 : ShowSevereError(state,
2376 0 : format("CalcWindowHeatBalance: ShadeFlag indicates Blind but Shade/Screen=\"{}\" is being used.",
2377 0 : matShade->Name));
2378 0 : ShowContinueError(state, "This is most likely a fault of the EMS values for shading control.");
2379 0 : ShowFatalError(state, "Preceding condition terminates program.");
2380 : }
2381 : }
2382 : // Blind on
2383 136655 : BlNum = state.dataSurface->SurfWinBlindNumber(SurfNum);
2384 136655 : auto const &blind = state.dataMaterial->Blind(BlNum);
2385 136655 : wm->thick[TotGlassLay] = blind.SlatThickness;
2386 136655 : wm->scon[TotGlassLay] = blind.SlatConductivity / blind.SlatThickness;
2387 :
2388 136655 : if (state.dataSurface->SurfWinMovableSlats(SurfNum)) {
2389 3122 : int slatAngIndex = state.dataSurface->SurfWinSlatsAngIndex(SurfNum);
2390 3122 : int slatAngIndex2 = std::min(Material::MaxSlatAngs, slatAngIndex + 1);
2391 :
2392 3122 : Real64 interpFac = state.dataSurface->SurfWinSlatsAngInterpFac(SurfNum);
2393 3122 : wm->emis[wm->nglface] = General::Interp(blind.IRFrontEmiss(slatAngIndex), blind.IRFrontEmiss(slatAngIndex2), interpFac);
2394 3122 : wm->emis[wm->nglface + 1] = General::Interp(blind.IRBackEmiss(slatAngIndex), blind.IRBackEmiss(slatAngIndex2), interpFac);
2395 3122 : wm->tir[wm->nglface] = General::Interp(blind.IRFrontTrans(slatAngIndex), blind.IRFrontTrans(slatAngIndex2), interpFac);
2396 3122 : wm->tir[wm->nglface + 1] = General::Interp(blind.IRBackTrans(slatAngIndex), blind.IRBackTrans(slatAngIndex2), interpFac);
2397 : } else {
2398 133533 : wm->emis[wm->nglface] = blind.IRFrontEmiss(1);
2399 133533 : wm->emis[wm->nglface + 1] = blind.IRBackEmiss(1);
2400 133533 : wm->tir[wm->nglface] = blind.IRFrontTrans(1);
2401 133533 : wm->tir[wm->nglface + 1] = blind.IRBackTrans(1);
2402 : }
2403 : }
2404 : }
2405 :
2406 38129412 : if (mat->group == Material::Group::WindowGas || mat->group == Material::Group::WindowGasMixture) {
2407 6997765 : ++IGap;
2408 6997765 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(state.dataMaterial->Material(LayPtr));
2409 6997765 : assert(matGas != nullptr);
2410 6997765 : wm->gaps[IGap - 1].width = matGas->Thickness;
2411 6997765 : wm->gaps[IGap - 1].numGases = matGas->numGases;
2412 14051978 : for (int IMix = 0; IMix < wm->gaps[IGap - 1].numGases; ++IMix) {
2413 7054213 : wm->gaps[IGap - 1].gases[IMix] = matGas->gases[IMix];
2414 7054213 : wm->gaps[IGap - 1].gasFracts[IMix] = matGas->gasFracts[IMix];
2415 : }
2416 : }
2417 :
2418 : } // End of loop over glass, gap and blind/shade layers in a window construction
2419 :
2420 23964637 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2421 : // Interior or exterior blind, shade or screen is on.
2422 : // Fill gap between blind/shade and adjacent glass with air properties.
2423 169245 : ++IGap;
2424 169245 : if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) // Interior or exterior shade
2425 36020 : wm->gaps[IGap - 1].width =
2426 36020 : dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(ShadeLayPtr))->WinShadeToGlassDist;
2427 133225 : else if (ShadeFlag == WinShadingType::ExtScreen) {
2428 5376 : wm->gaps[IGap - 1].width = dynamic_cast<Material::MaterialScreen const *>(state.dataMaterial->Material(ShadeLayPtr))->toGlassDist;
2429 : } else { // Interior or exterior blind
2430 127849 : wm->gaps[IGap - 1].width = state.dataMaterial->Blind(state.dataSurface->SurfWinBlindNumber(SurfNum)).BlindToGlassDist;
2431 : }
2432 169245 : wm->gaps[IGap - 1].numGases = 1;
2433 :
2434 169245 : wm->gaps[IGap - 1].gases[0] = Material::gases[(int)Material::GasType::Air];
2435 169245 : wm->gaps[IGap - 1].gasFracts[0] = 1;
2436 : }
2437 :
2438 : // Exterior convection coefficient, exterior air temperature and IR radiance
2439 : // of exterior surround. Depend on whether window is interzone (in an interzone
2440 : // wall or exterior (in an exterior wall).
2441 :
2442 23964637 : wm->hcout = HextConvCoeff; // Exterior convection coefficient is passed in from outer routine
2443 : // tsky = SkyTemp + TKelvin
2444 :
2445 23964637 : if (SurfNumAdj > 0) { // Interzone window
2446 :
2447 27072 : ZoneNumAdj = state.dataSurface->Surface(SurfNumAdj).Zone;
2448 27072 : Real64 RefAirTemp = state.dataSurface->Surface(SurfNumAdj).getInsideAirTemperature(state, SurfNumAdj);
2449 27072 : state.dataHeatBal->SurfTempEffBulkAir(SurfNumAdj) = RefAirTemp;
2450 27072 : wm->tout = RefAirTemp + Constant::Kelvin; // outside air temperature
2451 :
2452 : // Add long-wave radiation from adjacent zone absorbed by glass layer closest to the adjacent zone.
2453 27072 : wm->AbsRadGlassFace[0] += state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNumAdj);
2454 :
2455 : // The IR radiance of this window's "exterior" surround is the IR radiance
2456 : // from surfaces and high-temp radiant sources in the adjacent zone
2457 :
2458 27072 : wm->Outir = state.dataSurface->SurfWinIRfromParentZone(SurfNumAdj) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNumAdj);
2459 :
2460 : } else { // Exterior window (Ext BoundCond = 0)
2461 : // Calculate LWR from surrounding surfaces if defined for an exterior window
2462 23937565 : OutSrdIR = 0;
2463 23937565 : if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
2464 133056 : if (state.dataSurface->Surface(SurfNum).SurfHasSurroundingSurfProperty) {
2465 2688 : SrdSurfTempAbs = surface.SrdSurfTemp + Constant::Kelvin;
2466 2688 : OutSrdIR = Constant::StefanBoltzmann * surface.ViewFactorSrdSurfs * pow_4(SrdSurfTempAbs);
2467 : }
2468 : }
2469 23937565 : if (surface.ExtWind) { // Window is exposed to wind (and possibly rain)
2470 23937565 : if (state.dataEnvrn->IsRain) { // Raining: since wind exposed, outside window surface gets wet
2471 5844 : wm->tout = state.dataSurface->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
2472 : } else { // Dry
2473 23931721 : wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2474 : }
2475 : } else { // Window not exposed to wind
2476 0 : wm->tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
2477 : }
2478 23937565 : wm->Ebout = Constant::StefanBoltzmann * pow_4(wm->tout);
2479 23937565 : wm->Outir = surface.ViewFactorSkyIR *
2480 23937565 : (state.dataSurface->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(state.dataEnvrn->SkyTempKelvin) +
2481 23937565 : (1.0 - state.dataSurface->SurfAirSkyRadSplit(SurfNum)) * wm->Ebout) +
2482 23937565 : surface.ViewFactorGroundIR * wm->Ebout + OutSrdIR;
2483 : }
2484 :
2485 : // Factors used in window layer temperature solution
2486 23964637 : if (wm->ngllayer >= 2) {
2487 6837855 : wm->A23P = -wm->emis[2] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
2488 6837855 : wm->A32P = wm->emis[1] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
2489 6837855 : wm->A23 = wm->emis[1] * Constant::StefanBoltzmann * wm->A23P;
2490 : }
2491 :
2492 23964637 : if (wm->ngllayer >= 3) {
2493 92352 : wm->A45P = -wm->emis[4] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
2494 92352 : wm->A54P = wm->emis[3] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
2495 92352 : wm->A45 = wm->emis[3] * Constant::StefanBoltzmann * wm->A45P;
2496 : }
2497 :
2498 23964637 : if (wm->ngllayer == 4) {
2499 50688 : wm->A67P = -wm->emis[6] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
2500 50688 : wm->A76P = wm->emis[5] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
2501 50688 : wm->A67 = wm->emis[5] * Constant::StefanBoltzmann * wm->A67P;
2502 : }
2503 :
2504 23964637 : wm->thetas = {0.0};
2505 23964637 : wm->thetasPrev = {0.0};
2506 23964637 : wm->fvec = {0.0};
2507 :
2508 : // Calculate window face temperatures
2509 :
2510 23964637 : SolveForWindowTemperatures(state, SurfNum);
2511 :
2512 : // Temperature difference across glass layers (for debugging)
2513 :
2514 23964637 : dth1 = wm->thetas[1] - wm->thetas[0];
2515 23964637 : dth2 = wm->thetas[3] - wm->thetas[2];
2516 23964637 : dth3 = wm->thetas[5] - wm->thetas[4];
2517 23964637 : dth4 = wm->thetas[7] - wm->thetas[6];
2518 :
2519 23964637 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
2520 147791 : SurfInsideTemp = wm->thetas[2 * wm->ngllayer + 1] - Constant::Kelvin;
2521 147791 : if (state.dataSurface->SurfWinMovableSlats(SurfNum)) {
2522 : EffShBlEmiss =
2523 2569 : General::Interp(window.EffShBlindEmiss[state.dataSurface->SurfWinSlatsAngIndex(SurfNum)],
2524 2569 : window.EffShBlindEmiss[std::min(Material::MaxSlatAngs, state.dataSurface->SurfWinSlatsAngIndex(SurfNum) + 1)],
2525 2569 : state.dataSurface->SurfWinSlatsAngInterpFac(SurfNum));
2526 : EffGlEmiss =
2527 2569 : General::Interp(window.EffGlassEmiss[state.dataSurface->SurfWinSlatsAngIndex(SurfNum)],
2528 5138 : window.EffGlassEmiss[std::min(Material::MaxSlatAngs, state.dataSurface->SurfWinSlatsAngIndex(SurfNum) + 1)],
2529 2569 : state.dataSurface->SurfWinSlatsAngInterpFac(SurfNum));
2530 : } else {
2531 145222 : EffShBlEmiss = state.dataSurface->SurfaceWindow(SurfNum).EffShBlindEmiss[1];
2532 145222 : EffGlEmiss = state.dataSurface->SurfaceWindow(SurfNum).EffGlassEmiss[1];
2533 : }
2534 147791 : state.dataSurface->SurfWinEffInsSurfTemp(SurfNum) =
2535 147791 : (EffShBlEmiss * SurfInsideTemp + EffGlEmiss * (wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin)) /
2536 147791 : (EffShBlEmiss + EffGlEmiss);
2537 : } else {
2538 23816846 : SurfInsideTemp = wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin;
2539 : }
2540 23964637 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2541 21454 : SurfOutsideTemp = wm->thetas[2 * wm->ngllayer] - Constant::Kelvin; // this index looks suspicious (CR 8202)
2542 : // SurfOutsideEmiss = emis(1) ! this index should be coordinated with previous line
2543 21454 : SurfOutsideEmiss = wm->emis[2 * wm->ngllayer]; // fix for CR 8202
2544 : } else {
2545 23943183 : SurfOutsideEmiss = wm->emis[0];
2546 23943183 : SurfOutsideTemp = wm->thetas[0] - Constant::Kelvin;
2547 : }
2548 :
2549 : // Save temperatures for use next time step
2550 :
2551 86227931 : for (int k = 1; k <= wm->nglfacep; ++k) {
2552 62263294 : window.thetaFace[k] = wm->thetas[k - 1];
2553 : }
2554 :
2555 : // Added TH 12/23/2008 for thermochromic windows to save the current TC layer temperature
2556 23964637 : if (wm->locTCFlag) {
2557 8064 : state.dataSurface->SurfWinTCLayerTemp(SurfNum) = (wm->thetas[2 * state.dataConstruction->Construct(ConstrNum).TCGlassID - 2] +
2558 4032 : wm->thetas[2 * state.dataConstruction->Construct(ConstrNum).TCGlassID - 1]) /
2559 4032 : 2 -
2560 : Constant::Kelvin; // degree C
2561 : }
2562 : } // regular window, not BSDF, not EQL
2563 :
2564 : // Set condensation flag to 1 if condensation expected to occur on the innermost glass face,
2565 : // or, for airflow windows, on either or the two glass faces in the airflow gap
2566 24010669 : if (!state.dataConstruction->Construct(surface.Construction).WindowTypeEQL) {
2567 24002605 : InsideGlassTemp = wm->thetas[2 * wm->ngllayer - 1] - Constant::Kelvin;
2568 24002605 : RoomHumRat = thisZoneHB.airHumRat;
2569 24002605 : RoomDewPoint = PsyTdpFnWPb(state, RoomHumRat, state.dataEnvrn->OutBaroPress);
2570 24002605 : state.dataSurface->SurfWinInsideGlassCondensationFlag(SurfNum) = 0;
2571 24002605 : if (InsideGlassTemp < RoomDewPoint) state.dataSurface->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
2572 : // If airflow window, is there condensation on either glass face of the airflow gap?
2573 24002605 : if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
2574 16128 : Tleft = wm->thetas[2 * wm->ngllayer - 3] - Constant::Kelvin;
2575 16128 : Tright = wm->thetas[2 * wm->ngllayer - 2] - Constant::Kelvin;
2576 16128 : if (state.dataSurface->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
2577 16128 : if (Tleft < RoomDewPoint || Tright < RoomDewPoint) state.dataSurface->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
2578 0 : } else if (state.dataSurface->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Outdoor) {
2579 0 : if (Tleft < state.dataEnvrn->OutDewPointTemp || Tright < state.dataEnvrn->OutDewPointTemp)
2580 0 : state.dataSurface->SurfWinInsideGlassCondensationFlag(SurfNum) = 1;
2581 : }
2582 : }
2583 :
2584 : // Do frame and divider calculation
2585 24002605 : if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0 || state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0)
2586 656496 : CalcWinFrameAndDividerTemps(state, SurfNum, wm->tout, wm->tin, wm->hcout, wm->hcin, wm->Outir, ConstrNum);
2587 24002605 : if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0) {
2588 656496 : state.dataSurface->SurfWinInsideFrameCondensationFlag(SurfNum) = 0;
2589 656496 : if (state.dataSurface->SurfWinFrameTempIn(SurfNum) < RoomDewPoint) state.dataSurface->SurfWinInsideFrameCondensationFlag(SurfNum) = 1;
2590 : }
2591 24002605 : if (state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0) {
2592 327888 : state.dataSurface->SurfWinInsideDividerCondensationFlag(SurfNum) = 0;
2593 327888 : if (state.dataSurface->SurfWinDividerTempIn(SurfNum) < RoomDewPoint)
2594 71289 : state.dataSurface->SurfWinInsideDividerCondensationFlag(SurfNum) = 1;
2595 : }
2596 : }
2597 : // update exterior environment surface heat loss reporting
2598 24010669 : Tsout = SurfOutsideTemp + Constant::Kelvin;
2599 24010669 : state.dataHeatBalSurf->SurfQdotConvOutPerArea(SurfNum) = -wm->hcout * (Tsout - wm->tout);
2600 :
2601 24010669 : Real64 const Tsout_4(pow_4(Tsout)); // Tuned To reduce pow calls and redundancies
2602 24010669 : Real64 const Tout_4(pow_4(wm->tout));
2603 24010669 : Real64 const emiss_sigma_product(SurfOutsideEmiss * Constant::StefanBoltzmann);
2604 24010669 : Real64 rad_out_lw_srd_per_area = 0;
2605 :
2606 24010669 : if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
2607 133056 : if (state.dataSurface->Surface(SurfNum).SurfHasSurroundingSurfProperty) {
2608 : // update SurfHSrdSurfExt if the windows has exterior shade or blind
2609 2688 : state.dataHeatBalSurf->SurfHSrdSurfExt(SurfNum) =
2610 2688 : Convect::SurroundingSurfacesRadCoeffAverage(state, SurfNum, Tsout, SurfOutsideEmiss);
2611 2688 : rad_out_lw_srd_per_area = state.dataHeatBalSurf->SurfHSrdSurfExt(SurfNum) * (surface.SrdSurfTemp - SurfOutsideTemp);
2612 : }
2613 : }
2614 :
2615 : Real64 const rad_out_air_per_area =
2616 24010669 : -emiss_sigma_product * (1.0 - state.dataSurface->SurfAirSkyRadSplit(SurfNum)) * surface.ViewFactorSkyIR * (Tsout_4 - Tout_4);
2617 24010669 : Real64 const rad_out_ground_per_area = -emiss_sigma_product * surface.ViewFactorGroundIR * (Tsout_4 - Tout_4);
2618 24010669 : Real64 const rad_out_sky_per_area = -emiss_sigma_product * state.dataSurface->SurfAirSkyRadSplit(SurfNum) * surface.ViewFactorSkyIR *
2619 24010669 : (Tsout_4 - pow_4(state.dataEnvrn->SkyTempKelvin));
2620 24010669 : 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;
2621 :
2622 24010669 : state.dataHeatBalSurf->SurfHAirExt(SurfNum) = rad_out_air_per_area / (Tsout - wm->tout);
2623 24010669 : state.dataHeatBalSurf->SurfQRadLWOutSrdSurfs(SurfNum) = rad_out_lw_srd_per_area;
2624 24010669 : state.dataHeatBalSurf->SurfQdotRadOutRepPerArea(SurfNum) = rad_out_per_area;
2625 24010669 : } // CalcWindowHeatBalanceInternalRoutines()
2626 :
2627 : //****************************************************************************
2628 :
2629 0 : void WindowHeatBalanceEquations(EnergyPlusData &state, int const SurfNum) // Surface number
2630 : {
2631 :
2632 : // SUBROUTINE INFORMATION:
2633 : // AUTHOR F. Winkelmann
2634 : // DATE WRITTEN February 2000
2635 : // MODIFIED na
2636 : // RE-ENGINEERED na
2637 :
2638 : // PURPOSE OF THIS SUBROUTINE:
2639 : // Evaluates heat balance functions at each glass face.
2640 : // Also evaluates Jacobian.
2641 : // Currently limited to three glass layers.
2642 :
2643 0 : Array1D<Real64> hgap(maxGlassLayers); // Gap gas conductance
2644 : Real64 gr; // Gap gas Grashof number
2645 : Real64 con; // Gap gas conductivity
2646 : Real64 pr; // Gap gas Prandtl number
2647 : Real64 nu; // Gap gas Nusselt number
2648 : Real64 thetas_2_3_4;
2649 : Real64 thetas_4_5_4;
2650 : Real64 thetas_6_7_4;
2651 :
2652 0 : auto &wm = state.dataWindowManager;
2653 0 : auto const &surfWin = state.dataSurface->SurfaceWindow(SurfNum);
2654 :
2655 : // Have to zero fvec each time since LUdecompostion and LUsolution may
2656 : // add values to this array in unexpected places
2657 :
2658 0 : wm->fvec = {0.0};
2659 :
2660 0 : switch (wm->ngllayer) {
2661 :
2662 0 : case 1: { // single pane
2663 0 : wm->fvec[0] = wm->Outir * wm->emis[0] - wm->emis[0] * Constant::StefanBoltzmann * pow_4(wm->thetas[0]) +
2664 0 : wm->scon[0] * (wm->thetas[1] - wm->thetas[0]) + wm->hcout * (wm->tout - wm->thetas[0]) + wm->AbsRadGlassFace[0];
2665 0 : wm->fvec[1] = wm->Rmir * wm->emis[1] - wm->emis[1] * Constant::StefanBoltzmann * pow_4(wm->thetas[1]) +
2666 0 : wm->scon[0] * (wm->thetas[0] - wm->thetas[1]) + wm->hcin * (wm->tin - wm->thetas[1]) + wm->AbsRadGlassFace[1];
2667 0 : } break;
2668 0 : case 2: { // double pane
2669 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2670 0 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2671 0 : hgap(1) = (con / wm->gaps[0].width * nu) * surfWin.edgeGlassCorrFac;
2672 :
2673 0 : wm->fvec[0] = wm->Outir * wm->emis[0] - wm->emis[0] * Constant::StefanBoltzmann * pow_4(wm->thetas[0]) +
2674 0 : wm->scon[0] * (wm->thetas[1] - wm->thetas[0]) + wm->hcout * (wm->tout - wm->thetas[0]) + wm->AbsRadGlassFace[0];
2675 0 : thetas_2_3_4 = pow_4(wm->thetas[1]) - pow_4(wm->thetas[2]);
2676 0 : wm->fvec[1] = wm->scon[0] * (wm->thetas[0] - wm->thetas[1]) + hgap(1) * (wm->thetas[2] - wm->thetas[1]) + wm->A23 * thetas_2_3_4 +
2677 0 : wm->AbsRadGlassFace[1];
2678 0 : wm->fvec[2] = hgap(1) * (wm->thetas[1] - wm->thetas[2]) + wm->scon[1] * (wm->thetas[3] - wm->thetas[2]) - wm->A23 * thetas_2_3_4 +
2679 0 : wm->AbsRadGlassFace[2];
2680 0 : wm->fvec[3] = wm->Rmir * wm->emis[3] - wm->emis[3] * Constant::StefanBoltzmann * pow_4(wm->thetas[3]) +
2681 0 : wm->scon[1] * (wm->thetas[2] - wm->thetas[3]) + wm->hcin * (wm->tin - wm->thetas[3]) + wm->AbsRadGlassFace[3];
2682 0 : } break;
2683 0 : case 3: { // Triple Pane
2684 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2685 0 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2686 0 : hgap(1) = con / wm->gaps[0].width * nu * surfWin.edgeGlassCorrFac;
2687 :
2688 0 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
2689 0 : NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
2690 0 : hgap(2) = con / wm->gaps[1].width * nu * surfWin.edgeGlassCorrFac;
2691 :
2692 0 : thetas_2_3_4 = pow_4(wm->thetas[1]) - pow_4(wm->thetas[2]);
2693 0 : thetas_4_5_4 = pow_4(wm->thetas[3]) - pow_4(wm->thetas[4]);
2694 0 : wm->fvec[0] = wm->Outir * wm->emis[0] - wm->emis[0] * Constant::StefanBoltzmann * pow_4(wm->thetas[0]) +
2695 0 : wm->scon[0] * (wm->thetas[1] - wm->thetas[0]) + wm->hcout * (wm->tout - wm->thetas[0]) + wm->AbsRadGlassFace[0];
2696 0 : wm->fvec[1] = wm->scon[0] * (wm->thetas[0] - wm->thetas[1]) + hgap(1) * (wm->thetas[2] - wm->thetas[1]) + wm->A23 * thetas_2_3_4 +
2697 0 : wm->AbsRadGlassFace[1];
2698 0 : wm->fvec[2] = hgap(1) * (wm->thetas[1] - wm->thetas[2]) + wm->scon[1] * (wm->thetas[3] - wm->thetas[2]) - wm->A23 * thetas_2_3_4 +
2699 0 : wm->AbsRadGlassFace[2];
2700 0 : wm->fvec[3] = wm->scon[1] * (wm->thetas[2] - wm->thetas[3]) + hgap(2) * (wm->thetas[4] - wm->thetas[3]) + wm->A45 * thetas_4_5_4 +
2701 0 : wm->AbsRadGlassFace[3];
2702 0 : wm->fvec[4] = hgap(2) * (wm->thetas[3] - wm->thetas[4]) + wm->scon[2] * (wm->thetas[5] - wm->thetas[4]) - wm->A45 * thetas_4_5_4 +
2703 0 : wm->AbsRadGlassFace[4];
2704 0 : wm->fvec[5] = wm->Rmir * wm->emis[5] - wm->emis[5] * Constant::StefanBoltzmann * pow_4(wm->thetas[5]) +
2705 0 : wm->scon[2] * (wm->thetas[4] - wm->thetas[5]) + wm->hcin * (wm->tin - wm->thetas[5]) + wm->AbsRadGlassFace[5];
2706 0 : } break;
2707 0 : case 4: { // Quad Pane
2708 0 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2709 0 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2710 0 : hgap(1) = con / wm->gaps[0].width * nu * surfWin.edgeGlassCorrFac;
2711 :
2712 0 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
2713 0 : NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
2714 0 : hgap(2) = con / wm->gaps[1].width * nu * surfWin.edgeGlassCorrFac;
2715 :
2716 0 : WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
2717 0 : NusseltNumber(state, SurfNum, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
2718 0 : hgap(3) = con / wm->gaps[2].width * nu * surfWin.edgeGlassCorrFac;
2719 :
2720 0 : thetas_2_3_4 = pow_4(wm->thetas[1]) - pow_4(wm->thetas[2]);
2721 0 : thetas_4_5_4 = pow_4(wm->thetas[3]) - pow_4(wm->thetas[4]);
2722 0 : thetas_6_7_4 = pow_4(wm->thetas[5]) - pow_4(wm->thetas[6]);
2723 0 : wm->fvec[0] = wm->Outir * wm->emis[0] - wm->emis[0] * Constant::StefanBoltzmann * pow_4(wm->thetas[0]) +
2724 0 : wm->scon[0] * (wm->thetas[1] - wm->thetas[0]) + wm->hcout * (wm->tout - wm->thetas[0]) + wm->AbsRadGlassFace[0];
2725 0 : wm->fvec[1] = wm->scon[0] * (wm->thetas[0] - wm->thetas[1]) + hgap(1) * (wm->thetas[2] - wm->thetas[1]) + wm->A23 * thetas_2_3_4 +
2726 0 : wm->AbsRadGlassFace[1];
2727 0 : wm->fvec[2] = hgap(1) * (wm->thetas[1] - wm->thetas[2]) + wm->scon[1] * (wm->thetas[3] - wm->thetas[2]) - wm->A23 * thetas_2_3_4 +
2728 0 : wm->AbsRadGlassFace[2];
2729 0 : wm->fvec[3] = wm->scon[1] * (wm->thetas[2] - wm->thetas[3]) + hgap(2) * (wm->thetas[4] - wm->thetas[3]) + wm->A45 * thetas_4_5_4 +
2730 0 : wm->AbsRadGlassFace[3];
2731 0 : wm->fvec[4] = hgap(2) * (wm->thetas[3] - wm->thetas[4]) + wm->scon[2] * (wm->thetas[5] - wm->thetas[4]) - wm->A45 * thetas_4_5_4 +
2732 0 : wm->AbsRadGlassFace[4];
2733 0 : wm->fvec[5] = wm->scon[2] * (wm->thetas[4] - wm->thetas[5]) + hgap(3) * (wm->thetas[6] - wm->thetas[5]) + wm->A67 * thetas_6_7_4 +
2734 0 : wm->AbsRadGlassFace[5];
2735 0 : wm->fvec[6] = hgap(3) * (wm->thetas[5] - wm->thetas[6]) + wm->scon[3] * (wm->thetas[7] - wm->thetas[6]) - wm->A67 * thetas_6_7_4 +
2736 0 : wm->AbsRadGlassFace[6];
2737 0 : wm->fvec[7] = wm->Rmir * wm->emis[7] - wm->emis[7] * Constant::StefanBoltzmann * pow_4(wm->thetas[7]) +
2738 0 : wm->scon[3] * (wm->thetas[6] - wm->thetas[7]) + wm->hcin * (wm->tin - wm->thetas[7]) + wm->AbsRadGlassFace[7];
2739 0 : } break;
2740 : } // switch
2741 0 : } // WindowHeatBalanceEquations()
2742 :
2743 : //****************************************************************************
2744 :
2745 15358 : void GetHeatBalanceEqCoefMatrixSimple(EnergyPlusData &state,
2746 : int const nglasslayer, // Number of glass layers
2747 : Array1D<Real64> const &hr, // Radiative conductance (W/m2-K)
2748 : Array1A<Real64> &hgap, // Gap gas conductive conductance (W/m2-K)
2749 : Array2D<Real64> &Aface, // Coefficient in equation Aface*thetas = Bface
2750 : Array1D<Real64> &Bface // Coefficient in equation Aface*thetas = Bface
2751 : )
2752 : {
2753 : Real64 gr; // Grashof number of gas in a gap
2754 : Real64 con; // Gap gas conductivity
2755 : Real64 pr; // Gap gas Prandtl number
2756 : Real64 nu; // Gap gas Nusselt number
2757 :
2758 15358 : auto &wm = state.dataWindowManager;
2759 :
2760 15358 : if (nglasslayer == 1) {
2761 8223 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2762 8223 : Bface(2) = wm->Rmir * wm->emis[1] + wm->hcin * wm->tin + wm->AbsRadGlassFace[1];
2763 :
2764 8223 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2765 8223 : Aface(2, 1) = -wm->scon[0];
2766 8223 : Aface(1, 2) = -wm->scon[0];
2767 8223 : Aface(2, 2) = hr(2) + wm->scon[0] + wm->hcin;
2768 :
2769 7135 : } else if (nglasslayer == 2) {
2770 6017 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2771 6017 : NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2772 6017 : hgap(1) = con / wm->gaps[0].width * nu;
2773 :
2774 6017 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2775 6017 : Bface(2) = wm->AbsRadGlassFace[1];
2776 6017 : Bface(3) = wm->AbsRadGlassFace[2];
2777 6017 : Bface(4) = wm->Rmir * wm->emis[3] + wm->hcin * wm->tin + wm->AbsRadGlassFace[3];
2778 :
2779 6017 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2780 6017 : Aface(2, 1) = -wm->scon[0];
2781 :
2782 6017 : Aface(1, 2) = -wm->scon[0];
2783 6017 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2784 6017 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2785 :
2786 6017 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2787 6017 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2788 6017 : Aface(4, 3) = -wm->scon[1];
2789 :
2790 6017 : Aface(3, 4) = -wm->scon[1];
2791 6017 : Aface(4, 4) = hr(4) + wm->scon[1] + wm->hcin;
2792 :
2793 1118 : } else if (nglasslayer == 3) {
2794 1037 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2795 1037 : NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2796 1037 : hgap(1) = con / wm->gaps[0].width * nu;
2797 :
2798 1037 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
2799 1037 : NusseltNumber(state, 0, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
2800 1037 : hgap(2) = con / wm->gaps[1].width * nu;
2801 :
2802 1037 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2803 1037 : Bface(2) = wm->AbsRadGlassFace[1];
2804 1037 : Bface(3) = wm->AbsRadGlassFace[2];
2805 1037 : Bface(4) = wm->AbsRadGlassFace[3];
2806 1037 : Bface(5) = wm->AbsRadGlassFace[4];
2807 1037 : Bface(6) = wm->Rmir * wm->emis[5] + wm->hcin * wm->tin + wm->AbsRadGlassFace[5];
2808 :
2809 1037 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2810 1037 : Aface(2, 1) = -wm->scon[0];
2811 :
2812 1037 : Aface(1, 2) = -wm->scon[0];
2813 1037 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2814 1037 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2815 :
2816 1037 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2817 1037 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2818 1037 : Aface(4, 3) = -wm->scon[1];
2819 :
2820 1037 : Aface(3, 4) = -wm->scon[1];
2821 1037 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
2822 1037 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
2823 :
2824 1037 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
2825 1037 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
2826 1037 : Aface(6, 5) = -wm->scon[2];
2827 :
2828 1037 : Aface(5, 6) = -wm->scon[2];
2829 1037 : Aface(6, 6) = hr(6) + wm->scon[2] + wm->hcin;
2830 :
2831 81 : } else if (nglasslayer == 4) {
2832 81 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2833 81 : NusseltNumber(state, 0, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2834 81 : hgap(1) = con / wm->gaps[0].width * nu;
2835 :
2836 81 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
2837 81 : NusseltNumber(state, 0, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
2838 81 : hgap(2) = con / wm->gaps[1].width * nu;
2839 :
2840 81 : WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
2841 81 : NusseltNumber(state, 0, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
2842 81 : hgap(3) = con / wm->gaps[2].width * nu;
2843 :
2844 81 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2845 81 : Bface(2) = wm->AbsRadGlassFace[1];
2846 81 : Bface(3) = wm->AbsRadGlassFace[2];
2847 81 : Bface(4) = wm->AbsRadGlassFace[3];
2848 81 : Bface(5) = wm->AbsRadGlassFace[4];
2849 81 : Bface(6) = wm->AbsRadGlassFace[5];
2850 81 : Bface(7) = wm->AbsRadGlassFace[6];
2851 81 : Bface(8) = wm->Rmir * wm->emis[7] + wm->hcin * wm->tin + wm->AbsRadGlassFace[7];
2852 :
2853 81 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2854 81 : Aface(2, 1) = -wm->scon[0];
2855 :
2856 81 : Aface(1, 2) = -wm->scon[0];
2857 81 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
2858 81 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
2859 :
2860 81 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
2861 81 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
2862 81 : Aface(4, 3) = -wm->scon[1];
2863 :
2864 81 : Aface(3, 4) = -wm->scon[1];
2865 81 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
2866 81 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
2867 :
2868 81 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
2869 81 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
2870 81 : Aface(6, 5) = -wm->scon[2];
2871 :
2872 81 : Aface(5, 6) = -wm->scon[2];
2873 81 : Aface(6, 6) = wm->scon[2] + hgap(3) - wm->A67P * hr(6);
2874 81 : Aface(7, 6) = -hgap(3) - wm->A76P * hr(7);
2875 :
2876 81 : Aface(6, 7) = -hgap(3) + wm->A67P * hr(6);
2877 81 : Aface(7, 7) = hgap(3) + wm->scon[3] + wm->A76P * hr(7);
2878 81 : Aface(8, 7) = -wm->scon[3];
2879 :
2880 81 : Aface(7, 8) = -wm->scon[3];
2881 81 : Aface(8, 8) = hr(8) + wm->scon[3] + wm->hcin;
2882 : }
2883 15358 : } // GetHeatBalanceEqCoefMatrixSimple()
2884 :
2885 44666044 : void GetHeatBalanceEqCoefMatrix(EnergyPlusData &state,
2886 : int const SurfNum,
2887 : int const nglasslayer,
2888 : WinShadingType const ShadeFlag,
2889 : Real64 const sconsh,
2890 : Real64 const TauShIR,
2891 : Real64 const EpsShIR1,
2892 : Real64 const EpsShIR2,
2893 : Real64 const RhoShIR1,
2894 : Real64 const RhoShIR2,
2895 : Real64 const ShGlReflFacIR,
2896 : Real64 const RhoGlIR1,
2897 : Real64 const RhoGlIR2,
2898 : Real64 const hcv, // Convection coefficient from gap glass or shade/blind to gap air (W/m2-K)
2899 : Real64 const TGapNew, // Current-iteration average air temp in airflow gap (K)
2900 : Real64 const TAirflowGapNew, // Average air temp in airflow gap between glass panes (K)
2901 : Real64 const hcvAirflowGap, // Convection coefficient from airflow gap glass to airflow gap air (W/m2-K)
2902 : Array1A<Real64> const &hcvBG, // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
2903 : Array1A<Real64> const &TGapNewBG,
2904 : Array1A<Real64> const &AbsRadShadeFace,
2905 : Array1D<Real64> const &hr,
2906 : Array2D<Real64> &Aface,
2907 : Array1D<Real64> &Bface)
2908 : {
2909 44666044 : auto &wm = state.dataWindowManager;
2910 :
2911 : Real64 gr; // Grashof number of gas in a gap
2912 : Real64 con; // Gap gas conductivity
2913 : Real64 pr; // Gap gas Prandtl number
2914 : Real64 nu; // Gap gas Nusselt number
2915 :
2916 : Real64 FacRhoIR25; // Intermediate variable
2917 : Real64 FacRhoIR63; // Intermediate variable
2918 : Real64 RhoIRfp; // Intermediate variable
2919 : Real64 RhoIRbp; // Intermediate variable
2920 : Real64 FacRhoIR2fp; // Intermediate variable
2921 : Real64 FacRhoIR3bp; // Intermediate variable
2922 : Real64 FacRhoIR2fpRhoIR63; // Intermediate variable
2923 : Real64 FacRhoIR3bpRhoIR25; // Intermediate variable
2924 : Real64 FacRhoIR47; // Intermediate variable
2925 : Real64 FacRhoIR85; // Intermediate variable
2926 : Real64 FacRhoIR4fp; // Intermediate variable
2927 : Real64 FacRhoIR5bp; // Intermediate variable
2928 : Real64 FacRhoIR4fpRhoIR85; // Intermediate variable
2929 : Real64 FacRhoIR5bpRhoIR47; // Intermediate variable
2930 :
2931 44666044 : Array1D<Real64> hgap(maxGlassLayers); // Gap gas conductance (W/m2-K)
2932 :
2933 44666044 : auto const &surfWin = state.dataSurface->SurfaceWindow(SurfNum);
2934 :
2935 44666044 : if (nglasslayer == 1) {
2936 30910820 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2937 30910820 : Bface(2) = wm->Rmir * wm->emis[1] + wm->hcin * wm->tin + wm->AbsRadGlassFace[1];
2938 :
2939 30910820 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2940 30910820 : Aface(2, 1) = -wm->scon[0];
2941 30910820 : Aface(1, 2) = -wm->scon[0];
2942 30910820 : Aface(2, 2) = hr(2) + wm->scon[0] + wm->hcin;
2943 :
2944 30910820 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
2945 : // interior shade, single pane
2946 : // || ||
2947 : // outside 1||2 3||4
2948 : // || ||
2949 : // gl bl/sh/sc
2950 503397 : Bface(2) = wm->Rmir * wm->emis[1] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[1];
2951 503397 : Bface(3) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
2952 503397 : Bface(4) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
2953 :
2954 503397 : Aface(2, 2) = hr(2) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[0] + hcv;
2955 503397 : Aface(3, 2) = -wm->emis[1] * hr(3) / ShGlReflFacIR;
2956 503397 : Aface(2, 3) = -hr(2) * EpsShIR1 / ShGlReflFacIR;
2957 503397 : Aface(3, 3) = hr(3) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
2958 503397 : Aface(4, 3) = -sconsh;
2959 503397 : Aface(3, 4) = -sconsh;
2960 503397 : Aface(4, 4) = hr(4) + sconsh + wm->hcin;
2961 : }
2962 :
2963 30910820 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
2964 : // exterior shade, single pane
2965 : // || ||
2966 : // outside 3||4 1||2
2967 : // || ||
2968 : // bl/sh/sc gl
2969 72296 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
2970 72296 : Bface(3) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
2971 72296 : Bface(4) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
2972 :
2973 72296 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
2974 72296 : Aface(4, 1) = -wm->emis[0] * hr(4) / ShGlReflFacIR;
2975 72296 : Aface(3, 3) = hr(3) + sconsh + wm->hcout;
2976 72296 : Aface(4, 3) = -sconsh;
2977 72296 : Aface(1, 4) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
2978 72296 : Aface(3, 4) = -sconsh;
2979 72296 : Aface(4, 4) = hr(4) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
2980 : }
2981 :
2982 13755224 : } else if (nglasslayer == 2) {
2983 13525048 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
2984 13525048 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
2985 13525048 : hgap(1) = con / wm->gaps[0].width * nu;
2986 13525048 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
2987 1523789 : wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
2988 1523789 : hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
2989 : }
2990 :
2991 13525048 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
2992 13525048 : Bface(2) = wm->AbsRadGlassFace[1];
2993 13525048 : Bface(3) = wm->AbsRadGlassFace[2];
2994 13525048 : Bface(4) = wm->Rmir * wm->emis[3] + wm->hcin * wm->tin + wm->AbsRadGlassFace[3];
2995 :
2996 13525048 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
2997 13525048 : Aface(2, 1) = -wm->scon[0];
2998 :
2999 13525048 : Aface(1, 2) = -wm->scon[0];
3000 13525048 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
3001 13525048 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
3002 :
3003 13525048 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
3004 13525048 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
3005 13525048 : Aface(4, 3) = -wm->scon[1];
3006 :
3007 13525048 : Aface(3, 4) = -wm->scon[1];
3008 13525048 : Aface(4, 4) = hr(4) + wm->scon[1] + wm->hcin;
3009 :
3010 13525048 : if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
3011 8052 : Bface(2) = wm->AbsRadGlassFace[1] + hcvAirflowGap * TAirflowGapNew;
3012 8052 : Bface(3) = wm->AbsRadGlassFace[2] + hcvAirflowGap * TAirflowGapNew;
3013 8052 : Aface(2, 2) = wm->scon[0] + hcvAirflowGap - wm->A23P * hr(2);
3014 8052 : Aface(3, 2) = -wm->A32P * hr(3);
3015 8052 : Aface(2, 3) = wm->A23P * hr(2);
3016 8052 : Aface(3, 3) = hcvAirflowGap + wm->scon[1] + wm->A32P * hr(3);
3017 : }
3018 :
3019 13525048 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3020 90082 : Bface(4) = wm->Rmir * wm->emis[3] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[3];
3021 90082 : Bface(5) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
3022 90082 : Bface(6) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
3023 :
3024 90082 : Aface(4, 4) = hr(4) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[1] + hcv;
3025 90082 : Aface(5, 4) = -wm->emis[3] * hr(5) / ShGlReflFacIR;
3026 90082 : Aface(4, 5) = -hr(4) * EpsShIR1 / ShGlReflFacIR;
3027 90082 : Aface(5, 5) = hr(5) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
3028 90082 : Aface(6, 5) = -sconsh;
3029 90082 : Aface(5, 6) = -sconsh;
3030 90082 : Aface(6, 6) = hr(6) + sconsh + wm->hcin;
3031 : }
3032 :
3033 13525048 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
3034 103926 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
3035 103926 : Bface(5) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
3036 103926 : Bface(6) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
3037 :
3038 103926 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
3039 103926 : Aface(6, 1) = -wm->emis[0] * hr(6) / ShGlReflFacIR;
3040 103926 : Aface(5, 5) = hr(5) + sconsh + wm->hcout;
3041 103926 : Aface(6, 5) = -sconsh;
3042 103926 : Aface(1, 6) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
3043 103926 : Aface(5, 6) = -sconsh;
3044 103926 : Aface(6, 6) = hr(6) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
3045 : }
3046 :
3047 13525048 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
3048 61025 : Array1D<Real64> RhoIR(6); // Face IR reflectance
3049 :
3050 427175 : for (int i = 1; i <= 6; ++i) {
3051 366150 : RhoIR(i) = max(0.0, 1.0 - wm->tir[i - 1] - wm->emis[i - 1]);
3052 : }
3053 61025 : FacRhoIR25 = 1.0 - RhoIR(2) * RhoIR(5);
3054 61025 : FacRhoIR63 = 1.0 - RhoIR(6) * RhoIR(3);
3055 61025 : Real64 const tir_5_squared(pow_2(wm->tir[4]));
3056 61025 : RhoIRfp = RhoIR(5) + tir_5_squared * RhoIR(3) / FacRhoIR63;
3057 61025 : RhoIRbp = RhoIR(6) + tir_5_squared * RhoIR(2) / FacRhoIR25;
3058 61025 : FacRhoIR2fp = 1.0 - RhoIRfp * RhoIR(2);
3059 61025 : FacRhoIR3bp = 1.0 - RhoIRbp * RhoIR(3);
3060 61025 : FacRhoIR2fpRhoIR63 = FacRhoIR2fp * FacRhoIR63;
3061 61025 : FacRhoIR3bpRhoIR25 = FacRhoIR3bp * FacRhoIR25;
3062 61025 : Aface(2, 2) = wm->scon[0] + hcvBG(1) + hr(2) * (1 - RhoIRfp * (wm->emis[1] + RhoIR(2))) / FacRhoIR2fp;
3063 61025 : Aface(3, 2) = -wm->emis[1] * hr(3) * wm->tir[4] / FacRhoIR2fpRhoIR63;
3064 61025 : Aface(5, 2) = -wm->emis[1] * hr(5) / FacRhoIR2fp;
3065 61025 : Aface(6, 2) = -wm->emis[1] * hr(6) * RhoIR(3) * wm->tir[4] / FacRhoIR2fpRhoIR63;
3066 61025 : Bface(2) = hcvBG(1) * TGapNewBG(1) + wm->AbsRadGlassFace[1];
3067 61025 : Aface(2, 3) = -wm->emis[2] * hr(2) * wm->tir[4] / FacRhoIR3bpRhoIR25;
3068 61025 : Aface(3, 3) = wm->scon[1] + hcvBG(2) + hr(3) * (1 - RhoIRbp * (wm->emis[2] + RhoIR(3))) / FacRhoIR3bp;
3069 61025 : Aface(5, 3) = -wm->emis[2] * hr(5) * RhoIR(2) * wm->tir[4] / FacRhoIR3bpRhoIR25;
3070 61025 : Aface(6, 3) = -wm->emis[2] * hr(6) / FacRhoIR3bp;
3071 61025 : Bface(3) = hcvBG(2) * TGapNewBG(2) + wm->AbsRadGlassFace[2];
3072 61025 : Aface(2, 5) = -wm->emis[4] * hr(2) / FacRhoIR2fp;
3073 61025 : Aface(3, 5) = -hr(3) * wm->tir[4] * RhoIR(2) * wm->emis[4] / FacRhoIR2fpRhoIR63;
3074 61025 : Aface(5, 5) = sconsh + hcvBG(1) + hr(5) * (1 - RhoIR(2) * wm->emis[4] / FacRhoIR2fp);
3075 61025 : Aface(6, 5) = -sconsh - hr(6) * RhoIR(2) * wm->tir[4] * RhoIR(3) * wm->emis[4] / FacRhoIR2fpRhoIR63;
3076 61025 : Bface(5) = hcvBG(1) * TGapNewBG(1) + AbsRadShadeFace(1);
3077 61025 : Aface(2, 6) = -hr(2) * wm->tir[4] * RhoIR(3) * wm->emis[5] / FacRhoIR3bpRhoIR25;
3078 61025 : Aface(3, 6) = -wm->emis[5] * hr(3) / FacRhoIR3bp;
3079 61025 : Aface(5, 6) = -sconsh - hr(5) * RhoIR(3) * wm->tir[4] * RhoIR(2) * wm->emis[5] / FacRhoIR3bpRhoIR25;
3080 61025 : Aface(6, 6) = sconsh + hcvBG(2) + hr(6) * (1 - RhoIR(3) * wm->emis[5] / FacRhoIR3bp);
3081 61025 : Bface(6) = hcvBG(2) * TGapNewBG(2) + AbsRadShadeFace(2);
3082 61025 : }
3083 :
3084 230176 : } else if (nglasslayer == 3) {
3085 123739 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
3086 123739 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
3087 123739 : hgap(1) = con / wm->gaps[0].width * nu;
3088 123739 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3089 15026 : wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
3090 15026 : hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
3091 : }
3092 :
3093 123739 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
3094 123739 : NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
3095 123739 : hgap(2) = con / wm->gaps[1].width * nu;
3096 123739 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3097 15026 : wm->hrgap[1] = 0.5 * std::abs(wm->A45) * pow_3(wm->thetas[3] + wm->thetas[4]);
3098 15026 : hgap(2) = hgap(2) * surfWin.edgeGlassCorrFac + wm->hrgap[1] * (surfWin.edgeGlassCorrFac - 1.0);
3099 : }
3100 :
3101 123739 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
3102 123739 : Bface(2) = wm->AbsRadGlassFace[1];
3103 123739 : Bface(3) = wm->AbsRadGlassFace[2];
3104 123739 : Bface(4) = wm->AbsRadGlassFace[3];
3105 123739 : Bface(5) = wm->AbsRadGlassFace[4];
3106 123739 : Bface(6) = wm->Rmir * wm->emis[5] + wm->hcin * wm->tin + wm->AbsRadGlassFace[5];
3107 :
3108 123739 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
3109 123739 : Aface(2, 1) = -wm->scon[0];
3110 :
3111 123739 : Aface(1, 2) = -wm->scon[0];
3112 123739 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
3113 123739 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
3114 :
3115 123739 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
3116 123739 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
3117 123739 : Aface(4, 3) = -wm->scon[1];
3118 :
3119 123739 : Aface(3, 4) = -wm->scon[1];
3120 123739 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
3121 123739 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
3122 :
3123 123739 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
3124 123739 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
3125 123739 : Aface(6, 5) = -wm->scon[2];
3126 :
3127 123739 : Aface(5, 6) = -wm->scon[2];
3128 123739 : Aface(6, 6) = hr(6) + wm->scon[2] + wm->hcin;
3129 :
3130 123739 : if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
3131 8375 : Bface(4) = wm->AbsRadGlassFace[3] + hcvAirflowGap * TAirflowGapNew;
3132 8375 : Bface(5) = wm->AbsRadGlassFace[4] + hcvAirflowGap * TAirflowGapNew;
3133 8375 : Aface(4, 4) = wm->scon[1] + hcvAirflowGap - wm->A45P * hr(4);
3134 8375 : Aface(5, 4) = -wm->A54P * hr(5);
3135 8375 : Aface(4, 5) = wm->A45P * hr(4);
3136 8375 : Aface(5, 5) = hcvAirflowGap + wm->scon[2] + wm->A54P * hr(5);
3137 : }
3138 :
3139 123739 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3140 6560 : Bface(6) = wm->Rmir * wm->emis[5] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[5];
3141 6560 : Bface(7) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
3142 6560 : Bface(8) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
3143 :
3144 6560 : Aface(6, 6) = hr(6) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[2] + hcv;
3145 6560 : Aface(7, 6) = -wm->emis[5] * hr(7) / ShGlReflFacIR;
3146 6560 : Aface(6, 7) = -hr(6) * EpsShIR1 / ShGlReflFacIR;
3147 6560 : Aface(7, 7) = hr(7) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
3148 6560 : Aface(8, 7) = -sconsh;
3149 6560 : Aface(7, 8) = -sconsh;
3150 6560 : Aface(8, 8) = hr(8) + sconsh + wm->hcin;
3151 117179 : } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
3152 0 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
3153 0 : Bface(7) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
3154 0 : Bface(8) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
3155 :
3156 0 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
3157 0 : Aface(8, 1) = -wm->emis[0] * hr(8) / ShGlReflFacIR;
3158 0 : Aface(7, 7) = hr(7) + sconsh + wm->hcout;
3159 0 : Aface(8, 7) = -sconsh;
3160 0 : Aface(1, 8) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
3161 0 : Aface(7, 8) = -sconsh;
3162 0 : Aface(8, 8) = hr(8) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
3163 117179 : } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
3164 47421 : Array1D<Real64> RhoIR(8); // Face IR reflectance
3165 426789 : for (int i = 1; i <= 8; ++i) {
3166 379368 : RhoIR(i) = max(0.0, 1.0 - wm->tir[i - 1] - wm->emis[i - 1]);
3167 : }
3168 47421 : FacRhoIR47 = 1 - RhoIR(4) * RhoIR(7);
3169 47421 : FacRhoIR85 = 1 - RhoIR(8) * RhoIR(5);
3170 47421 : Real64 const tir_7_squared(pow_2(wm->tir[6]));
3171 47421 : RhoIRfp = RhoIR(7) + tir_7_squared * RhoIR(5) / FacRhoIR85;
3172 47421 : RhoIRbp = RhoIR(8) + tir_7_squared * RhoIR(4) / FacRhoIR47;
3173 47421 : FacRhoIR4fp = 1 - RhoIRfp * RhoIR(4);
3174 47421 : FacRhoIR5bp = 1 - RhoIRbp * RhoIR(5);
3175 47421 : FacRhoIR4fpRhoIR85 = FacRhoIR4fp * FacRhoIR85;
3176 47421 : FacRhoIR5bpRhoIR47 = FacRhoIR5bp * FacRhoIR47;
3177 47421 : Aface(4, 4) = wm->scon[1] + hcvBG(1) + hr(4) * (1 - RhoIRfp * (wm->emis[3] + RhoIR(4))) / FacRhoIR4fp;
3178 47421 : Aface(5, 4) = -wm->emis[3] * hr(5) * wm->tir[6] / FacRhoIR4fpRhoIR85;
3179 47421 : Aface(7, 4) = -wm->emis[3] * hr(7) / FacRhoIR4fp;
3180 47421 : Aface(8, 4) = -wm->emis[3] * hr(8) * RhoIR(5) * wm->tir[6] / FacRhoIR4fpRhoIR85;
3181 47421 : Bface(4) = hcvBG(1) * TGapNewBG(1) + wm->AbsRadGlassFace[3];
3182 47421 : Aface(4, 5) = -wm->emis[4] * hr(4) * wm->tir[6] / FacRhoIR5bpRhoIR47;
3183 47421 : Aface(5, 5) = wm->scon[2] + hcvBG(2) + hr(5) * (1 - RhoIRbp * (wm->emis[4] + RhoIR(5))) / FacRhoIR5bp;
3184 47421 : Aface(7, 5) = -wm->emis[4] * hr(7) * RhoIR(4) * wm->tir[6] / FacRhoIR5bpRhoIR47;
3185 47421 : Aface(8, 5) = -wm->emis[4] * hr(8) / FacRhoIR5bp;
3186 47421 : Bface(5) = hcvBG(2) * TGapNewBG(2) + wm->AbsRadGlassFace[4];
3187 47421 : Aface(4, 7) = -wm->emis[6] * hr(4) / FacRhoIR4fp;
3188 47421 : Aface(5, 7) = -hr(5) * wm->tir[6] * RhoIR(4) * wm->emis[6] / FacRhoIR4fpRhoIR85;
3189 47421 : Aface(7, 7) = sconsh + hcvBG(1) + hr(7) * (1 - RhoIR(4) * wm->emis[6] / FacRhoIR4fp);
3190 47421 : Aface(8, 7) = -sconsh - hr(8) * RhoIR(4) * wm->tir[6] * RhoIR(5) * wm->emis[6] / FacRhoIR4fpRhoIR85;
3191 47421 : Bface(7) = hcvBG(1) * TGapNewBG(1) + AbsRadShadeFace(1);
3192 47421 : Aface(4, 8) = -hr(4) * wm->tir[6] * RhoIR(5) * wm->emis[7] / FacRhoIR5bpRhoIR47;
3193 47421 : Aface(5, 8) = -wm->emis[7] * hr(5) / FacRhoIR5bp;
3194 47421 : Aface(7, 8) = -sconsh - hr(7) * RhoIR(5) * wm->tir[6] * RhoIR(4) * wm->emis[7] / FacRhoIR5bpRhoIR47;
3195 47421 : Aface(8, 8) = sconsh + hcvBG(2) + hr(8) * (1 - RhoIR(5) * wm->emis[7] / FacRhoIR5bp);
3196 47421 : Bface(8) = hcvBG(2) * TGapNewBG(2) + AbsRadShadeFace(2);
3197 47421 : }
3198 :
3199 106437 : } else if (nglasslayer == 4) {
3200 106437 : WindowGasConductance(state, wm->thetas[1], wm->thetas[2], 1, con, pr, gr);
3201 106437 : NusseltNumber(state, SurfNum, wm->thetas[1], wm->thetas[2], 1, gr, pr, nu);
3202 106437 : hgap(1) = con / wm->gaps[0].width * nu;
3203 106437 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3204 0 : wm->hrgap[0] = 0.5 * std::abs(wm->A23) * pow_3(wm->thetas[1] + wm->thetas[2]);
3205 0 : hgap(1) = hgap(1) * surfWin.edgeGlassCorrFac + wm->hrgap[0] * (surfWin.edgeGlassCorrFac - 1.0);
3206 : }
3207 :
3208 106437 : WindowGasConductance(state, wm->thetas[3], wm->thetas[4], 2, con, pr, gr);
3209 106437 : NusseltNumber(state, SurfNum, wm->thetas[3], wm->thetas[4], 2, gr, pr, nu);
3210 106437 : hgap(2) = con / wm->gaps[1].width * nu;
3211 106437 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3212 0 : wm->hrgap[1] = 0.5 * std::abs(wm->A45) * pow_3(wm->thetas[3] + wm->thetas[4]);
3213 0 : hgap(2) = hgap(2) * surfWin.edgeGlassCorrFac + wm->hrgap[1] * (surfWin.edgeGlassCorrFac - 1.0);
3214 : }
3215 :
3216 106437 : WindowGasConductance(state, wm->thetas[5], wm->thetas[6], 3, con, pr, gr);
3217 106437 : NusseltNumber(state, SurfNum, wm->thetas[5], wm->thetas[6], 3, gr, pr, nu);
3218 106437 : hgap(3) = con / wm->gaps[2].width * nu;
3219 106437 : if (surfWin.edgeGlassCorrFac > 1.0) { // Edge of glass correction
3220 0 : wm->hrgap[2] = 0.5 * std::abs(wm->A67) * pow_3(wm->thetas[5] + wm->thetas[6]);
3221 0 : hgap(3) = hgap(3) * surfWin.edgeGlassCorrFac + wm->hrgap[2] * (surfWin.edgeGlassCorrFac - 1.0);
3222 : }
3223 106437 : Bface(1) = wm->Outir * wm->emis[0] + wm->hcout * wm->tout + wm->AbsRadGlassFace[0];
3224 106437 : Bface(2) = wm->AbsRadGlassFace[1];
3225 106437 : Bface(3) = wm->AbsRadGlassFace[2];
3226 106437 : Bface(4) = wm->AbsRadGlassFace[3];
3227 106437 : Bface(5) = wm->AbsRadGlassFace[4];
3228 106437 : Bface(6) = wm->AbsRadGlassFace[5];
3229 106437 : Bface(7) = wm->AbsRadGlassFace[6];
3230 106437 : Bface(8) = wm->Rmir * wm->emis[7] + wm->hcin * wm->tin + wm->AbsRadGlassFace[7];
3231 :
3232 106437 : Aface(1, 1) = hr(1) + wm->scon[0] + wm->hcout;
3233 106437 : Aface(2, 1) = -wm->scon[0];
3234 :
3235 106437 : Aface(1, 2) = -wm->scon[0];
3236 106437 : Aface(2, 2) = wm->scon[0] + hgap(1) - wm->A23P * hr(2);
3237 106437 : Aface(3, 2) = -hgap(1) - wm->A32P * hr(3);
3238 :
3239 106437 : Aface(2, 3) = -hgap(1) + wm->A23P * hr(2);
3240 106437 : Aface(3, 3) = hgap(1) + wm->scon[1] + wm->A32P * hr(3);
3241 106437 : Aface(4, 3) = -wm->scon[1];
3242 :
3243 106437 : Aface(3, 4) = -wm->scon[1];
3244 106437 : Aface(4, 4) = wm->scon[1] + hgap(2) - wm->A45P * hr(4);
3245 106437 : Aface(5, 4) = -hgap(2) - wm->A54P * hr(5);
3246 :
3247 106437 : Aface(4, 5) = -hgap(2) + wm->A45P * hr(4);
3248 106437 : Aface(5, 5) = hgap(2) + wm->scon[2] + wm->A54P * hr(5);
3249 106437 : Aface(6, 5) = -wm->scon[2];
3250 :
3251 106437 : Aface(5, 6) = -wm->scon[2];
3252 106437 : Aface(6, 6) = wm->scon[2] + hgap(3) - wm->A67P * hr(6);
3253 106437 : Aface(7, 6) = -hgap(3) - wm->A76P * hr(7);
3254 :
3255 106437 : Aface(6, 7) = -hgap(3) + wm->A67P * hr(6);
3256 106437 : Aface(7, 7) = hgap(3) + wm->scon[3] + wm->A76P * hr(7);
3257 106437 : Aface(8, 7) = -wm->scon[3];
3258 :
3259 106437 : Aface(7, 8) = -wm->scon[3];
3260 106437 : Aface(8, 8) = hr(8) + wm->scon[3] + wm->hcin;
3261 :
3262 106437 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3263 0 : Bface(8) = wm->Rmir * wm->emis[7] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[7];
3264 0 : Bface(9) = wm->Rmir * TauShIR * RhoGlIR2 * EpsShIR1 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(1);
3265 0 : Bface(10) = wm->Rmir * EpsShIR2 + wm->hcin * wm->tin + AbsRadShadeFace(2);
3266 :
3267 0 : Aface(8, 8) = hr(8) * (1 - RhoShIR1) / ShGlReflFacIR + wm->scon[3] + hcv;
3268 0 : Aface(9, 8) = -wm->emis[7] * hr(9) / ShGlReflFacIR;
3269 0 : Aface(8, 9) = -hr(8) * EpsShIR1 / ShGlReflFacIR;
3270 0 : Aface(9, 9) = hr(9) * (1 - RhoGlIR2 * (EpsShIR1 + RhoShIR1)) / ShGlReflFacIR + sconsh + hcv;
3271 0 : Aface(10, 9) = -sconsh;
3272 0 : Aface(9, 10) = -sconsh;
3273 0 : Aface(10, 10) = hr(10) + sconsh + wm->hcin;
3274 : }
3275 :
3276 106437 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
3277 0 : Bface(1) = wm->Outir * wm->emis[0] * TauShIR / ShGlReflFacIR + hcv * TGapNew + wm->AbsRadGlassFace[0];
3278 0 : Bface(9) = wm->Outir * EpsShIR1 + wm->hcout * wm->tout + AbsRadShadeFace(1);
3279 0 : Bface(10) = wm->Outir * TauShIR * RhoGlIR1 * EpsShIR2 / ShGlReflFacIR + hcv * TGapNew + AbsRadShadeFace(2);
3280 :
3281 0 : Aface(1, 1) = hr(1) * (1 - RhoShIR2) / ShGlReflFacIR + wm->scon[0] + hcv;
3282 0 : Aface(10, 1) = -wm->emis[0] * hr(10) / ShGlReflFacIR;
3283 0 : Aface(9, 9) = hr(9) + sconsh + wm->hcout;
3284 0 : Aface(10, 9) = -sconsh;
3285 0 : Aface(1, 10) = -hr(1) * EpsShIR2 / ShGlReflFacIR;
3286 0 : Aface(9, 10) = -sconsh;
3287 0 : Aface(10, 10) = hr(10) * (1 - RhoGlIR1 * (EpsShIR2 + RhoShIR2)) / ShGlReflFacIR + sconsh + hcv;
3288 : }
3289 :
3290 : } else {
3291 0 : ShowFatalError(state, format("SolveForWindowTemperatures: Invalid number of Glass Layers={}, up to 4 allowed.", wm->ngllayer));
3292 : }
3293 44666044 : } // GetHeatBalanceEqCoefMatrix()
3294 :
3295 23964637 : void SolveForWindowTemperatures(EnergyPlusData &state, int const SurfNum) // Surface number
3296 : {
3297 :
3298 : // SUBROUTINE INFORMATION:
3299 : // AUTHOR F. Winkelmann
3300 : // DATE WRITTEN July 2000
3301 : // MODIFIED Oct 2000, FW: modify edge-of-glass correction to account
3302 : // for gap radiative conductance affects
3303 : // Feb 2001, FW: add interior or exterior shade to layer
3304 : // heat balance calculation.
3305 : // Mar 2001, FW: relax error tolerance if MaxIterations reached.
3306 : // Jun 2001, FW: add interior or exterior blind
3307 : // Nov 2002, FW: add relaxation on face temperatures
3308 : // to improve convergence for multipane cases where outer pane
3309 : // has high solar absorptance: temp --> 0.5*(temp + previous temp);
3310 : // also, increase MaxIterations from 50 to 100.
3311 : // Dec 2002, FW: add between-glass shade/blind for double and triple glazing.
3312 : // Mar 2003, FW: remove redundant relaxation on radiative conductances
3313 : // Mar 2003, FW: increase convergence tolerance from 0.01 to 0.02 to enhance
3314 : // convergence in difficult cases.
3315 : // June 2003, FW: correct the expression for convective gain to zone air
3316 : // from airflow windows with airflow destination = InsideAir. Previously
3317 : // convective gain of air as it passed through gap was used, which is correct
3318 : // for airflow source = InsideAir but incorrect for airflow source = OutsideAir.
3319 : // Save SurfaceWindow%TAirflowGapOutlet for use in calculating convective heat
3320 : // gain to return air when airflow source = InsideAir, destination = ReturnAir.
3321 : // Dec 2003, FW: enhance converge for difficult cases by increasing relaxation
3322 : // in layer surface temperatures for iterations > MaxIterations/4
3323 : // May 2006, RR: add exterior window screen
3324 : // January 2009, BG: inserted call to recalc inside face convection inside iteration loop
3325 : // per ISO 15099 Section 8.3.2.2
3326 : // RE-ENGINEERED na
3327 :
3328 : // PURPOSE OF THIS SUBROUTINE:
3329 : // Evaluates the coefficients Aface and Bface in the system of linear
3330 : // algebraic equations
3331 : // Sum [Aface(i,j)*thetas(j)] = Bface(i), i = 1,nglfacep, j=1,nglfacep
3332 : // where
3333 : // nglface = number of glass faces (= 2 * number of glass layers), or, if shade or blind is present,
3334 : // nglgacep = number of glass faces + 2
3335 : // thetas(j) = temperature of face j
3336 : // If an interior, exterior or between-glass shade or blind, or exterior screen is present
3337 : // the face numbering is as follows:
3338 : // 1 to 2*nglface are glass faces, from outside to inside;
3339 : // 2*nglface+1 and 2*nglface+2 are the shade or blind faces, from outside to inside
3340 : // For example, the following diagram shows the face number for an exterior shade, screen or blind
3341 : // on double glazing:
3342 : // || || ||
3343 : // 5||6 1||2 3||4
3344 : // || || ||
3345 : // bl/sh/sc gl gl
3346 :
3347 : // And for a between-glass shade/blind in triple glazing:
3348 : // || || || ||
3349 : // 1||2 3||4 7||8 5||6
3350 : // || || || ||
3351 : // gl gl bl/sh gl
3352 :
3353 : // METHODOLOGY EMPLOYED:
3354 : // The Aface and Bface coefficients are determined by the equations for
3355 : // heat balance at the glass and shade/blind faces. The system of linear equations is solved
3356 : // by LU decomposition.
3357 :
3358 : // Using/Aliasing
3359 : using Convect::CalcISO15099WindowIntConvCoeff;
3360 : using Psychrometrics::PsyCpAirFnW;
3361 : using Psychrometrics::PsyHFnTdbW;
3362 : using Psychrometrics::PsyRhoAirFnPbTdbW;
3363 : using Psychrometrics::PsyTdbFnHW;
3364 :
3365 23964637 : constexpr int MaxIterations(100); // Maximum allowed number of iterations (increased 9/01 from 15 to 50,
3366 : // increased 11/02 from 50 to 100)
3367 23964637 : constexpr Real64 errtemptol(0.02); // Tolerance on errtemp for convergence (increased from 0.01, 3/4/03)
3368 :
3369 : int ZoneNum; // Zone number corresponding to SurfNum
3370 : int d; // +1 if number of row interchanges is even,
3371 : // -1 if odd (in LU decomposition
3372 :
3373 23964637 : auto &wm = state.dataWindowManager;
3374 :
3375 23964637 : int iter = 0; // Iteration number
3376 23964637 : Real64 errtemp = 0.0; // Absolute value of sum of face temperature differences between iterations, divided by number of faces
3377 23964637 : Real64 VGap = 0.0; // Air velocity in gap between glass and shade/blind (m/s)
3378 23964637 : Real64 VAirflowGap = 0.0; // Air velocity in airflow gap between glass panes (m/s)
3379 23964637 : Real64 VGapPrev = 0.0; // Value of VGap from previous iteration
3380 23964637 : Real64 TGapNew = 0.0; // Average air temp in gap between glass and shade/blind (K)
3381 23964637 : Real64 TAirflowGapNew = 0.0; // Average air temp in airflow gap between glass panes (K)
3382 23964637 : Real64 TGapOutlet = 0.0; // Temperature of air leaving gap between glass and shade/blind (K)
3383 23964637 : Real64 TAirflowGapOutlet = 0.0; // Temperature of air leaving airflow gap between glass panes (K)
3384 23964637 : Real64 TAirflowGapOutletC = 0.0; // Temperature of air leaving airflow gap between glass panes (C)
3385 23964637 : Real64 hcv = 0.0; // Convection coefficient from gap glass or shade/blind to gap air (W/m2-K)
3386 23964637 : Real64 hcvAirflowGap = 0.0; // Convection coefficient from airflow gap glass to airflow gap air (W/m2-K)
3387 23964637 : Real64 hcvPrev = 0.0; // Value of hcv from previous iteration
3388 23964637 : Real64 ConvHeatFlowForced = 0.0; // Convective heat flow from forced airflow gap (W)
3389 23964637 : Real64 ShGlReflFacIR = 0.0; // Factor for long-wave inter-reflection between shade/blind and adjacent glass
3390 23964637 : Real64 RhoGlIR1 = 0.0; // Long-wave reflectance of glass surface facing shade/blind; 1=exterior shade/blind,
3391 23964637 : Real64 RhoGlIR2 = 0.0;
3392 : // 2=exterior shade/blind
3393 23964637 : Real64 EpsShIR1 = 0.0; // Long-wave emissivity of shade/blind surface facing glass; 1=interior shade/blind,
3394 23964637 : Real64 EpsShIR2 = 0.0;
3395 : // 2=interior shade/blind
3396 23964637 : Real64 RhoShIR1 = 0.0; // Long-wave reflectance of shade/blind surface facing glass; 1=interior shade/blind,
3397 23964637 : Real64 RhoShIR2 = 0.0;
3398 : // 2=exterior shade/blind
3399 23964637 : Real64 TauShIR = 0.0; // Long-wave transmittance of isolated shade/blind
3400 23964637 : Real64 sconsh = 0.0; // shade/blind conductance (W/m2-K)
3401 :
3402 23964637 : WinShadingType ShadeFlag = WinShadingType::NoShade; // Shading flag
3403 : // radiation from lights and zone equipment absorbed by faces of shade/blind (W/m2)
3404 23964637 : Real64 ShadeArea = 0.0; // shade/blind area (m2)
3405 : // Real64 CondHeatGainGlass = 0.0; // Conduction through inner glass layer, outside to inside (W)
3406 : // Real64 CondHeatGainShade = 0.0; // Conduction through shade/blind, outside to inside (W)
3407 : // shade/blind is present. Zero if shade/blind has zero IR transmittance (W)
3408 : // Real64 IncidentSolar = 0.0; // Solar incident on outside of window (W)
3409 23964637 : Real64 TotAirflowGap = 0.0; // Total volumetric airflow through window gap (m3/s)
3410 23964637 : Real64 CpAirOutlet = 0.0; // Heat capacity of air from window gap (J/kg-K)
3411 23964637 : Real64 CpAirZone = 0.0; // Heat capacity of zone air (J/kg-K)
3412 23964637 : Real64 InletAirHumRat = 0.0; // Humidity ratio of air from window gap entering fan
3413 23964637 : int InsideFaceIndex = 0; // intermediate variable for index of inside face in thetas
3414 :
3415 23964637 : Array1D<Real64> hr = Array1D<Real64>(2 * maxGlassLayers); // Radiative conductance (W/m2-K)
3416 23964637 : Array1D<Real64> AbsRadShadeFace(2); // Solar radiation, short-wave radiation from lights, and long-wave
3417 23964637 : Array1D<Real64> TGapNewBG(2); // For between-glass shade/blind, average gas temp in gaps on either
3418 : // side of shade/blind (K)
3419 23964637 : Array1D<Real64> hcvBG(2); // For between-glass shade/blind, convection coefficient from gap glass or
3420 : // shade/blind to gap gas on either side of shade/blind (W/m2-K)
3421 :
3422 47929274 : Array2D<Real64> Aface(2 * maxGlassLayers, 2 * maxGlassLayers); // Coefficient in equation Aface*thetas = Bface
3423 23964637 : Array1D<Real64> Bface(2 * maxGlassLayers); // Coefficient in equation Aface*thetas = Bface
3424 23964637 : Array1D_int indx(2 * maxGlassLayers); // Vector of row permutations in LU decomposition
3425 :
3426 23964637 : wm->nglfacep = wm->nglface;
3427 23964637 : ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
3428 23964637 : ZoneNum = state.dataSurface->Surface(SurfNum).Zone;
3429 23964637 : AbsRadShadeFace = 0.0;
3430 :
3431 23964637 : if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
3432 186115 : wm->nglfacep = wm->nglface + 2;
3433 186115 : AbsRadShadeFace(1) = DataSurfaces::AbsFrontSide(state, SurfNum);
3434 186115 : AbsRadShadeFace(2) = DataSurfaces::AbsBackSide(state, SurfNum);
3435 186115 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) AbsRadShadeFace(2) += state.dataSurface->SurfWinIntLWAbsByShade(SurfNum);
3436 186115 : sconsh = wm->scon[wm->ngllayer];
3437 186115 : TauShIR = wm->tir[wm->nglface];
3438 186115 : EpsShIR1 = wm->emis[wm->nglface];
3439 186115 : EpsShIR2 = wm->emis[wm->nglface + 1];
3440 186115 : RhoShIR1 = max(0.0, 1.0 - TauShIR - EpsShIR1);
3441 186115 : RhoShIR2 = max(0.0, 1.0 - TauShIR - EpsShIR2);
3442 186115 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3443 147791 : RhoGlIR2 = 1.0 - wm->emis[2 * wm->ngllayer - 1];
3444 147791 : ShGlReflFacIR = 1.0 - RhoGlIR2 * RhoShIR1;
3445 38324 : } else if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag)) {
3446 21454 : RhoGlIR1 = 1.0 - wm->emis[0];
3447 21454 : ShGlReflFacIR = 1.0 - RhoGlIR1 * RhoShIR2;
3448 : }
3449 : } // End of check if shade or blind is on
3450 :
3451 : // Initialize face temperatures.
3452 :
3453 23964637 : StartingWindowTemps(state, SurfNum, AbsRadShadeFace);
3454 :
3455 23964637 : hcvPrev = 0.0;
3456 23964637 : VGapPrev = 0.0;
3457 :
3458 : // Calculate radiative conductances
3459 :
3460 23964637 : errtemp = errtemptol * 2.0;
3461 :
3462 68630681 : while (iter < MaxIterations && errtemp > errtemptol) {
3463 :
3464 163951220 : for (int i = 1; i <= wm->nglfacep; ++i) {
3465 119285176 : hr(i) = wm->emis[i - 1] * Constant::StefanBoltzmann * pow_3(wm->thetas[i - 1]);
3466 : // Following line is redundant since thetas is being relaxed;
3467 : // removed by FCW, 3/4/03
3468 : //! fw if ( iter >= 1 ) hr(i) = 0.5*(hrprev(i)+hr(i))
3469 : }
3470 :
3471 : // call for new interior film coeff (since it is temperature dependent) if using Detailed inside coef model
3472 44666044 : if (((state.dataSurface->surfIntConv(SurfNum).model == Convect::HcInt::SetByZone) &&
3473 54759300 : (state.dataHeatBal->Zone(ZoneNum).IntConvAlgo == Convect::HcInt::ASHRAETARP)) ||
3474 10093256 : (state.dataSurface->surfIntConv(SurfNum).model == Convect::HcInt::ASHRAETARP)) {
3475 : // coef model is "detailed" and not prescribed by user
3476 : // need to find inside face index, varies with shade/blind etc.
3477 34572788 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3478 600039 : InsideFaceIndex = wm->nglfacep;
3479 : } else {
3480 33972749 : InsideFaceIndex = wm->nglface;
3481 : }
3482 34572788 : CalcISO15099WindowIntConvCoeff(state, SurfNum, wm->thetas[InsideFaceIndex - 1] - Constant::Kelvin, wm->tin - Constant::Kelvin);
3483 34572788 : wm->hcin = state.dataHeatBalSurf->SurfHConvInt(SurfNum);
3484 : }
3485 :
3486 44666044 : Aface = 0.0;
3487 44666044 : Bface = 0.0;
3488 :
3489 : // If interior or exterior shade or blind is present, get heat transfer
3490 : // coefficient from glass and shade/blind to gap between glass and shade/blind,
3491 : // effective gap air temperature, velocity of air in gap and gap outlet temperature.
3492 :
3493 44666044 : if (ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag) || ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3494 776261 : ExtOrIntShadeNaturalFlow(
3495 776261 : state, SurfNum, iter, VGap, TGapNew, TGapOutlet, hcv, state.dataSurface->SurfWinConvHeatFlowNatural(SurfNum));
3496 776261 : if (iter >= 1) {
3497 607016 : hcv = 0.5 * (hcvPrev + hcv);
3498 607016 : VGap = 0.5 * (VGapPrev + VGap);
3499 : }
3500 776261 : hcvPrev = hcv;
3501 776261 : VGapPrev = VGap;
3502 : }
3503 :
3504 44666044 : TAirflowGapOutlet = 0.0;
3505 : // If between-glass shade or blind is not present and this is an airflow window
3506 : // (i.e., with forced airflow in the gap for double glass or in the inner gap for triple glass)
3507 : // get glass-to-air forced convection heat transfer coefficient, average gap air temperature, and
3508 : // convective heat flow from gap.
3509 :
3510 44666044 : if (!ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag) && state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
3511 16427 : BetweenGlassForcedFlow(state, SurfNum, iter, VAirflowGap, TAirflowGapNew, TAirflowGapOutlet, hcvAirflowGap, ConvHeatFlowForced);
3512 : }
3513 :
3514 : // If between-glass shade or blind is present, get convective heat transfer
3515 : // coefficients from glass and shade/blind to the two gaps on either side of the shade/blind.
3516 : // Also get average gas temperature in the two gaps, and, for airflow window, the sum of the
3517 : // convective heat flows from the gaps.
3518 :
3519 44666044 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
3520 108446 : if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) == 0.0) { // Natural convection in gaps
3521 88448 : BetweenGlassShadeNaturalFlow(state, SurfNum, iter, VGap, TGapNewBG, hcvBG);
3522 : } else { // Forced convection in gaps
3523 19998 : BetweenGlassShadeForcedFlow(state, SurfNum, iter, VGap, TGapNewBG, TAirflowGapOutlet, hcvBG, ConvHeatFlowForced);
3524 : }
3525 : }
3526 :
3527 44666044 : ++iter;
3528 :
3529 : // Calculations based on number of glass layers
3530 89332088 : GetHeatBalanceEqCoefMatrix(state,
3531 : SurfNum,
3532 44666044 : wm->ngllayer,
3533 : ShadeFlag,
3534 : sconsh,
3535 : TauShIR,
3536 : EpsShIR1,
3537 : EpsShIR2,
3538 : RhoShIR1,
3539 : RhoShIR2,
3540 : ShGlReflFacIR,
3541 : RhoGlIR1,
3542 : RhoGlIR2,
3543 : hcv,
3544 : TGapNew,
3545 : TAirflowGapNew,
3546 : hcvAirflowGap,
3547 : hcvBG,
3548 : TGapNewBG,
3549 : AbsRadShadeFace,
3550 : hr,
3551 : Aface,
3552 : Bface);
3553 44666044 : LUdecomposition(state, Aface, wm->nglfacep, indx, d); // Note that these routines change Aface;
3554 44666044 : LUsolution(state, Aface, wm->nglfacep, indx, Bface); // face temperatures are returned in Bface
3555 :
3556 163951220 : for (int i = 1; i <= wm->nglfacep; ++i) {
3557 119285176 : wm->thetasPrev[i - 1] = wm->thetas[i - 1];
3558 119285176 : if (iter < MaxIterations / 4) {
3559 119285144 : wm->thetas[i - 1] = 0.5 * wm->thetas[i - 1] + 0.5 * Bface(i);
3560 : } else {
3561 32 : wm->thetas[i - 1] = 0.75 * wm->thetas[i - 1] + 0.25 * Bface(i);
3562 : }
3563 : }
3564 :
3565 44666044 : errtemp = 0.0;
3566 163951220 : for (int i = 1; i <= wm->nglfacep; ++i) {
3567 119285176 : errtemp += std::abs(wm->thetas[i - 1] - wm->thetasPrev[i - 1]);
3568 : }
3569 44666044 : errtemp /= wm->nglfacep;
3570 : }
3571 :
3572 23964637 : state.dataSurface->SurfWinWindowCalcIterationsRep(SurfNum) = iter;
3573 :
3574 : // We have reached iteration limit or we have converged. If we have reached the
3575 : // iteration limit the following test relaxes the convergence tolerance.
3576 : // If we have converged (errtemp <= errtemptol) the following test has not effect.
3577 :
3578 23964637 : if (errtemp < 10 * errtemptol) {
3579 :
3580 : // Window heat balance solution has converged.
3581 :
3582 : // For interior shade, add convective gain from glass/shade gap air flow to zone convective gain;
3583 : // For all cases, get total window heat gain for reporting. See CalcWinFrameAndDividerTemps for
3584 : // contribution of frame and divider.
3585 : // IncidentSolar = state.dataSurface->Surface(SurfNum).Area * state.dataHeatBal->SurfQRadSWOutIncident(SurfNum);
3586 23964637 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3587 : // Interior shade or blind
3588 : // Window heat gain from glazing and shade/blind to zone. Consists of transmitted solar, convection
3589 : // from air exiting gap, convection from zone-side of shade/blind, net IR to zone from shade and net IR to
3590 : // zone from the glass adjacent to the shade/blind (zero if shade/blind IR transmittance is zero).
3591 : // Following assumes glazed area = window area (i.e., dividers ignored) in calculating
3592 : // IR to zone from glass when interior shade/blind is present.
3593 147791 : ShadeArea = state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum);
3594 : // CondHeatGainShade = ShadeArea * sconsh *
3595 : // (wm->thetas(wm->nglfacep - 1) -
3596 : // wm->thetas[wm->nglfacep-1]);
3597 147791 : state.dataSurface->SurfWinGainIRShadeToZoneRep(SurfNum) =
3598 147791 : ShadeArea * EpsShIR2 * (Constant::StefanBoltzmann * pow_4(wm->thetas[wm->nglfacep - 1]) - wm->Rmir) +
3599 147791 : EpsShIR1 * (Constant::StefanBoltzmann * pow_4(wm->thetas[wm->nglfacep - 2]) - wm->Rmir) * RhoGlIR2 * TauShIR / ShGlReflFacIR;
3600 147791 : state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) =
3601 147791 : ShadeArea * (wm->emis[2 * wm->ngllayer - 1] * TauShIR / ShGlReflFacIR) *
3602 147791 : (Constant::StefanBoltzmann * pow_4(wm->thetas[2 * wm->ngllayer - 1]) - wm->Rmir);
3603 147791 : state.dataSurface->SurfWinGainConvShadeToZoneRep(SurfNum) = ShadeArea * wm->hcin * (wm->thetas[wm->nglfacep - 1] - wm->tin);
3604 147791 : state.dataSurface->SurfWinHeatGain(SurfNum) =
3605 147791 : state.dataSurface->SurfWinTransSolar(SurfNum) + state.dataSurface->SurfWinConvHeatFlowNatural(SurfNum) +
3606 147791 : state.dataSurface->SurfWinGainConvShadeToZoneRep(SurfNum) + state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) +
3607 147791 : state.dataSurface->SurfWinGainIRShadeToZoneRep(SurfNum);
3608 : } else {
3609 : // Interior shade or blind not present; innermost layer is glass
3610 : // CondHeatGainGlass = state.dataSurface->Surface(SurfNum).Area * wm->scon(wm->ngllayer) *
3611 : // (wm->thetas(2 * wm->ngllayer - 1) -
3612 : // wm->thetas[2 * wm->ngllayer - 1]);
3613 23816846 : state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) =
3614 23816846 : state.dataSurface->Surface(SurfNum).Area * wm->emis[2 * wm->ngllayer - 1] *
3615 23816846 : (Constant::StefanBoltzmann * pow_4(wm->thetas[2 * wm->ngllayer - 1]) - wm->Rmir);
3616 23816846 : state.dataSurface->SurfWinGainConvGlazToZoneRep(SurfNum) =
3617 23816846 : state.dataSurface->Surface(SurfNum).Area * wm->hcin * (wm->thetas[2 * wm->ngllayer - 1] - wm->tin);
3618 47633692 : state.dataSurface->SurfWinHeatGain(SurfNum) = state.dataSurface->SurfWinTransSolar(SurfNum) +
3619 23816846 : state.dataSurface->SurfWinGainConvGlazToZoneRep(SurfNum) +
3620 23816846 : state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum);
3621 : }
3622 :
3623 : // Add convective heat gain from airflow window
3624 : // Note: effect of fan heat on gap outlet temperature is neglected since fan power (based
3625 : // on pressure drop through the gap) is extremely small
3626 :
3627 23964637 : state.dataSurface->SurfWinGapConvHtFlowRep(SurfNum) = 0.0;
3628 23964637 : state.dataSurface->SurfWinGapConvHtFlowRepEnergy(SurfNum) = 0.0;
3629 23964637 : TotAirflowGap = state.dataSurface->SurfWinAirflowThisTS(SurfNum) * state.dataSurface->Surface(SurfNum).Width;
3630 23964637 : TAirflowGapOutletC = TAirflowGapOutlet - Constant::Kelvin;
3631 23964637 : state.dataSurface->SurfWinTAirflowGapOutlet(SurfNum) = TAirflowGapOutletC;
3632 23964637 : if (state.dataSurface->SurfWinAirflowThisTS(SurfNum) > 0.0) {
3633 16128 : state.dataSurface->SurfWinGapConvHtFlowRep(SurfNum) = ConvHeatFlowForced;
3634 16128 : state.dataSurface->SurfWinGapConvHtFlowRepEnergy(SurfNum) =
3635 16128 : state.dataSurface->SurfWinGapConvHtFlowRep(SurfNum) * state.dataGlobal->TimeStepZoneSec;
3636 : // Add heat from gap airflow to zone air if destination is inside air; save the heat gain to return
3637 : // air in case it needs to be sent to the zone (due to no return air determined in HVAC simulation)
3638 32256 : if (state.dataSurface->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Indoor ||
3639 16128 : state.dataSurface->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Return) {
3640 0 : auto &thisZoneHB = state.dataZoneTempPredictorCorrector->zoneHeatBalance(ZoneNum);
3641 0 : if (state.dataSurface->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
3642 0 : InletAirHumRat = thisZoneHB.airHumRat;
3643 : } else { // AirflowSource = outside air
3644 0 : InletAirHumRat = state.dataEnvrn->OutHumRat;
3645 : }
3646 0 : Real64 ZoneTemp = thisZoneHB.MAT; // this should be Tin (account for different reference temps)
3647 0 : CpAirOutlet = PsyCpAirFnW(InletAirHumRat);
3648 0 : CpAirZone = PsyCpAirFnW(thisZoneHB.airHumRat);
3649 0 : state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum) =
3650 0 : TotAirflowGap * (CpAirOutlet * (TAirflowGapOutletC)-CpAirZone * ZoneTemp);
3651 0 : if (state.dataSurface->SurfWinAirflowDestination(SurfNum) == WindowAirFlowDestination::Indoor) {
3652 0 : state.dataSurface->SurfWinHeatGain(SurfNum) += state.dataSurface->SurfWinRetHeatGainToZoneAir(SurfNum);
3653 : }
3654 : }
3655 : // For AirflowDestination = ReturnAir in a controlled (i.e., conditioned) zone with return air, see CalcZoneLeavingConditions
3656 : // for calculation of modification of return-air temperature due to airflow from window gaps into return air.
3657 : }
3658 :
3659 : // Correct WinHeatGain for interior diffuse shortwave (solar and shortwave from lights) transmitted
3660 : // back out window
3661 23964637 : int const ConstrNum = state.dataSurface->SurfActiveConstruction(SurfNum);
3662 23964637 : int const ConstrNumSh = state.dataSurface->SurfWinActiveShadedConstruction(SurfNum);
3663 :
3664 23964637 : Real64 reflDiff = 0.0; // Diffuse shortwave back reflectance
3665 23964637 : if (NOT_SHADED(ShadeFlag)) {
3666 23706736 : reflDiff = state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack;
3667 257901 : } else if (ANY_SHADE_SCREEN(ShadeFlag)) {
3668 49460 : reflDiff = state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack;
3669 208441 : } else if (ANY_BLIND(ShadeFlag)) {
3670 136655 : if (state.dataSurface->SurfWinMovableSlats(SurfNum)) {
3671 9366 : reflDiff = General::Interp(
3672 3122 : state.dataConstruction->Construct(ConstrNumSh).BlReflectSolDiffBack(state.dataSurface->SurfWinSlatsAngIndex(SurfNum)),
3673 3122 : state.dataConstruction->Construct(ConstrNumSh)
3674 6244 : .BlTransDiff(std::min(Material::MaxSlatAngs, state.dataSurface->SurfWinSlatsAngIndex(SurfNum) + 1)),
3675 3122 : state.dataSurface->SurfWinSlatsAngInterpFac(SurfNum));
3676 : } else {
3677 133533 : reflDiff = state.dataConstruction->Construct(ConstrNumSh).BlReflectSolDiffBack(1);
3678 : }
3679 71786 : } else if (ShadeFlag == WinShadingType::SwitchableGlazing) {
3680 71786 : reflDiff = InterpSw(state.dataSurface->SurfWinSwitchingFactor(SurfNum),
3681 71786 : state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack,
3682 71786 : state.dataConstruction->Construct(ConstrNumSh).ReflectSolDiffBack);
3683 : }
3684 : // shouldn't this be + outward flowing fraction of absorbed SW? -- do not know whose comment this is? LKL (9/2012)
3685 23964637 : state.dataSurface->SurfWinLossSWZoneToOutWinRep(SurfNum) =
3686 23964637 : state.dataHeatBal->EnclSolQSWRad(state.dataSurface->Surface(SurfNum).SolarEnclIndex) * state.dataSurface->Surface(SurfNum).Area *
3687 47929274 : (1 - reflDiff) +
3688 23964637 : state.dataHeatBalSurf->SurfWinInitialBeamSolInTrans(SurfNum);
3689 23964637 : state.dataSurface->SurfWinHeatGain(SurfNum) -=
3690 23964637 : (state.dataSurface->SurfWinLossSWZoneToOutWinRep(SurfNum) +
3691 23964637 : state.dataHeatBalSurf->SurfWinInitialDifSolInTrans(SurfNum) * state.dataSurface->Surface(SurfNum).Area);
3692 :
3693 23964637 : if (ANY_SHADE_SCREEN(ShadeFlag) || ANY_BLIND(ShadeFlag)) {
3694 186115 : state.dataSurface->SurfWinShadingAbsorbedSolar(SurfNum) =
3695 186115 : (state.dataSurface->SurfWinExtBeamAbsByShade(SurfNum) + state.dataSurface->SurfWinExtDiffAbsByShade(SurfNum)) *
3696 186115 : (state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum));
3697 186115 : state.dataSurface->SurfWinShadingAbsorbedSolarEnergy(SurfNum) =
3698 186115 : state.dataSurface->SurfWinShadingAbsorbedSolar(SurfNum) * state.dataGlobal->TimeStepZoneSec;
3699 : }
3700 23964637 : if (state.dataEnvrn->SunIsUp) {
3701 :
3702 12130790 : state.dataSurface->SurfWinSysSolTransmittance(SurfNum) =
3703 12130790 : state.dataSurface->SurfWinTransSolar(SurfNum) /
3704 12130790 : (state.dataHeatBal->SurfQRadSWOutIncident(SurfNum) *
3705 12130790 : (state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum)) +
3706 : 0.0001);
3707 12130790 : state.dataSurface->SurfWinSysSolAbsorptance(SurfNum) =
3708 12130790 : (state.dataHeatBal->SurfWinQRadSWwinAbsTot(SurfNum) + state.dataSurface->SurfWinShadingAbsorbedSolar(SurfNum)) /
3709 12130790 : (state.dataHeatBal->SurfQRadSWOutIncident(SurfNum) *
3710 12130790 : (state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum)) +
3711 : 0.0001);
3712 12130790 : state.dataSurface->SurfWinSysSolReflectance(SurfNum) =
3713 12130790 : 1.0 - state.dataSurface->SurfWinSysSolTransmittance(SurfNum) - state.dataSurface->SurfWinSysSolAbsorptance(SurfNum);
3714 : } else {
3715 11833847 : state.dataSurface->SurfWinSysSolTransmittance(SurfNum) = 0.0;
3716 11833847 : state.dataSurface->SurfWinSysSolAbsorptance(SurfNum) = 0.0;
3717 11833847 : state.dataSurface->SurfWinSysSolReflectance(SurfNum) = 0.0;
3718 : }
3719 :
3720 : // Save hcv for use in divider calc with interior or exterior shade (see CalcWinFrameAndDividerTemps)
3721 23964637 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag) || ANY_EXTERIOR_SHADE_BLIND_SCREEN(ShadeFlag))
3722 169245 : state.dataSurface->SurfWinConvCoeffWithShade(SurfNum) = hcv;
3723 : } else {
3724 : // No convergence after MaxIterations even with relaxed error tolerance
3725 0 : ShowSevereError(state, format("Convergence error in SolveForWindowTemperatures for window {}", state.dataSurface->Surface(SurfNum).Name));
3726 0 : ShowContinueErrorTimeStamp(state, "");
3727 :
3728 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3729 : // report out temperatures
3730 0 : for (int i = 1; i <= wm->nglfacep; ++i) {
3731 0 : ShowContinueError(state,
3732 0 : format("Glazing face index = {} ; new temperature ={:.4R}C ; previous temperature = {:.4R}C",
3733 : i,
3734 0 : wm->thetas[i - 1] - Constant::Kelvin,
3735 0 : wm->thetasPrev[i - 1] - Constant::Kelvin));
3736 : }
3737 : }
3738 :
3739 0 : ShowFatalError(state,
3740 0 : format("Program halted because of convergence error in SolveForWindowTemperatures for window {}",
3741 0 : state.dataSurface->Surface(SurfNum).Name));
3742 : }
3743 23964637 : } // SolveForWindowTemperatures()
3744 :
3745 : //****************************************************************************
3746 :
3747 776261 : void ExtOrIntShadeNaturalFlow(EnergyPlusData &state,
3748 : int const SurfNum, // Surface number
3749 : int const iter, // Iteration number for glass heat balance calculation
3750 : Real64 &VGap, // Air velocity in glass-shade/blind gap (m/s)
3751 : Real64 &TGapNew, // Current-iteration average air temp in glass-shade/blind gap (K)
3752 : Real64 &TGapOutlet, // Temperature of air leaving glass-shade/blind gap at top for upward
3753 : Real64 &hcv, // Convection coefficient from gap glass or shade to gap air (W/m2-K)
3754 : Real64 &QConvGap // Convective heat gain from glass-shade/blind gap for interior shade (W)
3755 : )
3756 : {
3757 :
3758 : // SUBROUTINE INFORMATION:
3759 : // AUTHOR F. Winkelmann
3760 : // DATE WRITTEN December 2000
3761 : // MODIFIED June 2001: add window blinds
3762 : // May 2006 (RR): add exterior window screens
3763 : // RE-ENGINEERED na
3764 :
3765 : // PURPOSE OF THIS SUBROUTINE:
3766 : // Called by SolveForWindowTemperatures for windows that have an interior
3767 : // or exterior blind or shade in place.
3768 : // Solves for air flow in gap between glass and shade/blind.
3769 : // Finds temperature of gap air and coefficient for convective heat transfer
3770 : // from glass to gap air and shade/blind to gap air.
3771 :
3772 : // METHODOLOGY EMPLOYED:
3773 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
3774 : // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
3775 :
3776 : // SUBROUTINE ARGUMENT DEFINITIONS:
3777 : // air flow or bottom for downward air flow (K)
3778 :
3779 : int ConstrNumSh; // Shaded construction number
3780 : int MatNumSh; // Material number of shade/blind layer
3781 : int nglassfaces; // Number of glass faces in contruction
3782 : Real64 TGapInlet; // Temperature of air entering glass-shade/blind gap at bottom for upward
3783 : // air flow or top for downward air flow (K)
3784 : Real64 TGlassFace; // Temperature of glass surface facing glass-shade/blind gap (K)
3785 : Real64 TShadeFace; // Temperature of shade surface facing glass-shade/blind gap (K)
3786 : Real64 hGapStill; // Still-air glass-shade/blind gap conduction/convection coeff (W/m2-K)
3787 : Real64 TGapOld; // Previous-iteration average air temp in glass-shade/blind gap (K)
3788 : Real64 GapHeight; // Vertical length of glass-shade/blind gap (m)
3789 : Real64 GapDepth; // Distance from shade to glass (m)
3790 : Real64 RhoAir; // Density of glass-shade/blind gap air at a temperature of TGapOld (kg/m3)
3791 : Real64 RhoTRef; // Density of glass-shade/blind air at reference temp = KelvinConv (kg/m3)
3792 : Real64 ViscAir; // Viscosity of glass-shade/blind gap air at a temperature of TGapOld (kg/m3)
3793 : Real64 AGap; // Cross sectional area of glass-shade/blind gap (m2); for vertical window, this
3794 : // is in horizontal plane normal to window.
3795 : Real64 ATopGap; // Area of the top and bottom openings (m2)
3796 : Real64 ABotGap;
3797 : Real64 ALeftGap; // Area of the left and right openings (m2)
3798 : Real64 ARightGap;
3799 : Real64 AHolesGap; // Area of the holes in the shade (assumed homogeneously
3800 : // distributed) (m2)
3801 : Real64 ATopLRH; // Intermediate variables
3802 : Real64 ABotLRH;
3803 : Real64 AEqInlet; // Equivalent inlet and outlet opening areas (m2)
3804 : Real64 AEqOutlet;
3805 : Real64 Zinlet; // Inlet and outlet pressure loss factors
3806 : Real64 Zoutlet;
3807 : Real64 AVGap; // Coeff. of VGap**2 term in pressure balance equation
3808 : Real64 BVGap; // Coeff. of VGap term in pressure balance equation
3809 : Real64 CVGap; // VGap-independent term in pressure balance equation
3810 : Real64 GapHeightChar; // Characteristic height of the gap air temperature profile (m)
3811 : Real64 TAve; // Average of TGlass and TShade (K)
3812 : // REAL(r64) :: AirProps(8) ! Air properties
3813 : int TotGaps; // Glass/glass gaps + glass-shade/blind gap
3814 : Real64 con; // Gap conductivity and derivative
3815 : Real64 gr; // glass-shade/blind gap Grashof number
3816 : Real64 pr; // glass-shade/blind gap Prandtl number
3817 : Real64 nu; // glass-shade/blind gap Nusselt number
3818 : WinShadingType ShadeFlag; // Shading flag
3819 : int BlNum; // Blind number
3820 :
3821 776261 : auto &wm = state.dataWindowManager;
3822 : // Air properties
3823 : // Dens dDens/dT Con dCon/dT Vis dVis/dT Prandtl dPrandtl/dT
3824 : // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72, 1.8d-3 /
3825 :
3826 776261 : ConstrNumSh = state.dataSurface->SurfWinActiveShadedConstruction(SurfNum);
3827 776261 : ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
3828 776261 : nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
3829 776261 : TotGaps = state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
3830 :
3831 776261 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) { // Interior shade or blind
3832 600039 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(nglassfaces);
3833 600039 : TGapInlet = wm->tin;
3834 600039 : TGlassFace = wm->thetas[nglassfaces - 1];
3835 600039 : TShadeFace = wm->thetas[nglassfaces];
3836 : } else { // Exterior shade, screen or blind
3837 176222 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1);
3838 176222 : TGapInlet = wm->tout;
3839 176222 : TGlassFace = wm->thetas[0];
3840 176222 : TShadeFace = wm->thetas[nglassfaces + 1];
3841 : }
3842 776261 : TAve = 0.5 * (TGlassFace + TShadeFace);
3843 :
3844 776261 : if (iter == 0) {
3845 169245 : TGapOld = 0.5 * (TAve + TGapInlet);
3846 : } else {
3847 607016 : TGapOld = TGapNew;
3848 : }
3849 :
3850 : // Conductance of gap between glass and shade assuming gap is sealed
3851 776261 : WindowGasConductance(state, TGlassFace, TShadeFace, TotGaps, con, pr, gr);
3852 776261 : NusseltNumber(state, SurfNum, TGlassFace, TShadeFace, TotGaps, gr, pr, nu);
3853 776261 : hGapStill = con / wm->gaps[TotGaps - 1].width * nu;
3854 :
3855 : // For near-horizontal windows (i.e., no more than 5 deg from horizontal) assume
3856 : // there is no air flow thru gap
3857 :
3858 776261 : if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) < 0.0872) {
3859 0 : VGap = 0.0;
3860 0 : hcv = 2.0 * hGapStill;
3861 0 : QConvGap = 0.0;
3862 0 : TGapNew = TAve;
3863 0 : TGapOutlet = TAve;
3864 0 : return;
3865 : }
3866 :
3867 776261 : GapHeight = state.dataSurface->Surface(SurfNum).Height;
3868 :
3869 776261 : if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) {
3870 194498 : auto const *matShade = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(MatNumSh));
3871 194498 : assert(matShade != nullptr);
3872 : // Shade or Screen on
3873 194498 : GapDepth = matShade->WinShadeToGlassDist;
3874 194498 : AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
3875 194498 : ATopGap = matShade->WinShadeTopOpeningMult * AGap;
3876 194498 : ABotGap = matShade->WinShadeBottomOpeningMult * AGap;
3877 194498 : ALeftGap = matShade->WinShadeLeftOpeningMult * GapHeight * GapDepth;
3878 194498 : ARightGap = matShade->WinShadeRightOpeningMult * GapHeight * GapDepth;
3879 194498 : AHolesGap = matShade->WinShadeAirFlowPermeability * GapHeight * state.dataSurface->Surface(SurfNum).Width;
3880 776261 : } else if (ShadeFlag == WinShadingType::ExtScreen) {
3881 97106 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(state.dataMaterial->Material(MatNumSh));
3882 97106 : assert(matScreen != nullptr);
3883 : // Shade or Screen on
3884 97106 : GapDepth = matScreen->toGlassDist;
3885 97106 : AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
3886 97106 : ATopGap = matScreen->topOpeningMult * AGap;
3887 97106 : ABotGap = matScreen->bottomOpeningMult * AGap;
3888 97106 : ALeftGap = matScreen->leftOpeningMult * GapHeight * GapDepth;
3889 97106 : ARightGap = matScreen->rightOpeningMult * GapHeight * GapDepth;
3890 97106 : AHolesGap = matScreen->airFlowPermeability * GapHeight * state.dataSurface->Surface(SurfNum).Width;
3891 : } else {
3892 : // Blind on
3893 484657 : BlNum = state.dataSurface->SurfWinBlindNumber(SurfNum);
3894 484657 : auto const &blind = state.dataMaterial->Blind(BlNum);
3895 484657 : GapDepth = blind.BlindToGlassDist;
3896 484657 : AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
3897 484657 : ATopGap = blind.BlindTopOpeningMult * AGap;
3898 484657 : ABotGap = blind.BlindBottomOpeningMult * AGap;
3899 484657 : ALeftGap = blind.BlindLeftOpeningMult * GapHeight * GapDepth;
3900 484657 : ARightGap = blind.BlindRightOpeningMult * GapHeight * GapDepth;
3901 484657 : AHolesGap = state.dataSurface->SurfWinBlindAirFlowPermeability(SurfNum) * GapHeight * state.dataSurface->Surface(SurfNum).Width;
3902 : }
3903 :
3904 776261 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapOld - Constant::Kelvin);
3905 776261 : ViscAir = wm->AirProps[4] + wm->AirProps[5] * (TGapOld - Constant::Kelvin);
3906 : // The factor 12 in the next line is based on the solution of steady laminar flow between fixed
3907 : // parallel plates given in Sec. 6.9.1 of Fundamentals of Fluid Mechanics, Munson/Young/Okishi, Third Edition
3908 : // Update, John Wiley & Sons, 1998; ISO 15099 has 8 for this factor, which is for flow through a tube.
3909 776261 : BVGap = 12.0 * ViscAir * GapHeight / pow_2(GapDepth);
3910 : // Adding 0.000001 and 0.000002 in the following gives ATopLRH = ABotLRH =
3911 : // 0.25*(ALeftGap + ARightGap + AHolesGap) when ABotGap = ATopGap = 0.0 (shade/blind sealed at
3912 : // bottom and top but possibly open at left side, right side and/or in-shade/blind)
3913 776261 : ATopLRH = 0.5 * ((ATopGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
3914 776261 : ABotLRH = 0.5 * ((ABotGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
3915 776261 : if (TGapOld > TGapInlet) {
3916 366845 : AEqInlet = ABotGap + ATopLRH;
3917 366845 : AEqOutlet = ATopGap + ABotLRH;
3918 : } else {
3919 409416 : AEqOutlet = ABotGap + ATopLRH;
3920 409416 : AEqInlet = ATopGap + ABotLRH;
3921 : }
3922 : // Adding 0.000001 in the following gives very large value of Zinlet for AEqInlet = 0 and
3923 : // very large value of Zoutlet for AEqInlet = 0; this gives VGap close to zero, as required
3924 : // when there is no inlet and/or outlet for air. This then reduces to the
3925 : // case of a completely sealed shade, in which hcv = 2*hGapStill and QConvGap = 0.
3926 776261 : Zinlet = pow_2(AGap / (0.6 * AEqInlet + 0.000001) - 1.0);
3927 776261 : Zoutlet = pow_2(AGap / (0.6 * AEqOutlet + 0.000001) - 1.0);
3928 776261 : AVGap = 0.5 * RhoAir * (1 + Zinlet + Zoutlet);
3929 776261 : RhoTRef = wm->AirProps[0] * Constant::Kelvin;
3930 776261 : CVGap = RhoTRef * 9.81 * GapHeight * state.dataSurface->Surface(SurfNum).SinTilt * (TGapOld - TGapInlet) / (TGapOld * TGapInlet);
3931 :
3932 : // Solution of quadratic equation in VGap
3933 776261 : VGap = (std::sqrt(pow_2(BVGap) + std::abs(4.0 * AVGap * CVGap)) - BVGap) / (2.0 * AVGap);
3934 776261 : hcv = 2.0 * hGapStill + 4.0 * VGap;
3935 776261 : GapHeightChar = RhoAir * 1008.0 * GapDepth * VGap / (2.0 * hcv);
3936 : // The following avoids divide by zero and exponential underflow
3937 776261 : if (GapHeightChar == 0.0) {
3938 0 : TGapOutlet = TAve;
3939 776261 : } else if ((GapHeight / GapHeightChar) > 15.0) {
3940 67499 : TGapOutlet = TAve;
3941 : } else {
3942 708762 : TGapOutlet = TAve - (TAve - TGapInlet) * std::exp(-GapHeight / GapHeightChar);
3943 : }
3944 776261 : TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet);
3945 :
3946 : // Convective heat flow from gap to room air for interior shade or blind
3947 776261 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
3948 600039 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapNew - Constant::Kelvin);
3949 600039 : QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet);
3950 : // Exclude convection to gap due to divider, if present; divider convection handled
3951 : // separately in CalcWinFrameAndDividerTemps
3952 600039 : QConvGap *= 0.5 * (1.0 + state.dataSurface->Surface(SurfNum).Area /
3953 600039 : (state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum)));
3954 : }
3955 : }
3956 :
3957 : //****************************************************************************
3958 :
3959 88448 : void BetweenGlassShadeNaturalFlow(EnergyPlusData &state,
3960 : int const SurfNum, // Surface number
3961 : int const iter, // Iteration number for glass heat balance calculation
3962 : Real64 &VGap, // Gas velocity in gaps (m/s)
3963 : Array1A<Real64> TGapNew, // Current-iteration average gas temp in gaps (K)
3964 : Array1A<Real64> hcv // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
3965 : )
3966 : {
3967 :
3968 : // SUBROUTINE INFORMATION:
3969 : // AUTHOR F. Winkelmann
3970 : // DATE WRITTEN December 2002
3971 : // MODIFIED na
3972 : // RE-ENGINEERED na
3973 :
3974 : // PURPOSE OF THIS SUBROUTINE:
3975 : // Called by SolveForWindowTemperatures for windows that have a
3976 : // between-glass shade or blind in place.
3977 : // Solves for gas flow in the two gaps on either side of shade/blind.
3978 : // Finds average temperature of gas in the two gaps, and the coefficient
3979 : // for convective heat transfer from glass to gap gas and shade/blind to gap gas
3980 : // for the two gaps. The two gaps are assumed to have the same depth so that the
3981 : // gas velocity due to natural convection is the same in the two gaps.
3982 : // The Between-glass shade/blind is between the two glass layers of double glazing
3983 : // or between the two inner glass layers of triple glazing. The quadruple glazing
3984 : // case is not considered.
3985 :
3986 : // METHODOLOGY EMPLOYED:
3987 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
3988 : // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
3989 :
3990 : // Argument array dimensioning
3991 88448 : TGapNew.dim(2);
3992 88448 : hcv.dim(2);
3993 :
3994 : int ConstrNumSh; // Shaded construction number
3995 : int MatNumSh; // Material number of shade/blind layer
3996 : int nglassfaces; // Number of glass faces in contruction
3997 : // In the following, "gaps" refer to the gaps on either side of the shade/blind
3998 88448 : Array1D<Real64> TGlassFace(2); // Temperature of glass surfaces facing gaps (K)
3999 88448 : Array1D<Real64> TShadeFace(2); // Temperature of shade surfaces facing gaps (K)
4000 88448 : Array1D<Real64> hGapStill(2); // Still-air conduction/convection coeffs for the gaps (W/m2-K)
4001 88448 : Array1D<Real64> TGapOld(2); // Previous-iteration average gas temp in gaps (K)
4002 : Real64 GapHeight; // Vertical length of glass-shade/blind gap (m)
4003 : Real64 GapDepth; // Distance from shade/blind to glass; assumed same for both gaps (m)
4004 88448 : Array1D<Real64> RhoGas(2); // Density of gap gas at a temperature of TGapOld (kg/m3)
4005 : Real64 RhoTRef; // Density of gap gas at reference temp = KelvinConvK (kg/m3)
4006 88448 : Array1D<Real64> ViscGas(2); // Viscosity of gap gas at a temperature of TGapOld (kg/m3)
4007 : Real64 RhoGasZero; // Gas density at KelvinConvK
4008 : Real64 ViscGasZero; // Gas viscosity at KelvinConvK (not used)
4009 : Real64 AGap; // Cross sectional area of gaps (m2); for vertical window, this
4010 : // is in horizontal plane normal to window.
4011 : Real64 ATopGap; // Area of the top and bottom openings of shade/blind (m2)
4012 : Real64 ABotGap;
4013 : Real64 ALeftGap; // Area of the left and right openings of shade/blind (m2)
4014 : Real64 ARightGap;
4015 : Real64 AHolesGap; // Area of the holes in the shade/blind (assumed homogeneously
4016 : // distributed) (m2)
4017 : Real64 ATopLRH; // Intermediate variables
4018 : Real64 ABotLRH;
4019 : Real64 AEqInlet; // Equivalent inlet and outlet opening areas (m2)
4020 : Real64 AEqOutlet;
4021 : Real64 Zinlet; // Inlet and outlet pressure loss factors
4022 : Real64 Zoutlet;
4023 : Real64 AVGap; // Coeff. of VGap**2 term in pressure balance equation
4024 : Real64 BVGap; // Coeff. of VGap term in pressure balance equation
4025 : Real64 CVGap; // VGap-independent term in pressure balance equation
4026 88448 : Array1D<Real64> GapHeightChar(2); // Characteristic height of the gap gas temperature profile (m)
4027 88448 : Array1D<Real64> EpsChar(2); // EXP(-GapHeight/GapHeightChar(IGap))
4028 88448 : Array1D<Real64> TAve(2); // Average of TGlass and TShade for the gaps (K)
4029 : Real64 con; // Gap gas conductivity and derivative
4030 : Real64 gr; // Gap gas Grashof number
4031 : Real64 pr; // Gap gas Prandtl number
4032 : Real64 nu; // Gap gas Nusselt number
4033 : WinShadingType ShadeFlag; // Shading flag
4034 : int BlNum; // Blind number
4035 : int IGapInc; // Gap increment (0 or 1)
4036 :
4037 88448 : auto &wm = state.dataWindowManager;
4038 :
4039 88448 : ConstrNumSh = state.dataSurface->Surface(SurfNum).activeShadedConstruction;
4040 88448 : ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
4041 88448 : nglassfaces = 2 * state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers;
4042 :
4043 88448 : if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double glazing
4044 51044 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(3);
4045 51044 : IGapInc = 0;
4046 153132 : for (int IGap = 1; IGap <= 2; ++IGap) {
4047 102088 : TGlassFace(IGap) = wm->thetas[IGap];
4048 102088 : TShadeFace(IGap) = wm->thetas[IGap + 3];
4049 : }
4050 : } else { // Triple glazing
4051 37404 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(5);
4052 37404 : IGapInc = 1;
4053 112212 : for (int IGap = 1; IGap <= 2; ++IGap) {
4054 74808 : TGlassFace(IGap) = wm->thetas[IGap + 2];
4055 74808 : TShadeFace(IGap) = wm->thetas[IGap + 5];
4056 : }
4057 : }
4058 88448 : auto const *thisMaterialShade = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(MatNumSh));
4059 :
4060 265344 : for (int IGap = 1; IGap <= 2; ++IGap) {
4061 176896 : TAve(IGap) = 0.5 * (TGlassFace(IGap) + TShadeFace(IGap));
4062 176896 : if (iter == 0) {
4063 17612 : TGapOld(IGap) = TAve(IGap);
4064 : } else {
4065 159284 : TGapOld(IGap) = TGapNew(IGap);
4066 : }
4067 : // Conductance of gaps on either side of shade/blind assuming gaps are sealed
4068 176896 : WindowGasConductance(state, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, con, pr, gr);
4069 176896 : NusseltNumber(state, SurfNum, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, gr, pr, nu);
4070 176896 : hGapStill(IGap) = con / wm->gaps[IGap + IGapInc - 1].width * nu;
4071 : }
4072 :
4073 : // For near-horizontal windows (i.e., no more than 5 deg from horizontal) assume
4074 : // there is no air flow thru gap
4075 :
4076 88448 : if (std::abs(state.dataSurface->Surface(SurfNum).SinTilt) < 0.0872) {
4077 0 : VGap = 0.0;
4078 0 : for (int IGap = 1; IGap <= 2; ++IGap) {
4079 0 : hcv(IGap) = 2.0 * hGapStill(IGap);
4080 0 : TGapNew(IGap) = TAve(IGap);
4081 : }
4082 0 : return;
4083 : }
4084 :
4085 88448 : GapHeight = state.dataSurface->Surface(SurfNum).Height;
4086 88448 : GapDepth = wm->gaps[IGapInc].width;
4087 88448 : AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
4088 :
4089 88448 : if (ShadeFlag == WinShadingType::BGShade) {
4090 : // Shade on
4091 46151 : ATopGap = thisMaterialShade->WinShadeTopOpeningMult * AGap;
4092 46151 : ABotGap = thisMaterialShade->WinShadeBottomOpeningMult * AGap;
4093 46151 : ALeftGap = thisMaterialShade->WinShadeLeftOpeningMult * GapHeight * GapDepth;
4094 46151 : ARightGap = thisMaterialShade->WinShadeRightOpeningMult * GapHeight * GapDepth;
4095 46151 : AHolesGap = thisMaterialShade->WinShadeAirFlowPermeability * GapHeight * state.dataSurface->Surface(SurfNum).Width;
4096 : } else {
4097 : // Blind on
4098 42297 : BlNum = state.dataSurface->SurfWinBlindNumber(SurfNum);
4099 42297 : auto const &blind = state.dataMaterial->Blind(BlNum);
4100 42297 : ATopGap = blind.BlindTopOpeningMult * AGap;
4101 42297 : ABotGap = blind.BlindBottomOpeningMult * AGap;
4102 42297 : ALeftGap = blind.BlindLeftOpeningMult * GapHeight * GapDepth;
4103 42297 : ARightGap = blind.BlindRightOpeningMult * GapHeight * GapDepth;
4104 42297 : AHolesGap = state.dataSurface->SurfWinBlindAirFlowPermeability(SurfNum) * GapHeight * state.dataSurface->Surface(SurfNum).Width;
4105 : }
4106 :
4107 265344 : for (int IGap = 1; IGap <= 2; ++IGap) {
4108 176896 : WindowGasPropertiesAtTemp(state, TGapOld(IGap), IGap + IGapInc, RhoGas(IGap), ViscGas(IGap));
4109 : }
4110 :
4111 88448 : BVGap = 12.0 * (ViscGas(1) + ViscGas(2)) * GapHeight / pow_2(GapDepth);
4112 : // Adding 0.000001 and 0.000002 in the following gives ATopLRH = ABotLRH =
4113 : // 0.25*(ALeftGap + ARightGap + AHolesGap) when ABotGap = ATopGap = 0.0 (shade/blind sealed at
4114 : // bottom and top but possibly open at left side, right side and/or in shade/blind)
4115 88448 : ATopLRH = 0.5 * ((ATopGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
4116 88448 : ABotLRH = 0.5 * ((ABotGap + 0.000001) / (ABotGap + ATopGap + 0.000002)) * (ALeftGap + ARightGap + AHolesGap);
4117 88448 : AEqInlet = ABotGap + ATopLRH;
4118 88448 : AEqOutlet = ATopGap + ABotLRH;
4119 :
4120 : // Adding 0.000001 in the following gives very large value of Zinlet for AEqInlet = 0 and
4121 : // very large value of Zoutlet for AEqInlet = 0; this gives VGap close to zero, as required
4122 : // when there is no inlet and/or outlet for air. This then reduces to the
4123 : // case of a completely sealed shade, in which hcv = 2*hGapStill and QConvGap = 0.
4124 88448 : Zinlet = pow_2(AGap / (0.6 * AEqInlet + 0.000001) - 1.0);
4125 88448 : Zoutlet = pow_2(AGap / (0.6 * AEqOutlet + 0.000001) - 1.0);
4126 88448 : AVGap = 0.5 * (RhoGas(1) + RhoGas(2)) * (1.0 + Zinlet + Zoutlet);
4127 88448 : WindowGasPropertiesAtTemp(state, Constant::Kelvin, 1 + IGapInc, RhoGasZero, ViscGasZero);
4128 88448 : RhoTRef = RhoGasZero * Constant::Kelvin;
4129 88448 : CVGap = RhoTRef * 9.81 * GapHeight * state.dataSurface->Surface(SurfNum).SinTilt * (TGapOld(1) - TGapOld(2)) / (TGapOld(1) * TGapOld(2));
4130 :
4131 : // Solution of quadratic equation in VGap
4132 :
4133 88448 : VGap = (std::sqrt(pow_2(BVGap) + std::abs(4 * AVGap * CVGap)) - BVGap) / (2 * AVGap);
4134 :
4135 265344 : for (int IGap = 1; IGap <= 2; ++IGap) {
4136 176896 : hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
4137 176896 : GapHeightChar(IGap) = RhoGas(IGap) * 1008.0 * GapDepth * VGap / (2.0 * hcv(IGap));
4138 : // The following avoids divide by zero and exponential underflow
4139 176896 : if (GapHeightChar(IGap) == 0.0) {
4140 0 : EpsChar(IGap) = 0.0;
4141 176896 : } else if ((GapHeight / GapHeightChar(IGap)) > 15.0) {
4142 8938 : EpsChar(IGap) = 0.0;
4143 : } else {
4144 167958 : EpsChar(IGap) = std::exp(-GapHeight / GapHeightChar(IGap));
4145 : }
4146 : }
4147 :
4148 176896 : TGapNew(1) =
4149 88448 : TAve(1) - (TAve(1) - TAve(2)) * (GapHeightChar(1) / GapHeight) * (1 - EpsChar(1)) * (1 - EpsChar(2)) / (1 - EpsChar(1) * EpsChar(2));
4150 :
4151 176896 : TGapNew(2) =
4152 88448 : TAve(2) - (TAve(2) - TAve(1)) * (GapHeightChar(2) / GapHeight) * (1 - EpsChar(1)) * (1 - EpsChar(2)) / (1 - EpsChar(1) * EpsChar(2));
4153 88448 : }
4154 :
4155 : //****************************************************************************
4156 :
4157 16427 : void BetweenGlassForcedFlow(EnergyPlusData &state,
4158 : int const SurfNum, // Surface number
4159 : int const iter, // Iteration number for glass heat balance calculation
4160 : Real64 &VGap, // Air velocity in airflow gap (m/s)
4161 : Real64 &TGapNew, // Current-iteration average air temp in airflow gap (K)
4162 : Real64 &TGapOutlet, // Temperature of air leaving glass-shade/blind gap at top for upward
4163 : Real64 &hcv, // Convection coefficient from gap glass faces to gap air (W/m2-K)
4164 : Real64 &QConvGap // Convective heat gain from air flow gap (W)
4165 : )
4166 : {
4167 :
4168 : // SUBROUTINE INFORMATION:
4169 : // AUTHOR F. Winkelmann
4170 : // DATE WRITTEN February 2003
4171 : // MODIFIED na
4172 : // RE-ENGINEERED na
4173 :
4174 : // PURPOSE OF THIS SUBROUTINE:
4175 : // Called by SolveForWindowTemperatures for "airflow windows",i.e., windows
4176 : // with forced airflow in one of the gaps between layers of glass. Based on
4177 : // the velocity of airflow through gap, finds effective temperature of gap air,
4178 : // convective heat transfer coefficient from glass to gap air,
4179 : // the gap outlet temperature, and the outlet convective heat flow.
4180 :
4181 : // Called only for double and triple glazing. For triple glazing the airflow
4182 : // is assumed to be between the inner two layers of glass (glass layers 2 and 3).
4183 :
4184 : // METHODOLOGY EMPLOYED:
4185 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
4186 : // Detailed Calculations"
4187 :
4188 : // Using/Aliasing
4189 : using ScheduleManager::GetCurrentScheduleValue;
4190 :
4191 : // Locals
4192 : // SUBROUTINE ARGUMENT DEFINITIONS:
4193 : // air flow or bottom for downward air flow (K)
4194 :
4195 : int ConstrNum; // Construction number of surface
4196 : int NGlass; // Number of glass layers in construction
4197 : int GapNum; // Number of airflow gap
4198 : Real64 TGapInlet; // Temperature of air entering glass-shade/blind gap at bottom for upward
4199 : // air flow or top for downward air flow (K)
4200 : Real64 TGlassFace1; // Temperature of left-hand glass surface facing airflow gap (K)
4201 : Real64 TGlassFace2; // Temperature of right-hand glass surface facing airflow gap (K)
4202 : Real64 hGapStill; // Still-air gap conduction/convection coeff (W/m2-K)
4203 : Real64 TGapOld; // Previous-iteration average air temp in airflow gap (K)
4204 : Real64 GapHeight; // Vertical length of airflow gap (m)
4205 : Real64 GapDepth; // Thickness of airflow gap (m)
4206 : Real64 RhoAir; // Density of airflow gap air at a temperature of TGapOld (kg/m3)
4207 : Real64 AGap; // Cross sectional area of airflow gap (m2); for vertical window, this
4208 : // is in horizontal plane normal to window.
4209 : Real64 GapHeightChar; // Characteristic height of the airflow gap air temperature profile (m)
4210 : Real64 TAve; // Average of TGlassFace1 and TGlassFace2 (K)
4211 : // REAL(r64) :: AirProps(8) ! Air properties
4212 : Real64 con; // Gap conductivity and derivative
4213 : Real64 gr; // Gap air Grashof number
4214 : Real64 pr; // Gap air Prandtl number
4215 : Real64 nu; // Gap air Nusselt number
4216 :
4217 : // Air properties
4218 : // Dens dDens/dT Con dCon/dT Vis dVis/dT Prandtl dPrandtl/dT
4219 : // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72, 1.8d-3 /
4220 :
4221 16427 : auto &wm = state.dataWindowManager;
4222 :
4223 16427 : ConstrNum = state.dataSurface->Surface(SurfNum).Construction;
4224 16427 : NGlass = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
4225 16427 : TGlassFace1 = wm->thetas[2 * NGlass - 3];
4226 16427 : TGlassFace2 = wm->thetas[2 * NGlass - 2];
4227 16427 : GapNum = NGlass - 1;
4228 16427 : TAve = 0.5 * (TGlassFace1 + TGlassFace2);
4229 :
4230 16427 : if (state.dataSurface->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
4231 16427 : TGapInlet = wm->tin; // Source is inside air
4232 : } else {
4233 0 : TGapInlet = wm->tout; // Source is outside air
4234 : }
4235 :
4236 16427 : if (iter == 0) {
4237 8064 : TGapOld = 0.5 * (TAve + TGapInlet);
4238 : } else {
4239 8363 : TGapOld = TGapNew;
4240 : }
4241 :
4242 : // Conductance of gap assuming it is sealed
4243 16427 : WindowGasConductance(state, TGlassFace1, TGlassFace2, GapNum, con, pr, gr);
4244 16427 : NusseltNumber(state, SurfNum, TGlassFace1, TGlassFace2, GapNum, gr, pr, nu);
4245 16427 : hGapStill = con / wm->gaps[GapNum - 1].width * nu;
4246 16427 : GapHeight = state.dataSurface->Surface(SurfNum).Height;
4247 16427 : GapDepth = state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(2 * NGlass - 2))->Thickness;
4248 16427 : AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
4249 16427 : VGap = state.dataSurface->SurfWinAirflowThisTS(SurfNum) / GapDepth;
4250 16427 : hcv = 2.0 * hGapStill + 4.0 * VGap;
4251 16427 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapOld - Constant::Kelvin);
4252 16427 : GapHeightChar = RhoAir * 1008.0 * GapDepth * VGap / (2.0 * hcv);
4253 : // The following avoids divide by zero and exponential underflow
4254 16427 : if (GapHeightChar == 0.0) {
4255 0 : TGapOutlet = TAve;
4256 16427 : } else if ((GapHeight / GapHeightChar) > 15.0) {
4257 0 : TGapOutlet = TAve;
4258 : } else {
4259 16427 : TGapOutlet = TAve - (TAve - TGapInlet) * std::exp(-GapHeight / GapHeightChar);
4260 : }
4261 16427 : TGapNew = TAve - (GapHeightChar / GapHeight) * (TGapOutlet - TGapInlet);
4262 : // Convective heat flow from gap [W]
4263 16427 : RhoAir = wm->AirProps[0] + wm->AirProps[1] * (TGapNew - Constant::Kelvin);
4264 16427 : QConvGap = RhoAir * AGap * VGap * 1008.0 * (TGapOutlet - TGapInlet);
4265 16427 : } // BetweenGlassForcedFlow()
4266 :
4267 : //****************************************************************************
4268 :
4269 19998 : void BetweenGlassShadeForcedFlow(EnergyPlusData &state,
4270 : int const SurfNum, // Surface number
4271 : int const iter, // Iteration number for glass heat balance calculation
4272 : Real64 &VGap, // Air velocity in each gap (m/s)
4273 : Array1A<Real64> TGapNew, // Current-iteration average gas temp in gaps (K)
4274 : Real64 &TGapOutletAve, // Average of TGapOutlet(1) and TGapOutlet(2) (K)
4275 : Array1A<Real64> hcv, // Convection coefficient from gap glass or shade to gap gas (W/m2-K)
4276 : Real64 &QConvTot // Sum of convective heat flow from gaps (W)
4277 : )
4278 : {
4279 :
4280 : // SUBROUTINE INFORMATION:
4281 : // AUTHOR F. Winkelmann
4282 : // DATE WRITTEN February 2003
4283 : // MODIFIED na
4284 : // RE-ENGINEERED na
4285 :
4286 : // PURPOSE OF THIS SUBROUTINE:
4287 : // Called by SolveForWindowTemperatures for airflow windows with a
4288 : // between-glass shade or blind over which fan-forced air flows.
4289 : // Based on the air flow velocity (which is assumed to be the same in the
4290 : // gaps on either side of the shade/blind), finds, for each gap: the average
4291 : // air temperature, the shade/blind or glass surface to air convective heat
4292 : // transfer coefficient, the gap outlet temperature, and the outlet convective heat flow.
4293 :
4294 : // Called only for double and triple glazing. For triple glazing the airflow
4295 : // is assumed to be between the inner two layers of glass (glass layers 2 and 3),
4296 : // between which the shade/blind is located.
4297 :
4298 : // METHODOLOGY EMPLOYED:
4299 : // Based on ISO/DIS 15099, "Thermal Performance of Windows, Doors and Shading Devices --
4300 : // Detailed Calculations," 1/12/2000, Chapter 7, "Shading Devices."
4301 :
4302 : // Argument array dimensioning
4303 19998 : TGapNew.dim(2);
4304 19998 : hcv.dim(2);
4305 :
4306 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4307 : int ConstrNumSh; // Shaded construction number
4308 : int MatNumSh; // Material number of shade/blind layer
4309 : // In the following, "gaps" refer to the gaps on either side of the shade/blind
4310 19998 : Array1D<Real64> TGlassFace(2); // Temperature of glass surfaces facing gaps (K)
4311 19998 : Array1D<Real64> TShadeFace(2); // Temperature of shade surfaces facing gaps (K)
4312 19998 : Array1D<Real64> hGapStill(2); // Still-air conduction/convection coeffs for the gaps (W/m2-K)
4313 19998 : Array1D<Real64> TGapOld(2); // Previous-iteration average gas temp in gaps (K)
4314 : Real64 GapHeight; // Vertical length of glass-shade/blind gap (m)
4315 : Real64 GapDepth; // Distance from shade/blind to glass; assumed same for both gaps (m)
4316 19998 : Array1D<Real64> RhoAir(2); // Density of gap air (kg/m3)
4317 : Real64 AGap; // Cross sectional area of each gap (m2); for vertical window, this
4318 : // is in horizontal plane normal to window.
4319 : Real64 TGapInlet; // Gap inlet air temperature (K)
4320 19998 : Array1D<Real64> TGapOutlet(2); // Gap outlet air temperature (K)
4321 19998 : Array1D<Real64> QConvGap(2); // Convective heat flow from each gap (W)
4322 19998 : Array1D<Real64> GapHeightChar(2); // Characteristic height of the gap air temperature profile (m)
4323 19998 : Array1D<Real64> TAve(2); // Average of TGlass and TShade for the gaps (K)
4324 : Real64 con; // Gap air conductivity and derivative
4325 : Real64 gr; // Gap air Grashof number
4326 : Real64 pr; // Gap air Prandtl number
4327 : Real64 nu; // Gap air Nusselt number
4328 : WinShadingType ShadeFlag; // Shading flag
4329 : int IGapInc; // Gap increment; =0, double glass, =1, triple glass
4330 : // REAL(r64) :: AirProps(8) ! Air properties
4331 :
4332 19998 : auto &wm = state.dataWindowManager;
4333 :
4334 : // Air properties
4335 : // Dens dDens/dT Con dCon/dT Vis dVis/dT Prandtl dPrandtl/dT
4336 : // DATA AirProps / 1.29, -0.4d-2, 2.41d-2, 7.6d-5, 1.73d-5, 1.0d-7, 0.72, 1.8d-3 /
4337 :
4338 19998 : ConstrNumSh = state.dataSurface->Surface(SurfNum).activeShadedConstruction;
4339 19998 : ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
4340 :
4341 19998 : if (state.dataConstruction->Construct(ConstrNumSh).TotGlassLayers == 2) { // Double glazing
4342 9981 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(3);
4343 9981 : IGapInc = 0;
4344 29943 : for (int IGap = 1; IGap <= 2; ++IGap) {
4345 19962 : TGlassFace(IGap) = wm->thetas[IGap];
4346 19962 : TShadeFace(IGap) = wm->thetas[IGap + 3];
4347 : }
4348 : } else { // Triple glazing
4349 10017 : MatNumSh = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(5);
4350 10017 : IGapInc = 1;
4351 30051 : for (int IGap = 1; IGap <= 2; ++IGap) {
4352 20034 : TGlassFace(IGap) = wm->thetas[IGap + 2];
4353 20034 : TShadeFace(IGap) = wm->thetas[IGap + 5];
4354 : }
4355 : }
4356 :
4357 19998 : if (state.dataSurface->SurfWinAirflowSource(SurfNum) == WindowAirFlowSource::Indoor) {
4358 19998 : TGapInlet = wm->tin;
4359 : } else {
4360 0 : TGapInlet = wm->tout;
4361 : }
4362 :
4363 19998 : GapHeight = state.dataSurface->Surface(SurfNum).Height;
4364 19998 : GapDepth = wm->gaps[IGapInc].width;
4365 19998 : AGap = GapDepth * state.dataSurface->Surface(SurfNum).Width;
4366 : // Factor of 2 below assumes gaps on either side of shade/blind have same depth
4367 19998 : VGap = state.dataSurface->SurfWinAirflowThisTS(SurfNum) / (2.0 * GapDepth);
4368 :
4369 59994 : for (int IGap = 1; IGap <= 2; ++IGap) {
4370 39996 : TAve(IGap) = 0.5 * (TGlassFace(IGap) + TShadeFace(IGap));
4371 39996 : if (iter == 0) {
4372 16128 : TGapOld(IGap) = TAve(IGap);
4373 : } else {
4374 23868 : TGapOld(IGap) = TGapNew(IGap);
4375 : }
4376 : // Conductance of gaps on either side of shade/blind assuming gaps are sealed
4377 39996 : WindowGasConductance(state, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, con, pr, gr);
4378 39996 : NusseltNumber(state, SurfNum, TGlassFace(IGap), TShadeFace(IGap), IGap + IGapInc, gr, pr, nu);
4379 39996 : hGapStill(IGap) = con / wm->gaps[IGap + IGapInc - 1].width * nu;
4380 : // Shade/blind or glass surface to air convection coefficient
4381 39996 : hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
4382 39996 : RhoAir(IGap) = wm->AirProps[0] + wm->AirProps[1] * (TGapOld(IGap) - Constant::Kelvin);
4383 39996 : hcv(IGap) = 2.0 * hGapStill(IGap) + 4.0 * VGap;
4384 39996 : GapHeightChar(IGap) = RhoAir(IGap) * 1008.0 * GapDepth * VGap / (2.0 * hcv(IGap));
4385 : // The following avoids divide by zero and exponential underflow
4386 39996 : if (GapHeightChar(IGap) == 0.0) {
4387 0 : TGapOutlet(IGap) = TAve(IGap);
4388 39996 : } else if ((GapHeight / GapHeightChar(IGap)) > 15.0) {
4389 0 : TGapOutlet(IGap) = TAve(IGap);
4390 : } else {
4391 39996 : TGapOutlet(IGap) = TAve(IGap) - (TAve(IGap) - TGapInlet) * std::exp(-GapHeight / GapHeightChar(IGap));
4392 : }
4393 39996 : TGapNew(IGap) = TAve(IGap) - (GapHeightChar(IGap) / GapHeight) * (TGapOutlet(IGap) - TGapInlet);
4394 : // Convective heat flow from gap [W]
4395 39996 : RhoAir(IGap) = wm->AirProps[0] + wm->AirProps[1] * (TGapNew(IGap) - Constant::Kelvin);
4396 39996 : QConvGap(IGap) = RhoAir(IGap) * AGap * VGap * 1008.0 * (TGapOutlet(IGap) - TGapInlet);
4397 : }
4398 :
4399 19998 : QConvTot = QConvGap(1) + QConvGap(2);
4400 19998 : TGapOutletAve = 0.5 * (TGapOutlet(1) + TGapOutlet(2));
4401 19998 : } // BetweenGlassShadeForcedFlow()
4402 :
4403 : //****************************************************************************
4404 :
4405 44766113 : void LUdecomposition(EnergyPlusData &state,
4406 : Array2<Real64> &ajac, // As input: matrix to be decomposed;
4407 : int const n, // Dimension of matrix
4408 : Array1D_int &indx, // Vector of row permutations
4409 : int &d // +1 if even number of row interchange is even, -1
4410 : )
4411 : {
4412 :
4413 : // SUBROUTINE INFORMATION:
4414 : // AUTHOR F. Winkelmann, adapted from Numerical Recipes
4415 : // DATE WRITTEN February 2000
4416 : // MODIFIED na
4417 : // RE-ENGINEERED na
4418 :
4419 : // PURPOSE OF THIS SUBROUTINE:
4420 : // Performs LU decomposition of a matrix.
4421 :
4422 : // SUBROUTINE ARGUMENT DEFINITIONS:
4423 : // as output: decomposed matrix
4424 : // if odd
4425 :
4426 : int imax; // Temporary variable
4427 : // as output: decomposed matrix
4428 :
4429 : Real64 aamax; // Absolute value of largest element of matrix
4430 :
4431 44766113 : assert(n <= 10); // vv sizing
4432 44766113 : std::array<Real64, 10> vv = {0.0}; // Stores the implicit scaling of each row
4433 :
4434 44766113 : d = 1;
4435 164437517 : for (int i = 1; i <= n; ++i) {
4436 119671404 : Real64 aamax = 0.0;
4437 486029524 : for (int j = 1; j <= n; ++j) {
4438 366358120 : if (std::abs(ajac(j, i)) > aamax) aamax = std::abs(ajac(j, i));
4439 : }
4440 119671404 : if (aamax == 0.0) ShowFatalError(state, "Singular matrix in LUdecomposition, window calculations");
4441 119671404 : vv[i - 1] = 1.0 / aamax;
4442 : }
4443 164437517 : for (int j = 1; j <= n; ++j) {
4444 243014762 : for (int i = 1; i <= j - 1; ++i) {
4445 123343358 : Real64 sum = ajac(j, i);
4446 194593606 : for (int k = 1; k <= i - 1; ++k) {
4447 71250248 : sum -= ajac(k, i) * ajac(j, k);
4448 : }
4449 123343358 : ajac(j, i) = sum;
4450 : }
4451 119671404 : aamax = 0.0;
4452 362686166 : for (int i = j; i <= n; ++i) {
4453 243014762 : Real64 sum = ajac(j, i);
4454 437608368 : for (int k = 1; k <= j - 1; ++k) {
4455 194593606 : sum -= ajac(k, i) * ajac(j, k);
4456 : }
4457 243014762 : ajac(j, i) = sum;
4458 243014762 : Real64 dum = vv[i - 1] * std::abs(sum);
4459 243014762 : if (dum >= aamax) {
4460 120100354 : imax = i;
4461 120100354 : aamax = dum;
4462 : }
4463 : }
4464 119671404 : if (j != imax) {
4465 2490498 : for (int k = 1; k <= n; ++k) {
4466 2061548 : Real64 dum = ajac(k, imax);
4467 2061548 : ajac(k, imax) = ajac(k, j);
4468 2061548 : ajac(k, j) = dum;
4469 : }
4470 428950 : d = -d;
4471 428950 : vv[imax - 1] = vv[j - 1];
4472 : }
4473 119671404 : indx(j) = imax;
4474 119671404 : if (ajac(j, j) == 0.0) ajac(j, j) = Constant::rTinyValue;
4475 119671404 : if (j != n) {
4476 74905291 : Real64 dum = 1.0 / ajac(j, j);
4477 198248649 : for (int i = j + 1; i <= n; ++i) {
4478 123343358 : ajac(j, i) *= dum;
4479 : }
4480 : }
4481 : }
4482 44766113 : } // LUdecomposition()
4483 :
4484 : //**************************************************************************
4485 :
4486 45020246 : void LUsolution(EnergyPlusData &state,
4487 : Array2<Real64> const &a, // Matrix and vector in a.x = b;
4488 : int const n, // Dimension of a and b
4489 : Array1D_int const &indx, // Vector of row permutations
4490 : Array1D<Real64> &b // Matrix and vector in a.x = b;
4491 : )
4492 : {
4493 :
4494 : // SUBROUTINE INFORMATION:
4495 : // AUTHOR F. Winkelmann, adapted from Numerical Recipes
4496 : // DATE WRITTEN February 2000
4497 : // MODIFIED na
4498 : // RE-ENGINEERED na
4499 :
4500 : // PURPOSE OF THIS SUBROUTINE:
4501 : // Solves set of linear equations a.x = b
4502 :
4503 : // Locals
4504 : // SUBROUTINE ARGUMENT DEFINITIONS:
4505 : // b is also output as the solution, x
4506 : // b is also output as the solution, x
4507 :
4508 : int ii; // Intermediate variables
4509 : int ll;
4510 : Real64 sum; // Summation variable
4511 :
4512 45020246 : ii = 0;
4513 165708182 : for (int i = 1; i <= n; ++i) {
4514 120687936 : ll = indx(i);
4515 120687936 : sum = b(ll);
4516 120687936 : b(ll) = b(i);
4517 120687936 : if (ii != 0) {
4518 198841626 : for (int j = ii; j <= i - 1; ++j) {
4519 123682202 : sum -= a(j, i) * b(j);
4520 : }
4521 45528512 : } else if (sum != 0.0) {
4522 45020246 : ii = i;
4523 : }
4524 120687936 : b(i) = sum;
4525 : }
4526 165708182 : for (int i = n; i >= 1; --i) {
4527 120687936 : sum = b(i);
4528 245556092 : for (int j = i + 1; j <= n; ++j) {
4529 124868156 : sum -= a(j, i) * b(j);
4530 : }
4531 120687936 : b(i) = sum / a(i, i);
4532 : }
4533 45020246 : } // LUsolution()
4534 :
4535 : //******************************************************************************
4536 :
4537 15109751 : void WindowGasConductance(EnergyPlusData &state,
4538 : Real64 const tleft, // Temperature of gap surface closest to outside (K)
4539 : Real64 const tright, // Temperature of gap surface closest to zone (K)
4540 : int const IGap, // Gap number
4541 : Real64 &con, // Gap gas conductance (W/m2-K)
4542 : Real64 &pr, // Gap gas Prandtl number
4543 : Real64 &gr // Gap gas Grashof number
4544 : )
4545 : {
4546 :
4547 : // SUBROUTINE INFORMATION:
4548 : // AUTHOR Adapted by Fred Winkelmann from Window5 subroutine gasses
4549 : // DATE WRITTEN September 2001
4550 : // MODIFIED na
4551 : // RE-ENGINEERED na
4552 :
4553 : // PURPOSE OF THIS SUBROUTINE:
4554 : // Find the coefficient of convective/conductive heat transfer in the gas-filled gap
4555 : // between isothermal solid layers. The gap may be filled with a single gas or a gas mixture.
4556 :
4557 : // METHODOLOGY EMPLOYED:
4558 : // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
4559 : // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
4560 : // The equation numbers below correspond to those in the standard.
4561 :
4562 : // REFERENCES:
4563 : // Window5 source code; ISO 15099
4564 :
4565 15109751 : constexpr Real64 pres(1.0e5); // Gap gas pressure (Pa)
4566 15109751 : constexpr Real64 gaslaw(8314.51); // Molar gas constant (J/kMol-K)
4567 15109751 : Real64 const two_sqrt_2(2.0 * std::sqrt(2.0));
4568 :
4569 : int NMix; // Number of gases in a mixture
4570 : Real64 molmix; // Molecular weight of mixture
4571 :
4572 15109751 : auto &wm = state.dataWindowManager;
4573 :
4574 : Real64 kpmix; // Monotonic thermal conductivity of mixture
4575 : Real64 kdpmix;
4576 : Real64 kmix; // For accumulating conductance of gas mixture
4577 : Real64 mumix; // For accumulating viscosity of gas mixture
4578 15109751 : Real64 visc(0.0); // Dynamic viscosity of mixture at tmean (g/m-s)
4579 15109751 : Real64 cp(0.0); // Specific heat of mixture at tmean (J/m3-K)
4580 15109751 : Real64 dens(0.0); // Density of mixture at tmean (kg/m3)
4581 : Real64 cpmixm; // Gives cp when divided by molmix
4582 : Real64 phimup; // Numerator factor
4583 : Real64 downer; // Denominator factor
4584 : Real64 psiup; // Numerator factor
4585 : Real64 psiterm; // Factor
4586 : Real64 phikup; // Numerator factor
4587 : Real64 rhomix; // Density of gas mixture (kg/m3)
4588 :
4589 15109751 : std::array<Real64, 10> mukpdwn = {0.0}; // Denominator term
4590 15109751 : std::array<Real64, 10> kpdown = {0.0}; // Denominator terms
4591 15109751 : std::array<Real64, 10> kdpdown = {0.0};
4592 : // Conductivity term accounting for additional energy moved by the diffusional transport of internal energy in polyatomic gases.
4593 15109751 : std::array<Real64, 10> kdblprm = {0.0};
4594 15109751 : std::array<Real64, 10> frct = {0.0}; // Fraction of each gas in a mixture
4595 15109751 : std::array<Real64, 10> kprime = {0.0}; // Monotonic thermal conductivity
4596 :
4597 15109751 : std::array<Real64, 10> fvis = {0.0}; // Viscosity of each gas in a mixture (g/m-s)
4598 15109751 : std::array<Real64, 10> fcon = {0.0}; // Conductance of each gas in a mixture (W/m2-K)
4599 15109751 : std::array<Real64, 10> fdens = {0.0}; // Density of each gas in a mixture (kg/m3)
4600 15109751 : std::array<Real64, 10> fcp = {0.0}; // Specific heat of each gas in a mixture (J/m3-K)
4601 :
4602 : // Autodesk:Logic Either assert NMix>0 or handle NMix<=0 in logic so that con and locals guar. initialized before use
4603 15109751 : NMix = wm->gaps[IGap - 1].numGases;
4604 :
4605 30346895 : for (int IMix = 0; IMix < NMix; ++IMix) {
4606 15237144 : frct[IMix] = wm->gaps[IGap - 1].gasFracts[IMix];
4607 : }
4608 :
4609 15109751 : Real64 const tmean(0.5 * (tleft + tright)); // Average gap gas temperature (K)
4610 15109751 : Real64 const tmean_2(pow_2(tmean));
4611 :
4612 15109751 : auto const &wmgas0 = wm->gaps[IGap - 1].gases[0];
4613 15109751 : fcon[0] = wmgas0.con.c0 + wmgas0.con.c1 * tmean + wmgas0.con.c2 * tmean_2;
4614 15109751 : fvis[0] = wmgas0.vis.c0 + wmgas0.vis.c1 * tmean + wmgas0.vis.c2 * tmean_2;
4615 15109751 : fcp[0] = wmgas0.cp.c0 + wmgas0.cp.c1 * tmean + wmgas0.cp.c2 * tmean_2;
4616 15109751 : fdens[0] = pres * wmgas0.wght / (gaslaw * tmean); // Density using ideal gas law:
4617 : // rho=(presure*molecweight)/(gasconst*tmean)
4618 :
4619 15109751 : if (NMix == 1) { // Single gas
4620 14982358 : con = fcon[0];
4621 14982358 : visc = fvis[0];
4622 14982358 : cp = fcp[0];
4623 14982358 : dens = fdens[0];
4624 127393 : } else if (NMix > 1) { // Multiple gases; calculate mixture properties
4625 127393 : molmix = frct[0] * wmgas0.wght; // initialize eq. 56
4626 127393 : cpmixm = molmix * fcp[0]; // initialize eq. 58
4627 127393 : kprime[0] = 3.75 * (gaslaw / wmgas0.wght) * fvis[0]; // eq. 67
4628 127393 : kdblprm[0] = fcon[0] - kprime[0]; // eq. 67
4629 :
4630 : // Initialize summations for eqns 60-66
4631 127393 : mumix = 0.0;
4632 127393 : kpmix = 0.0;
4633 127393 : kdpmix = 0.0;
4634 127393 : mukpdwn[0] = 1.0;
4635 127393 : kpdown[0] = 1.0;
4636 127393 : kdpdown[0] = 1.0;
4637 :
4638 : // Calculate properties of mixture constituents
4639 254786 : for (int i = 2; i <= NMix; ++i) {
4640 127393 : auto const &wmgas = wm->gaps[IGap - 1].gases[i - 1];
4641 :
4642 127393 : fcon[i - 1] = wmgas.con.c0 + wmgas.con.c1 * tmean + wmgas.con.c2 * tmean_2;
4643 127393 : fvis[i - 1] = wmgas.vis.c0 + wmgas.vis.c1 * tmean + wmgas.vis.c2 * tmean_2;
4644 127393 : fcp[i - 1] = wmgas.cp.c0 + wmgas.cp.c1 * tmean + wmgas.cp.c2 * tmean_2;
4645 127393 : fdens[i - 1] = pres * wmgas.wght / (gaslaw * tmean);
4646 127393 : molmix += frct[i - 1] * wmgas.wght; // eq. 56
4647 127393 : cpmixm += frct[i - 1] * fcp[i - 1] * wmgas.wght; // eq. 58-59
4648 127393 : kprime[i - 1] = 3.75 * gaslaw / wmgas.wght * fvis[i - 1]; // eq. 67
4649 127393 : kdblprm[i - 1] = fcon[i - 1] - kprime[i - 1]; // eq. 68
4650 127393 : mukpdwn[i - 1] = 1.0; // initialize denomonator of eq. 60
4651 127393 : kpdown[i - 1] = 1.0; // initialize denomonator of eq. 63
4652 127393 : kdpdown[i - 1] = 1.0; // initialize denomonator of eq. 65
4653 : }
4654 :
4655 382179 : for (int i = 1; i <= NMix; ++i) {
4656 254786 : auto const &wmgasI = wm->gaps[IGap - 1].gases[i - 1];
4657 :
4658 764358 : for (int j = 1; j <= NMix; ++j) {
4659 509572 : auto const &wmgasJ = wm->gaps[IGap - 1].gases[j - 1];
4660 :
4661 : // numerator of equation 61
4662 509572 : phimup = pow_2(1.0 + std::sqrt(fvis[i - 1] / fvis[j - 1]) * root_4(wmgasJ.wght / wmgasI.wght));
4663 : // denomonator of eq. 61, 64 and 66
4664 509572 : downer = two_sqrt_2 * std::sqrt(1 + (wmgasI.wght / wmgasJ.wght));
4665 : // calculate the denominator of eq. 60
4666 509572 : if (i != j) mukpdwn[i - 1] += phimup / downer * frct[j - 1] / frct[i - 1];
4667 : // numerator of eq. 64; psiterm is the multiplied term in backets
4668 509572 : psiup = pow_2(1.0 + std::sqrt(kprime[i - 1] / kprime[j - 1]) * root_4(wmgasI.wght / wmgasJ.wght));
4669 509572 : psiterm = 1.0 + 2.41 * (wmgasI.wght - wmgasJ.wght) * (wmgasI.wght - 0.142 * wmgasJ.wght) / pow_2(wmgasI.wght + wmgasJ.wght);
4670 : // using the common denominator, downer, calculate the denominator for eq. 63
4671 509572 : if (i != j) kpdown[i - 1] += psiup * (psiterm / downer) * (frct[j - 1] / frct[i - 1]);
4672 : // calculate the numerator of eq. 66
4673 509572 : phikup = pow_2(1.0 + std::sqrt(kprime[i - 1] / kprime[j - 1]) * root_4(wmgasI.wght / wmgasJ.wght));
4674 : // using the common denominator, downer, calculate the denomonator for eq. 65
4675 509572 : if (i != j) kdpdown[i - 1] += (phikup / downer) * (frct[j - 1] / frct[i - 1]);
4676 : }
4677 254786 : mumix += fvis[i - 1] / mukpdwn[i - 1]; // eq. 60
4678 254786 : kpmix += kprime[i - 1] / kpdown[i - 1]; // eq. 63
4679 254786 : kdpmix += kdblprm[i - 1] / kdpdown[i - 1]; // eq. 65
4680 : }
4681 :
4682 : // Calculate the density of the mixture assuming an ideal gas
4683 127393 : rhomix = pres * molmix / (gaslaw * tmean); // eq. 57
4684 127393 : kmix = kpmix + kdpmix; // eq. 68-a
4685 :
4686 : // Final mixture properties
4687 127393 : visc = mumix;
4688 127393 : con = kmix;
4689 127393 : dens = rhomix;
4690 127393 : cp = cpmixm / molmix;
4691 :
4692 : } else {
4693 0 : assert(false);
4694 : } // End of check if single or multiple gases in gap
4695 :
4696 15109751 : pr = cp * visc / con;
4697 15109751 : gr = 9.807 * pow_3(wm->gaps[IGap - 1].width) * std::abs(tleft - tright) * pow_2(dens) / (tmean * pow_2(visc));
4698 15109751 : } // WindowGasConductance()
4699 :
4700 : //******************************************************************************
4701 :
4702 265344 : void WindowGasPropertiesAtTemp(EnergyPlusData &state,
4703 : Real64 const tmean, // Temperature of gas in gap (K)
4704 : int const IGap, // Gap number
4705 : Real64 &dens, // Gap gas density at tmean (kg/m3)
4706 : Real64 &visc // Gap gas dynamic viscosity at tmean (g/m-s)
4707 : )
4708 : {
4709 :
4710 : // SUBROUTINE INFORMATION:
4711 : // AUTHOR F. Winkelmann
4712 : // DATE WRITTEN December 2002
4713 : // MODIFIED na
4714 : // RE-ENGINEERED na
4715 :
4716 : // PURPOSE OF THIS SUBROUTINE:
4717 : // Finds the density and viscosity of the gas in a gap at a particular temperature.
4718 : // The gap may be filled with a single gas or a gas mixture.
4719 : // Based on Subroutine WindowGasConductance.
4720 :
4721 : // METHODOLOGY EMPLOYED:
4722 : // See Subr. WindowGasConductance
4723 :
4724 : // REFERENCES:
4725 : // See Subr. WindowGasConductance
4726 :
4727 265344 : Real64 constexpr pres(1.0e5); // Gap gas pressure (Pa)
4728 265344 : Real64 constexpr gaslaw(8314.51); // Molar gas constant (J/kMol-K)
4729 265344 : Real64 const two_sqrt_2(2.0 * std::sqrt(2.0));
4730 :
4731 : int NMix; // Number of gases in a mixture
4732 : Real64 molmix; // Molecular weight of mixture
4733 265344 : Array1D<Real64> mukpdwn(10); // Denominator term
4734 : Real64 mumix; // For accumulating viscosity of gas mixture
4735 : Real64 phimup; // Numerator factor
4736 : Real64 downer; // Denominator factor
4737 : Real64 rhomix; // Density of gas mixture (kg/m3)
4738 265344 : Array1D<Real64> frct(10); // Fraction of each gas in a mixture
4739 265344 : Array1D<Real64> fvis(10); // Viscosity of each gas in a mixture (g/m-s)
4740 265344 : Array1D<Real64> fdens(10); // Density of each gas in a mixture (kg/m3)
4741 :
4742 265344 : auto &wm = state.dataWindowManager;
4743 :
4744 265344 : NMix = wm->gaps[IGap - 1].numGases;
4745 :
4746 530688 : for (int IMix = 1; IMix <= NMix; ++IMix) {
4747 265344 : frct(IMix) = wm->gaps[IGap - 1].gasFracts[IMix - 1];
4748 : }
4749 :
4750 265344 : Real64 const tmean_2(pow_2(tmean));
4751 265344 : auto const &wmgas0 = wm->gaps[IGap - 1].gases[0];
4752 265344 : fvis(1) = wmgas0.vis.c0 + wmgas0.vis.c1 * tmean + wmgas0.vis.c2 * tmean_2;
4753 265344 : fdens(1) = pres * wmgas0.wght / (gaslaw * tmean); // Density using ideal gas law:
4754 : // rho=(presure*molecweight)/(gasconst*tmean)
4755 265344 : if (NMix == 1) { // Single gas
4756 265344 : visc = fvis(1);
4757 265344 : dens = fdens(1);
4758 : } else { // Multiple gases; calculate mixture properties
4759 0 : molmix = frct(1) * wmgas0.wght; // initialize eq. 56
4760 :
4761 : // Initialize summations for eqns 60-66
4762 0 : mumix = 0.0;
4763 0 : mukpdwn(1) = 1.0;
4764 :
4765 : // Calculate properties of mixture constituents
4766 0 : for (int i = 2; i <= NMix; ++i) {
4767 0 : auto const &wmgas = wm->gaps[IGap - 1].gases[i - 1];
4768 0 : fvis(i) = wmgas.vis.c0 + wmgas.vis.c1 * tmean + wmgas.vis.c2 * tmean_2;
4769 0 : fdens(i) = pres * wmgas.wght / (gaslaw * tmean);
4770 0 : molmix += frct(i) * wmgas.wght; // eq. 56
4771 0 : mukpdwn(i) = 1.0; // initialize denomonator of eq. 60
4772 : }
4773 :
4774 0 : for (int i = 1; i <= NMix; ++i) {
4775 0 : auto const &wmgasI = wm->gaps[IGap - 1].gases[i - 1];
4776 0 : for (int j = 1; j <= NMix; ++j) {
4777 0 : auto const &wmgasJ = wm->gaps[IGap - 1].gases[j - 1];
4778 : // numerator of equation 61
4779 0 : phimup = pow_2(1.0 + std::sqrt(fvis(i) / fvis(j)) * root_4(wmgasJ.wght / wmgasI.wght));
4780 : // denomonator of eq. 61, 64 and 66
4781 0 : downer = two_sqrt_2 * std::sqrt(1 + (wmgasI.wght / wmgasJ.wght));
4782 : // calculate the denominator of eq. 60
4783 0 : if (i != j) mukpdwn(i) += phimup / downer * frct(j) / frct(i);
4784 : }
4785 0 : mumix += fvis(i) / mukpdwn(i); // eq. 60
4786 : }
4787 :
4788 : // Calculate the density of the mixture assuming an ideal gas
4789 0 : rhomix = pres * molmix / (gaslaw * tmean); // eq. 57
4790 :
4791 : // Final mixture properties
4792 0 : visc = mumix;
4793 0 : dens = rhomix;
4794 :
4795 : } // End of check if single or multiple gases in gap
4796 265344 : } // WindowGasPropertiesAtTemp()
4797 :
4798 : //********************************************************************************
4799 :
4800 23964637 : void StartingWindowTemps(EnergyPlusData &state,
4801 : int const SurfNum, // Surface number
4802 : Array1A<Real64> AbsRadShade // Short-wave radiation absorbed by shade/blind faces
4803 : )
4804 : {
4805 :
4806 : // SUBROUTINE INFORMATION:
4807 : // AUTHOR F. Winkelmann
4808 : // DATE WRITTEN January 2000
4809 : // MODIFIED March 2003, FW: add rough calc of increase above ambient of
4810 : // initial shade/blind temperature when shade/blind deployed
4811 : // after having been off.
4812 : // Jan 2004, FW: take into account whether storm window was added
4813 : // or removed in the current time step.
4814 : // RE-ENGINEERED na
4815 :
4816 : // PURPOSE OF THIS SUBROUTINE:
4817 : // Initializes face temperature distribution prior to iteration
4818 :
4819 : // Argument array dimensioning
4820 23964637 : AbsRadShade.dim(2);
4821 :
4822 23964637 : constexpr Real64 hrad(5.3); // Typical radiative conductance (W/m2-K)
4823 23964637 : constexpr Real64 resgap(0.21); // Typical gap resistance (m2-K/W)
4824 :
4825 : WinShadingType ShadeFlag; // Shading flag
4826 23964637 : Array1D<Real64> rguess(11); // Combined radiative/convective resistance (m2-K/W) of
4827 : // inside or outside air film, or gap
4828 : Real64 restot; // Total window resistance including outside
4829 : // and inside air films (m2-K/W)
4830 : Real64 temdiff; // Inside/outside air temperature difference (K)
4831 : Real64 ressum; // Resistance sum (m2-K/W)
4832 : int StormWinFlagPrevDay; // Previous time step value (day) of storm window flag
4833 : int StormWinFlagThisDay; // Current time step value (day) of storm window flag
4834 : int nglfacePrevDay; // Previous time step value (dya) of number of glass faces (may differ
4835 : // current time step value, nglface, if storm window was
4836 : // added or removed during the current time step).
4837 :
4838 23964637 : auto &wm = state.dataWindowManager;
4839 :
4840 23964637 : StormWinFlagPrevDay = state.dataSurface->SurfWinStormWinFlagPrevDay(SurfNum);
4841 23964637 : StormWinFlagThisDay = state.dataSurface->SurfWinStormWinFlag(SurfNum);
4842 :
4843 23964637 : if (state.dataGlobal->BeginEnvrnFlag || (StormWinFlagThisDay != StormWinFlagPrevDay)) {
4844 :
4845 : // Guess values of glass face temperatures based on a simple resistance-network solution
4846 : // that (1) ignores short- and long-wave radiation (from lights and zone equipment) absorbed
4847 : // by the glass faces, and (2) assumes zero glass resistance. Absorbed solar is also ignored
4848 : // since the tests on BeginEnvrnFlag and storm window transition can be true only at midnight.
4849 : // Interaction with shade or blind, if one of these is present, is ignored. See below for
4850 : // separate calculation of shade/blind temperature.
4851 :
4852 26656 : rguess(1) = 1.0 / (wm->hcout + hrad);
4853 26656 : rguess(wm->nglface + 1) = 1.0 / (wm->hcin + hrad);
4854 :
4855 61890 : for (int i = 2; i <= wm->nglface; i += 2) {
4856 35234 : rguess(i) = 1.0 / wm->scon[i / 2 - 1];
4857 35234 : if (i < wm->nglface) rguess(i + 1) = resgap;
4858 : }
4859 :
4860 26656 : restot = 0.0;
4861 123780 : for (int i = 1; i <= wm->nglface + 1; ++i) {
4862 97124 : restot += rguess(i);
4863 : }
4864 :
4865 26656 : temdiff = wm->tin - wm->tout;
4866 26656 : if (std::abs(temdiff) < 0.5) temdiff = 2.0;
4867 :
4868 26656 : ressum = 0.0;
4869 97124 : for (int i = 1; i <= wm->nglface; ++i) {
4870 70468 : ressum += rguess(i);
4871 70468 : wm->thetas[i - 1] = (ressum / restot) * temdiff + wm->tout;
4872 : }
4873 :
4874 : } else {
4875 : // Use previous time step values
4876 85758577 : for (int i = 1; i <= wm->nglface; ++i) {
4877 61820596 : wm->thetas[i - 1] = state.dataSurface->SurfaceWindow(SurfNum).thetaFace[i];
4878 : }
4879 : }
4880 :
4881 : // Initialize face temperatures of shade or blind, if present
4882 :
4883 23964637 : ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
4884 23964637 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinExtIntShadePrevTS(SurfNum)) ||
4885 23816852 : state.dataSurface->SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtShade ||
4886 71582263 : state.dataSurface->SurfWinExtIntShadePrevTS(SurfNum) == WinShadingType::ExtBlind ||
4887 23800774 : ANY_BETWEENGLASS_SHADE_BLIND(state.dataSurface->SurfWinExtIntShadePrevTS(SurfNum))) {
4888 : // Shade or blind is on during the previous TS; use previous-TS values of shade/blind face temps.
4889 : // Note that if shade or blind is NOT on in the current TS the following two
4890 : // temperature values, although calculated here, are not used. The shade/blind face numbers
4891 : // during the previous time step depend on whether a storm window glass layer was added to
4892 : // or removed from the window during the current time step.
4893 180717 : nglfacePrevDay = wm->nglface;
4894 180717 : if (StormWinFlagPrevDay == 0 && StormWinFlagThisDay == 1) nglfacePrevDay = wm->nglface - 2;
4895 180717 : if (StormWinFlagPrevDay == 1 && StormWinFlagThisDay == 0) nglfacePrevDay = wm->nglface + 2;
4896 180717 : wm->thetas[wm->nglface] = state.dataSurface->SurfaceWindow(SurfNum).thetaFace[nglfacePrevDay + 1];
4897 180717 : wm->thetas[wm->nglface + 1] = state.dataSurface->SurfaceWindow(SurfNum).thetaFace[nglfacePrevDay + 2];
4898 : } else {
4899 : // No shade or blind previous time step; guess starting values of shade/blind
4900 : // taking into account short- and long-wave radiation (from solar, lights and zone equipment)
4901 : // absorbed by shade/blind faces. Face temps are assumed to be the same and
4902 : // equal to shade/blind temp. For interior shade/blind, air temp on either side is
4903 : // assumed to be the same and equal to tin; for exterior blind it is assumed to be
4904 : // equal to tout. For between-glass shade/blind it is assumed to be equal to the
4905 : // average temperature of the adjacent glass faces.
4906 :
4907 23783920 : if (ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) {
4908 4477 : wm->thetas[wm->nglface] = wm->tin + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (wm->hcin + hrad));
4909 4477 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4910 23779443 : } else if (ShadeFlag == WinShadingType::ExtShade || ShadeFlag == WinShadingType::ExtBlind) {
4911 1107 : wm->thetas[wm->nglface] = wm->tout + (AbsRadShade(1) + AbsRadShade(2)) / (2 * (wm->hcout + hrad));
4912 1107 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4913 23778336 : } else if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
4914 : // Between-glass shade/blind allowed only for double and triple glazing.
4915 : // The factor 16.0 below is based on a combined convective/radiative heat transfer
4916 : // coefficient on either side of the shade/blind of 8.0 W/m2-K -- about 1.4 Btu/h-ft2-F.
4917 30 : if (wm->nglface == 4) { // double glazing
4918 22 : wm->thetas[wm->nglface] = 0.5 * (wm->thetas[1] + wm->thetas[2]) + (AbsRadShade(1) + AbsRadShade(2)) / 16.0;
4919 22 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4920 : } else { // triple glazing
4921 8 : wm->thetas[wm->nglface] = 0.5 * (wm->thetas[3] + wm->thetas[4]) + (AbsRadShade(1) + AbsRadShade(2)) / 16.0;
4922 8 : wm->thetas[wm->nglface + 1] = wm->thetas[wm->nglface];
4923 : }
4924 : }
4925 : }
4926 23964637 : } // StartingWindowTemps()
4927 :
4928 : //****************************************************************************
4929 :
4930 15109751 : void NusseltNumber(EnergyPlusData &state,
4931 : int const SurfNum, // Surface number
4932 : Real64 const tso, // Temperature of gap surface closest to outside (K)
4933 : Real64 const tsi, // Temperature of gap surface closest to zone (K)
4934 : int const IGap, // Gap number
4935 : Real64 const gr, // Gap gas Grashof number
4936 : Real64 const pr, // Gap gas Prandtl number
4937 : Real64 &gnu // Gap gas Nusselt number
4938 : )
4939 : {
4940 :
4941 : // SUBROUTINE INFORMATION:
4942 : // AUTHOR Adapted by Fred Winkelmann from Window5 subroutine nusselt
4943 : // DATE WRITTEN September 2001
4944 : // MODIFIED na
4945 : // RE-ENGINEERED na
4946 :
4947 : // PURPOSE OF THIS SUBROUTINE:
4948 : // Finds the Nusselt number for gas-filled gaps between isothermal solid layers.
4949 : // The gap may be filled with a single gas or a gas mixture.
4950 :
4951 : // METHODOLOGY EMPLOYED:
4952 : // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
4953 : // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
4954 : // The equation numbers below correspond to those in the standard.
4955 :
4956 : // REFERENCES:
4957 : // Window5 source code; ISO 15099
4958 :
4959 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4960 : Real64 asp; // Aspect ratio: window height to gap width
4961 : Real64 ra; // Rayleigh number
4962 : Real64 gnu901; // Nusselt number temporary variables for
4963 : Real64 gnu902;
4964 : Real64 gnu90;
4965 : Real64 gnu601;
4966 : Real64 gnu602; // different tilt and Ra ranges
4967 : Real64 gnu60;
4968 : Real64 gnu601a;
4969 : Real64 gnua;
4970 : Real64 gnub;
4971 : Real64 cra; // Temporary variables
4972 : Real64 a;
4973 : Real64 b;
4974 : Real64 g;
4975 : Real64 ang;
4976 :
4977 15109751 : auto &wm = state.dataWindowManager;
4978 :
4979 15109751 : if (SurfNum > 0) {
4980 15101417 : asp = state.dataSurface->Surface(SurfNum).Height / wm->gaps[IGap - 1].width;
4981 : } else { // SurfNum = 0 when NusseltNumber is called from CalcNominalWindowCond, which applies to a
4982 : // particular construction. So window height is not known and we assume 5 ft (1.524 m)
4983 8334 : asp = 1.524 / wm->gaps[IGap - 1].width;
4984 : }
4985 :
4986 15109751 : wm->tiltr = wm->tilt * Constant::DegToRadians;
4987 15109751 : ra = gr * pr;
4988 : //! fw if (ra > 2.0e6): error that outside range of Rayleigh number?
4989 :
4990 15109751 : if (ra <= 1.0e4) gnu901 = 1.0 + 1.7596678e-10 * std::pow(ra, 2.2984755); // eq. 51
4991 15109751 : if (ra > 1.0e4 && ra <= 5.0e4) gnu901 = 0.028154 * std::pow(ra, 0.4134); // eq. 50
4992 15109751 : if (ra > 5.0e4) gnu901 = 0.0673838 * std::pow(ra, 1.0 / 3.0); // eq. 49
4993 :
4994 15109751 : gnu902 = 0.242 * std::pow(ra / asp, 0.272); // eq. 52
4995 15109751 : gnu90 = max(gnu901, gnu902);
4996 :
4997 15109751 : if (tso > tsi) { // window heated from above
4998 4773408 : gnu = 1.0 + (gnu90 - 1.0) * std::sin(wm->tiltr); // eq. 53
4999 : } else { // window heated from below
5000 10336343 : if (wm->tilt >= 60.0) {
5001 9205926 : if (ra >= 0.001) {
5002 9183516 : g = 0.5 * std::pow(1.0 + std::pow(ra / 3160.0, 20.6), -0.1); // eq. 47
5003 : } else {
5004 22410 : g = 0.5;
5005 : }
5006 9205926 : gnu601a = 1.0 + pow_7(0.0936 * std::pow(ra, 0.314) / (1.0 + g)); // eq. 45
5007 9205926 : gnu601 = std::pow(gnu601a, 0.142857);
5008 :
5009 : // For any aspect ratio
5010 9205926 : gnu602 = (0.104 + 0.175 / asp) * std::pow(ra, 0.283); // eq. 46
5011 9205926 : gnu60 = max(gnu601, gnu602);
5012 :
5013 : // linear interpolation for layers inclined at angles between 60 and 90 deg
5014 9205926 : gnu = ((90.0 - wm->tilt) * gnu60 + (wm->tilt - 60.0) * gnu90) / 30.0;
5015 : }
5016 10336343 : if (wm->tilt < 60.0) { // eq. 42
5017 1130417 : cra = ra * std::cos(wm->tiltr);
5018 1130417 : a = 1.0 - 1708.0 / cra;
5019 1130417 : b = std::pow(cra / 5830.0, 0.33333) - 1.0;
5020 1130417 : gnua = (std::abs(a) + a) / 2.0;
5021 1130417 : gnub = (std::abs(b) + b) / 2.0;
5022 1130417 : ang = 1708.0 * std::pow(std::sin(1.8 * wm->tiltr), 1.6);
5023 1130417 : gnu = 1.0 + 1.44 * gnua * (1.0 - ang / cra) + gnub;
5024 : }
5025 : }
5026 15109751 : } // NusseltNumber()
5027 :
5028 : //*******************************************************************************************************
5029 :
5030 913900 : void TransAndReflAtPhi(Real64 const cs, // Cosine of incidence angle
5031 : Real64 const tf0, // Transmittance at zero incidence angle
5032 : Real64 const rf0, // Front reflectance at zero incidence angle
5033 : Real64 const rb0, // Back reflectance at zero incidence angle
5034 : Real64 &tfp, // Transmittance at cs
5035 : Real64 &rfp, // Front reflectance at cs
5036 : Real64 &rbp, // Back reflectance at cs
5037 : bool const SimpleGlazingSystem, // .TRUE. if simple block model being used
5038 : Real64 const SimpleGlazingSHGC, // SHGC value to use in alternate model for simple glazing system
5039 : Real64 const SimpleGlazingU // U-factor value to use in alternate model for simple glazing system
5040 : )
5041 : {
5042 :
5043 : // SUBROUTINE INFORMATION:
5044 : // AUTHOR F. Winkelmann
5045 : // DATE WRITTEN January 2000
5046 : // MODIFIED 5 June 2003, FCW: modify to correspond to WINDOW 4 and WINDOW 5.
5047 : // Original routine was based on the method in E.U. Finlayson et al,
5048 : // "WINDOW 4.0: Documentation of Calculation Procedures," LBL-33943,
5049 : // July 1993, which is not used in either WINDOW 4 or WINDOW 5.
5050 : // The current routine is based on ASHRAE Handbook of Fundamentals,
5051 : // 2001, pp. 30.20-23, "Optical Properties of Single Glazing Layers."
5052 : // Original routine underpredicted transmittance at angles of
5053 : // incidence > 60 degrees.
5054 : // June 2009. Brent Griffith. add simple window correlation
5055 : // newer model from LBNL windows group 5/15/2009
5056 : // RE-ENGINEERED na
5057 :
5058 : // PURPOSE OF THIS SUBROUTINE:
5059 : // For a single glazing layer, calculate transmittance and reflectance at an arbitrary
5060 : // angle of incidence given transmittance and reflectance at zero incidence angle.
5061 :
5062 : // REFERENCES:
5063 : // ASHRAE Handbook of Fundamentals, 2001, pp. 30.20-23,
5064 : // "Optical Properties of Single Glazing Layers."
5065 :
5066 : Real64 tfp1; // Transmittance at cs for each polarization
5067 : Real64 tfp2;
5068 : Real64 rfp1; // Front reflectance at cs for each polarization
5069 : Real64 rfp2;
5070 : Real64 rbp1; // Back reflectance at cs for each polarization
5071 : Real64 rbp2;
5072 : Real64 betaf; // Intermediate variables
5073 : Real64 betab;
5074 : Real64 r0f;
5075 : Real64 r0b;
5076 : Real64 abf;
5077 : Real64 abb;
5078 : Real64 ngf; // Front and back index of refraction
5079 : Real64 ngb;
5080 : Real64 cgf; // Intermediate variables
5081 : Real64 cgb;
5082 : Real64 rpf1; // Front and back air/glass interface reflectivity
5083 : Real64 rpb1;
5084 : Real64 tpf1;
5085 : Real64 tpb1;
5086 : // and transmittivity for first polarization
5087 : Real64 rpf2; // Front and back air/glass interface reflectivity
5088 : Real64 rpb2;
5089 : Real64 tpf2;
5090 : Real64 tpb2;
5091 : // and transmittivity for second polarization
5092 : Real64 tcl; // Transmittance and reflectance for clear glass
5093 : Real64 rcl;
5094 : Real64 tbnz; // Transmittance and reflectance for bronze glass
5095 : Real64 rbnz;
5096 : Real64 expmabfdivcgf;
5097 : Real64 expm2abfdivcgf;
5098 : Real64 expmabbdivcgb;
5099 :
5100 : Real64 testval; // temporary value for calculations
5101 : Real64 tmp1; // temporary value for calculations
5102 : Real64 tmp2; // temporary value for calculations
5103 : Real64 tmp3; // temporary value for calculations
5104 : Real64 tmp4; // temporary value for calculations
5105 : Real64 tmp5; // temporary value for calculations
5106 : Real64 tmp6; // temporary value for calculations
5107 : Real64 tmp7; // temporary value for calculations
5108 : Real64 tmp8; // temporary value for calculations
5109 : Real64 tmp9; // temporary value for calculations
5110 :
5111 913900 : if (SimpleGlazingSystem) { // use alternate angular dependence model for block model of simple glazing input
5112 :
5113 5280 : Real64 const cs_2(pow_2(cs));
5114 5280 : Real64 const cs_3(pow_3(cs));
5115 5280 : Real64 const cs_4(pow_4(cs));
5116 5280 : Real64 TransCurveA = 0.00 + 3.36 * cs - 3.85 * cs_2 + 1.49 * cs_3 + 0.01 * cs_4;
5117 5280 : Real64 TransCurveB = 0.00 + 2.83 * cs - 2.42 * cs_2 + 0.04 * cs_3 + 0.55 * cs_4;
5118 5280 : Real64 TransCurveC = 0.00 + 2.45 * cs - 1.58 * cs_2 - 0.64 * cs_3 + 0.77 * cs_4;
5119 5280 : Real64 TransCurveD = 0.00 + 2.85 * cs - 2.58 * cs_2 + 0.40 * cs_3 + 0.35 * cs_4;
5120 5280 : Real64 TransCurveE = 0.00 + 1.51 * cs + 2.49 * cs_2 - 5.87 * cs_3 + 2.88 * cs_4;
5121 5280 : Real64 TransCurveF = 0.00 + 1.21 * cs + 3.14 * cs_2 - 6.37 * cs_3 + 3.03 * cs_4;
5122 5280 : Real64 TransCurveG = 0.00 + 1.09 * cs + 3.54 * cs_2 - 6.84 * cs_3 + 3.23 * cs_4;
5123 5280 : Real64 TransCurveH = 0.00 + 0.98 * cs + 3.83 * cs_2 - 7.13 * cs_3 + 3.33 * cs_4;
5124 5280 : Real64 TransCurveI = 0.00 + 0.79 * cs + 3.93 * cs_2 - 6.86 * cs_3 + 3.15 * cs_4;
5125 5280 : Real64 TransCurveJ = 0.00 + 0.08 * cs + 6.02 * cs_2 - 8.84 * cs_3 + 3.74 * cs_4;
5126 5280 : Real64 TransCurveFGHI = (TransCurveF + TransCurveG + TransCurveH + TransCurveI) / 4.0;
5127 5280 : Real64 TransCurveFH = (TransCurveF + TransCurveH) / 2.0;
5128 5280 : Real64 TransCurveBDCD = (TransCurveB + TransCurveD + TransCurveC + TransCurveD) / 4.0;
5129 :
5130 5280 : Real64 ReflectCurveA = 1.00 - 0.70 * cs + 2.57 * cs_2 - 3.20 * cs_3 + 1.33 * cs_4 - TransCurveA;
5131 5280 : Real64 ReflectCurveB = 1.00 - 1.87 * cs + 6.50 * cs_2 - 7.86 * cs_3 + 3.23 * cs_4 - TransCurveB;
5132 5280 : Real64 ReflectCurveC = 1.00 - 2.52 * cs + 8.40 * cs_2 - 9.86 * cs_3 + 3.99 * cs_4 - TransCurveC;
5133 5280 : Real64 ReflectCurveD = 1.00 - 1.85 * cs + 6.40 * cs_2 - 7.64 * cs_3 + 3.11 * cs_4 - TransCurveD;
5134 5280 : Real64 ReflectCurveE = 1.00 - 1.57 * cs + 5.60 * cs_2 - 6.82 * cs_3 + 2.80 * cs_4 - TransCurveE;
5135 5280 : Real64 ReflectCurveF = 1.00 - 3.15 * cs + 10.98 * cs_2 - 13.14 * cs_3 + 5.32 * cs_4 - TransCurveF;
5136 5280 : Real64 ReflectCurveG = 1.00 - 3.25 * cs + 11.32 * cs_2 - 13.54 * cs_3 + 5.49 * cs_4 - TransCurveG;
5137 5280 : Real64 ReflectCurveH = 1.00 - 3.39 * cs + 11.70 * cs_2 - 13.94 * cs_3 + 5.64 * cs_4 - TransCurveH;
5138 5280 : Real64 ReflectCurveI = 1.00 - 4.06 * cs + 13.55 * cs_2 - 15.74 * cs_3 + 6.27 * cs_4 - TransCurveI;
5139 5280 : Real64 ReflectCurveJ = 1.00 - 4.35 * cs + 14.27 * cs_2 - 16.32 * cs_3 + 6.39 * cs_4 - TransCurveJ;
5140 :
5141 5280 : Real64 ReflectCurveFGHI = (ReflectCurveF + ReflectCurveG + ReflectCurveH + ReflectCurveI) / 4.0;
5142 5280 : Real64 ReflectCurveFH = (ReflectCurveF + ReflectCurveH) / 2.0;
5143 5280 : Real64 ReflectCurveBDCD = (ReflectCurveB + ReflectCurveD + ReflectCurveC + ReflectCurveD) / 4.0;
5144 :
5145 5280 : Real64 TransTmp(0.0);
5146 5280 : Real64 ReflectTmp(0.0);
5147 :
5148 5280 : if (SimpleGlazingU < 1.4195) { // cell 1, 2, or 3
5149 80 : if (SimpleGlazingSHGC > 0.45) {
5150 : // cell # 1
5151 : // Curve E
5152 80 : TransTmp = TransCurveE;
5153 80 : ReflectTmp = ReflectCurveE;
5154 :
5155 0 : } else if ((0.35 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
5156 : // cell # 2
5157 : // 2 way interpolation between Curve E and Curve J
5158 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.35, 0.45, TransCurveJ, TransCurveE);
5159 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.35, 0.45, ReflectCurveJ, ReflectCurveE);
5160 :
5161 0 : } else if (SimpleGlazingSHGC < 0.35) {
5162 : // cell # 3
5163 : // Curve J
5164 0 : TransTmp = TransCurveJ;
5165 0 : ReflectTmp = ReflectCurveJ;
5166 : }
5167 :
5168 5200 : } else if ((1.4195 <= SimpleGlazingU) && (SimpleGlazingU <= 1.7034)) { // cell 4, 5 , 6, 7, 8, 9, or 10
5169 0 : if (SimpleGlazingSHGC > 0.55) {
5170 : // cell # 4
5171 : // Curve E
5172 0 : TransTmp = TransCurveE;
5173 0 : ReflectTmp = ReflectCurveE;
5174 :
5175 0 : } else if ((0.5 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
5176 : // cell # 5
5177 : // 4 way interpolation between Curve E , Curve E, Curve E and Curve FGHI
5178 :
5179 0 : TransTmp = InterpolateBetweenFourValues(
5180 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.50, 0.55, TransCurveE, TransCurveE, TransCurveFGHI, TransCurveE);
5181 0 : ReflectTmp = InterpolateBetweenFourValues(
5182 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.50, 0.55, ReflectCurveE, ReflectCurveE, ReflectCurveFGHI, ReflectCurveE);
5183 :
5184 0 : } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.5)) {
5185 : // cell # 6
5186 : // 2 way interpolation between Curve E and Curve FGHI
5187 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveE, TransCurveFGHI);
5188 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveE, ReflectCurveFGHI);
5189 :
5190 0 : } else if ((0.35 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
5191 : // cell # 7
5192 : // 4 way interpolation between Curve E , Curve FGHI, Curve J and Curve FGHI
5193 0 : TransTmp = InterpolateBetweenFourValues(
5194 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.35, 0.45, TransCurveJ, TransCurveE, TransCurveFGHI, TransCurveFGHI);
5195 0 : ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
5196 : SimpleGlazingSHGC,
5197 : 1.4195,
5198 : 1.7034,
5199 : 0.35,
5200 : 0.45,
5201 : ReflectCurveJ,
5202 : ReflectCurveE,
5203 : ReflectCurveFGHI,
5204 : ReflectCurveFGHI);
5205 :
5206 0 : } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.35)) {
5207 : // cell # 8
5208 : // 2 way interpolation between Curve J and Curve FGHI
5209 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveJ, TransCurveFGHI);
5210 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveJ, ReflectCurveFGHI);
5211 :
5212 0 : } else if ((0.25 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
5213 : // cell # 9
5214 : // 4 way interpolation between Curve J, Curve FGHI, Curve J and Curve FH
5215 0 : TransTmp = InterpolateBetweenFourValues(
5216 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.25, 0.3, TransCurveJ, TransCurveJ, TransCurveFH, TransCurveFGHI);
5217 0 : ReflectTmp = InterpolateBetweenFourValues(
5218 : SimpleGlazingU, SimpleGlazingSHGC, 1.4195, 1.7034, 0.25, 0.3, ReflectCurveJ, ReflectCurveJ, ReflectCurveFH, ReflectCurveFGHI);
5219 :
5220 0 : } else if (SimpleGlazingSHGC <= 0.25) {
5221 : // cell # 10
5222 : // 2 way interpolation between Curve J and Curve FH
5223 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, TransCurveJ, TransCurveFH);
5224 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 1.4195, 1.7034, ReflectCurveJ, ReflectCurveFH);
5225 : }
5226 5200 : } else if ((1.7034 < SimpleGlazingU) && (SimpleGlazingU < 3.4068)) { // cell 11, 12, 13, 14, or 15
5227 5040 : if (SimpleGlazingSHGC > 0.55) {
5228 : // cell # 11
5229 : // Curve E
5230 400 : TransTmp = TransCurveE;
5231 400 : ReflectTmp = ReflectCurveE;
5232 :
5233 4640 : } else if ((0.5 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
5234 : // cell # 12
5235 : // 2 way interpolation between Curve E and Curve FGHI
5236 40 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.5, 0.55, TransCurveFGHI, TransCurveE);
5237 40 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.5, 0.55, ReflectCurveFGHI, ReflectCurveE);
5238 :
5239 4600 : } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC < 0.5)) {
5240 : // cell # 13
5241 : // Curve FGHI
5242 4600 : TransTmp = TransCurveFGHI;
5243 4600 : ReflectTmp = ReflectCurveFGHI;
5244 :
5245 0 : } else if ((0.25 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
5246 : // cell # 14
5247 : // 2 way interpolation between Curve FGHI and Curve FH
5248 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.25, 0.30, TransCurveFH, TransCurveFGHI);
5249 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.25, 0.30, ReflectCurveFH, ReflectCurveFGHI);
5250 :
5251 0 : } else if (SimpleGlazingSHGC < 0.25) {
5252 : // cell # 15
5253 : // Curve FH
5254 0 : TransTmp = TransCurveFH;
5255 0 : ReflectTmp = ReflectCurveFH;
5256 : }
5257 :
5258 160 : } else if ((3.4068 <= SimpleGlazingU) && (SimpleGlazingU <= 4.5424)) { // cell 16, 17, 18, 19, 20, 21, 22, or 23
5259 80 : if (SimpleGlazingSHGC > 0.65) {
5260 : // cell # 16
5261 : // 2 way interpolation between Curve E and Curve A
5262 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveE, TransCurveA);
5263 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveE, ReflectCurveA);
5264 :
5265 80 : } else if ((0.6 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.65)) {
5266 : // cell # 17
5267 : // 4 way interpolation between Curve E , Curve E, Curve A, and Curve BDCD
5268 0 : TransTmp = InterpolateBetweenFourValues(
5269 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.6, 0.65, TransCurveE, TransCurveE, TransCurveBDCD, TransCurveA);
5270 0 : ReflectTmp = InterpolateBetweenFourValues(
5271 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.6, 0.65, ReflectCurveE, ReflectCurveE, ReflectCurveBDCD, ReflectCurveA);
5272 :
5273 80 : } else if ((0.55 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.6)) {
5274 : // cell # 18
5275 : // 2 way interpolation between Curve E and Curve BDCD
5276 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveE, TransCurveBDCD);
5277 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveE, ReflectCurveBDCD);
5278 :
5279 80 : } else if ((0.5 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.55)) {
5280 : // cell # 19
5281 : // 4 way interpolation between Curve E , Curve FGHI, Curve BDCD and Curve BDCD
5282 40 : TransTmp = InterpolateBetweenFourValues(
5283 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.5, 0.55, TransCurveFGHI, TransCurveE, TransCurveBDCD, TransCurveBDCD);
5284 40 : ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
5285 : SimpleGlazingSHGC,
5286 : 3.4068,
5287 : 4.5424,
5288 : 0.5,
5289 : 0.55,
5290 : ReflectCurveFGHI,
5291 : ReflectCurveE,
5292 : ReflectCurveBDCD,
5293 : ReflectCurveBDCD);
5294 :
5295 40 : } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.5)) {
5296 : // cell # 20
5297 : // 2 way interpolation between Curve FGHI and Curve BDCD
5298 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveFGHI, TransCurveBDCD);
5299 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveFGHI, ReflectCurveBDCD);
5300 :
5301 40 : } else if ((0.3 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
5302 : // cell # 21
5303 : // 4 way interpolation between Curve FGHI, Curve FGHI, Curve BDCD, and Curve D
5304 40 : TransTmp = InterpolateBetweenFourValues(
5305 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.3, 0.45, TransCurveFGHI, TransCurveFGHI, TransCurveD, TransCurveBDCD);
5306 40 : ReflectTmp = InterpolateBetweenFourValues(SimpleGlazingU,
5307 : SimpleGlazingSHGC,
5308 : 3.4068,
5309 : 4.5424,
5310 : 0.3,
5311 : 0.45,
5312 : ReflectCurveFGHI,
5313 : ReflectCurveFGHI,
5314 : ReflectCurveD,
5315 : ReflectCurveBDCD);
5316 :
5317 0 : } else if ((0.25 < SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.3)) {
5318 : // cell # 22
5319 : // 4 way interpolation between Curve FGHI, Curve FH, Curve D, and Curve D
5320 0 : TransTmp = InterpolateBetweenFourValues(
5321 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.25, 0.3, TransCurveFH, TransCurveFGHI, TransCurveD, TransCurveD);
5322 0 : ReflectTmp = InterpolateBetweenFourValues(
5323 : SimpleGlazingU, SimpleGlazingSHGC, 3.4068, 4.5424, 0.25, 0.3, ReflectCurveFH, ReflectCurveFGHI, ReflectCurveD, ReflectCurveD);
5324 :
5325 0 : } else if (SimpleGlazingSHGC <= 0.25) {
5326 : // cell # 23
5327 : // 2 way interpolation between Curve FH and Curve D
5328 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, TransCurveFH, TransCurveD);
5329 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingU, 3.4068, 4.5424, ReflectCurveFH, ReflectCurveD);
5330 : }
5331 80 : } else if (SimpleGlazingU > 4.5424) { // cell 24, 25, 26, 27, or 28
5332 80 : if (SimpleGlazingSHGC > 0.65) {
5333 : // cell # 24
5334 : // Curve A
5335 80 : TransTmp = TransCurveA;
5336 80 : ReflectTmp = ReflectCurveA;
5337 0 : } else if ((0.6 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.65)) {
5338 : // cell # 25
5339 : // 2 way interpolation between Curve A and Curve BDCD
5340 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.6, 0.65, TransCurveBDCD, TransCurveA);
5341 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.6, 0.65, ReflectCurveBDCD, ReflectCurveA);
5342 :
5343 0 : } else if ((0.45 < SimpleGlazingSHGC) && (SimpleGlazingSHGC < 0.6)) {
5344 : // cell # 26
5345 : // Curve BDCD
5346 0 : TransTmp = TransCurveBDCD;
5347 0 : ReflectTmp = ReflectCurveBDCD;
5348 :
5349 0 : } else if ((0.3 <= SimpleGlazingSHGC) && (SimpleGlazingSHGC <= 0.45)) {
5350 : // cell # 27
5351 : // 2 way interpolation between Curve BDCD and Curve D
5352 0 : TransTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.3, 0.45, TransCurveD, TransCurveBDCD);
5353 0 : ReflectTmp = InterpolateBetweenTwoValues(SimpleGlazingSHGC, 0.3, 0.45, ReflectCurveD, ReflectCurveBDCD);
5354 :
5355 0 : } else if (SimpleGlazingSHGC < 0.3) {
5356 : // cell # 28
5357 : // Curve D
5358 0 : TransTmp = TransCurveD;
5359 0 : ReflectTmp = ReflectCurveD;
5360 :
5361 : } else {
5362 0 : assert(false);
5363 : }
5364 : } else {
5365 0 : assert(false);
5366 : }
5367 :
5368 5280 : if (cs == 1.0) { // at 0 deg incident, TransTmp and ReflectTmp should be 1.0
5369 528 : TransTmp = 1.0;
5370 528 : ReflectTmp = 0.0;
5371 : }
5372 :
5373 : // now apply normalization factors to zero incidence angle properties
5374 5280 : tfp = tf0 * TransTmp;
5375 5280 : tfp = max(min(1.0, tfp), 0.0);
5376 :
5377 5280 : rfp = rf0 * (1. - ReflectTmp) + ReflectTmp;
5378 5280 : rfp = max(min(0.9999 - tfp, rfp), 0.0);
5379 :
5380 5280 : rbp = rfp;
5381 :
5382 908620 : } else if (tf0 <= 0.0) {
5383 : // This is an opaque window. For all angles, set transmittance to 0; set reflectance to that at zero incidence angle.
5384 0 : tfp = 0.0;
5385 0 : rfp = rf0;
5386 0 : rbp = rb0;
5387 : } else {
5388 :
5389 908620 : betaf = pow_2(tf0) - pow_2(rf0) + 2.0 * rf0 + 1.0;
5390 908620 : betab = pow_2(tf0) - pow_2(rb0) + 2.0 * rb0 + 1.0;
5391 908620 : r0f = (betaf - std::sqrt(pow_2(betaf) - 4.0 * (2.0 - rf0) * rf0)) / (2.0 * (2.0 - rf0));
5392 908620 : r0b = (betab - std::sqrt(pow_2(betab) - 4.0 * (2.0 - rb0) * rb0)) / (2.0 * (2.0 - rb0));
5393 :
5394 908620 : tmp1 = std::abs(r0f - r0b);
5395 908620 : if (tmp1 != 0.0) {
5396 264420 : testval = std::abs(r0f - r0b) / (r0f + r0b);
5397 : } else {
5398 644200 : testval = 0.0;
5399 : }
5400 :
5401 908620 : if (testval < 0.001) { // CR8830, CR8942, implications of relaxation of glazing properties CR8413
5402 : // UNCOATED GLASS
5403 654700 : tmp1 = r0f * tf0;
5404 654700 : if (tmp1 != 0.0) {
5405 654700 : abf = std::log(tmp1 / (rf0 - r0f));
5406 : } else {
5407 0 : abf = 0.0;
5408 : }
5409 654700 : tmp2 = r0b * tf0;
5410 654700 : if (tmp2 != 0.0) {
5411 654700 : abb = std::log(tmp2 / (rb0 - r0b));
5412 : } else {
5413 0 : abb = 0.0;
5414 : }
5415 654700 : ngf = (1.0 + std::sqrt(r0f)) / (1.0 - std::sqrt(r0f));
5416 654700 : ngb = (1.0 + std::sqrt(r0b)) / (1.0 - std::sqrt(r0b));
5417 654700 : cgf = std::sqrt(1.0 - (1.0 - cs * cs) / pow_2(ngf));
5418 654700 : cgb = std::sqrt(1.0 - (1.0 - cs * cs) / pow_2(ngb));
5419 654700 : tmp3 = ngf * cs - cgf;
5420 654700 : if (tmp3 != 0.0) {
5421 654700 : rpf1 = pow_2(tmp3 / (ngf * cs + cgf));
5422 : } else {
5423 0 : rpf1 = 0.0;
5424 : }
5425 654700 : tmp4 = ngf * cgf - cs;
5426 654700 : if (tmp4 != 0.0) {
5427 654700 : rpf2 = pow_2(tmp4 / (ngf * cgf + cs));
5428 : } else {
5429 0 : rpf2 = 0.0;
5430 : }
5431 654700 : tpf1 = 1 - rpf1;
5432 654700 : tpf2 = 1 - rpf2;
5433 654700 : tmp5 = ngb * cs - cgb;
5434 654700 : if (tmp5 != 0.0) {
5435 654700 : rpb1 = pow_2(tmp5 / (ngb * cs + cgb));
5436 : } else {
5437 0 : rpb1 = 0.0;
5438 : }
5439 654700 : tmp6 = ngb * cgb - cs;
5440 654700 : if (tmp6 != 0.0) {
5441 654700 : rpb2 = pow_2(tmp6 / (ngb * cgb + cs));
5442 : } else {
5443 0 : rpb2 = 0.0;
5444 : }
5445 654700 : tpb1 = 1 - rpf1;
5446 654700 : tpb2 = 1 - rpf2;
5447 654700 : tmp7 = -abf;
5448 654700 : if (cgf != 0.0) {
5449 654700 : expmabfdivcgf = std::exp(tmp7 / cgf);
5450 : } else {
5451 0 : expmabfdivcgf = 0.0;
5452 : }
5453 654700 : tmp8 = -2.0 * abf;
5454 654700 : if (cgf != 0.0) {
5455 654700 : expm2abfdivcgf = std::exp(tmp8 / cgf);
5456 : } else {
5457 0 : expm2abfdivcgf = 0.0;
5458 : }
5459 654700 : if (tpf1 != 0.0) {
5460 589230 : tfp1 = pow_2(tpf1) * expmabfdivcgf / (1.0 - pow_2(rpf1) * expm2abfdivcgf);
5461 : } else {
5462 65470 : tfp1 = 0.0;
5463 : }
5464 654700 : rfp1 = rpf1 * (1.0 + tfp1 * expmabfdivcgf);
5465 654700 : if (tpf2 != 0.0) {
5466 589230 : tfp2 = pow_2(tpf2) * expmabfdivcgf / (1.0 - pow_2(rpf2) * expm2abfdivcgf);
5467 : } else {
5468 65470 : tfp2 = 0.0;
5469 : }
5470 654700 : rfp2 = rpf2 * (1.0 + tfp2 * expmabfdivcgf);
5471 654700 : tfp = 0.5 * (tfp1 + tfp2);
5472 654700 : rfp = 0.5 * (rfp1 + rfp2);
5473 654700 : tmp9 = -abb;
5474 654700 : if (tmp9 != 0.0) {
5475 654700 : expmabbdivcgb = std::exp(tmp9 / cgb);
5476 : } else {
5477 0 : expmabbdivcgb = 0.0;
5478 : }
5479 654700 : rbp1 = rpb1 * (1.0 + tfp1 * expmabbdivcgb);
5480 654700 : rbp2 = rpb2 * (1.0 + tfp2 * expmabbdivcgb);
5481 654700 : rbp = 0.5 * (rbp1 + rbp2);
5482 : } else {
5483 : // COATED GLASS
5484 253920 : if (tf0 > 0.645) {
5485 : // Use clear glass angular distribution.
5486 : // Normalized clear glass transmittance and reflectance distribution
5487 144900 : if (cs > 0.999) { // Angle of incidence = 0 deg
5488 14490 : tcl = 1.0;
5489 14490 : rcl = 0.0;
5490 130410 : } else if (cs < 0.001) { // Angle of incidence = 90 deg
5491 14490 : tcl = 0.0;
5492 14490 : rcl = 1.0;
5493 : } else {
5494 115920 : tcl = -0.0015 + (3.355 + (-3.840 + (1.460 + 0.0288 * cs) * cs) * cs) * cs;
5495 115920 : rcl = 0.999 + (-0.563 + (2.043 + (-2.532 + 1.054 * cs) * cs) * cs) * cs - tcl;
5496 : }
5497 144900 : tfp = tf0 * tcl;
5498 144900 : rfp = rf0 * (1.0 - rcl) + rcl;
5499 144900 : rbp = rb0 * (1.0 - rcl) + rcl;
5500 : } else {
5501 : // Use bronze glass angular distribution.
5502 : // Normalized bronze tinted glass transmittance and reflectance distribution
5503 109020 : if (cs > 0.999) { // Angle of incidence = 0 deg
5504 10902 : tbnz = 1.0;
5505 10902 : rbnz = 0.0;
5506 98118 : } else if (cs < 0.001) { // Angle of incidence = 90 deg
5507 10902 : tbnz = 0.0;
5508 10902 : rbnz = 1.0;
5509 : } else {
5510 87216 : tbnz = -0.002 + (2.813 + (-2.341 + (-0.05725 + 0.599 * cs) * cs) * cs) * cs;
5511 87216 : rbnz = 0.997 + (-1.868 + (6.513 + (-7.862 + 3.225 * cs) * cs) * cs) * cs - tbnz;
5512 : }
5513 109020 : tfp = tf0 * tbnz;
5514 109020 : rfp = rf0 * (1.0 - rbnz) + rbnz;
5515 109020 : rbp = rb0 * (1.0 - rbnz) + rbnz;
5516 : }
5517 : }
5518 : }
5519 :
5520 : // total absorptance cannot be negative
5521 913900 : assert(1.0 - rfp - tfp >= -1e6);
5522 913900 : assert(1.0 - rbp - tfp >= -1e6);
5523 913900 : } // TransAndReflAtPhi()
5524 :
5525 80 : Real64 InterpolateBetweenTwoValues(Real64 const X, Real64 const X0, Real64 const X1, Real64 const F0, Real64 const F1)
5526 : {
5527 :
5528 : // FUNCTION INFORMATION:
5529 : // AUTHOR Brent Griffith
5530 : // DATE WRITTEN June 2009
5531 : // MODIFIED na
5532 : // RE-ENGINEERED na
5533 :
5534 : // PURPOSE OF THIS FUNCTION:
5535 : // Interpolate between two results
5536 :
5537 : // METHODOLOGY EMPLOYED:
5538 : // linear interpolation
5539 :
5540 : Real64 InterpResult;
5541 :
5542 80 : InterpResult = F0 + ((X - X0) / (X1 - X0)) * (F1 - F0);
5543 80 : return InterpResult;
5544 : } // InterpolateBetweenTwoValues()
5545 :
5546 160 : Real64 InterpolateBetweenFourValues(Real64 const X,
5547 : Real64 const Y,
5548 : Real64 const X1,
5549 : Real64 const X2,
5550 : Real64 const Y1,
5551 : Real64 const Y2,
5552 : Real64 const Fx1y1,
5553 : Real64 const Fx1y2,
5554 : Real64 const Fx2y1,
5555 : Real64 const Fx2y2)
5556 : {
5557 :
5558 : // FUNCTION INFORMATION:
5559 : // AUTHOR Brent Griffith
5560 : // DATE WRITTEN June 2009
5561 : // MODIFIED na
5562 : // RE-ENGINEERED na
5563 :
5564 : // PURPOSE OF THIS FUNCTION:
5565 : // Interpolate between four results.
5566 :
5567 : // METHODOLOGY EMPLOYED:
5568 : // bilinear interpolation (approximate)
5569 :
5570 : // REFERENCES:
5571 : // http://en.wikipedia.org/wiki/Bilinear_interpolation
5572 :
5573 : // Return value
5574 : Real64 InterpResult;
5575 :
5576 160 : InterpResult = (Fx1y1 / ((X2 - X1) * (Y2 - Y1))) * (X2 - X) * (Y2 - Y) + (Fx2y1 / ((X2 - X1) * (Y2 - Y1))) * (X - X1) * (Y2 - Y) +
5577 160 : (Fx1y2 / ((X2 - X1) * (Y2 - Y1))) * (X2 - X) * (Y - Y1) + (Fx2y2 / ((X2 - X1) * (Y2 - Y1))) * (X - X1) * (Y - Y1);
5578 160 : return InterpResult;
5579 : } // InterpolateBetweenFourValues()
5580 :
5581 : //**************************************************************************
5582 :
5583 23444 : void W5LsqFit(Array1S<Real64> const IndepVar, // Independent variables
5584 : Array1S<Real64> const DepVar, // Dependent variables
5585 : int const N, // Order of polynomial
5586 : int const N1, // First and last data points used
5587 : int const N2,
5588 : Array1S<Real64> CoeffsCurve // Polynomial coeffients from fit
5589 : )
5590 : {
5591 :
5592 : // SUBROUTINE INFORMATION:
5593 : // AUTHOR George Walton
5594 : // DATE WRITTEN April 1976
5595 : // MODIFIED November 1999 F.Winkelmann
5596 : // RE-ENGINEERED na
5597 :
5598 : // PURPOSE OF THIS SUBROUTINE:
5599 : // Does least squares fit for coefficients of a polynomial
5600 : // that gives a window property, such as transmittance, as a function of
5601 : // the cosine of the angle of incidence. The polynomial is of the
5602 : // form C1*X + C2*X**2 + C3*X**3 + ... +CN*X**N, where N <= 6.
5603 : // Adapted from BLAST subroutine LSQFIT.
5604 :
5605 46888 : Array2D<Real64> A(6, 6); // Least squares derivative matrix
5606 23444 : Array1D<Real64> B(6); // Least squares derivative vector
5607 46888 : Array2D<Real64> D(6, 16); // Powers of independent variable
5608 : Real64 ACON; // Intermediate variables
5609 : Real64 SUM;
5610 : int KP1;
5611 : int LP1;
5612 : int NM1;
5613 :
5614 : // Set up least squares matrix
5615 257884 : for (int M = N1; M <= N2; ++M) {
5616 234440 : D(1, M) = IndepVar(M);
5617 : }
5618 :
5619 140664 : for (int i = 2; i <= N; ++i) {
5620 1289420 : for (int M = N1; M <= N2; ++M) {
5621 1172200 : D(i, M) = D(i - 1, M) * IndepVar(M);
5622 : }
5623 : }
5624 :
5625 164108 : for (int i = 1; i <= N; ++i) {
5626 140664 : SUM = 0.0;
5627 1547304 : for (int M = N1; M <= N2; ++M) {
5628 1406640 : SUM += DepVar(M) * D(i, M);
5629 : }
5630 140664 : B(i) = SUM;
5631 984648 : for (int j = 1; j <= N; ++j) {
5632 843984 : SUM = 0.0;
5633 9283824 : for (int M = N1; M <= N2; ++M) {
5634 8439840 : SUM += D(i, M) * D(j, M);
5635 : }
5636 843984 : A(j, i) = SUM;
5637 843984 : A(i, j) = SUM;
5638 : }
5639 : }
5640 :
5641 : // Solve the simultaneous equations using Gauss elimination
5642 23444 : NM1 = N - 1;
5643 140664 : for (int K = 1; K <= NM1; ++K) {
5644 117220 : KP1 = K + 1;
5645 468880 : for (int i = KP1; i <= N; ++i) {
5646 351660 : ACON = A(K, i) / A(K, K);
5647 351660 : B(i) -= B(K) * ACON;
5648 1992740 : for (int j = K; j <= N; ++j) {
5649 1641080 : A(j, i) -= A(j, K) * ACON;
5650 : }
5651 : }
5652 : }
5653 :
5654 : // Perform back substituion
5655 23444 : CoeffsCurve(N) = B(N) / A(N, N);
5656 23444 : LP1 = N;
5657 23444 : int L = N - 1;
5658 :
5659 140664 : while (L > 0) {
5660 117220 : SUM = 0.0;
5661 468880 : for (int j = LP1; j <= N; ++j) {
5662 351660 : SUM += A(j, L) * CoeffsCurve(j);
5663 : }
5664 117220 : CoeffsCurve(L) = (B(L) - SUM) / A(L, L);
5665 117220 : LP1 = L;
5666 117220 : --L;
5667 : }
5668 23444 : } // W5LsqFit()
5669 :
5670 : //********************************************************************************
5671 :
5672 0 : void W5LsqFit2(Array1A<Real64> const IndepVar, // Independent variables
5673 : Array1A<Real64> const DepVar, // Dependent variables
5674 : int const N, // Order of polynomial
5675 : int const N1, // First and last data points used
5676 : int const N2,
5677 : Array1A<Real64> CoeffsCurve // Polynomial coefficients from fit
5678 : )
5679 : {
5680 :
5681 : // SUBROUTINE INFORMATION:
5682 : // AUTHOR George Walton
5683 : // DATE WRITTEN April 1976
5684 : // MODIFIED November 1999 F.Winkelmann
5685 : // May 2001 F. Winkelmann, to do 19 indep. variables
5686 : // RE-ENGINEERED na
5687 :
5688 : // PURPOSE OF THIS SUBROUTINE:
5689 : // Does least squares fit for coefficients of a polynomial
5690 : // that gives a window property, such as transmittance, as a function of
5691 : // the cosine of the angle of incidence. The polynomial is of the
5692 : // form C1*X + C2*X**2 + C3*X**3 + ... +CN*X**N, where N <= 6.
5693 : // Adapted from BLAST subroutine LSQFIT.
5694 :
5695 : // Argument array dimensioning
5696 0 : IndepVar.dim(19);
5697 0 : DepVar.dim(19);
5698 0 : CoeffsCurve.dim(6);
5699 :
5700 0 : Array2D<Real64> A(6, 6); // Least squares derivative matrix
5701 0 : Array1D<Real64> B(6); // Least squares derivative vector
5702 0 : Array2D<Real64> D(6, 16); // Powers of independent variable
5703 : Real64 ACON; // Intermediate variables
5704 : Real64 SUM;
5705 : int KP1;
5706 : int LP1;
5707 : int NM1;
5708 :
5709 : // Set up least squares matrix
5710 0 : for (int M = N1; M <= N2; ++M) {
5711 0 : D(1, M) = IndepVar(M);
5712 : }
5713 :
5714 0 : for (int i = 2; i <= N; ++i) {
5715 0 : for (int M = N1; M <= N2; ++M) {
5716 0 : D(i, M) = D(i - 1, M) * IndepVar(M);
5717 : }
5718 : }
5719 :
5720 0 : for (int i = 1; i <= N; ++i) {
5721 0 : SUM = 0.0;
5722 0 : for (int M = N1; M <= N2; ++M) {
5723 0 : SUM += DepVar(M) * D(i, M);
5724 : }
5725 0 : B(i) = SUM;
5726 0 : for (int j = 1; j <= N; ++j) {
5727 0 : SUM = 0.0;
5728 0 : for (int M = N1; M <= N2; ++M) {
5729 0 : SUM += D(i, M) * D(j, M);
5730 : }
5731 0 : A(j, i) = SUM;
5732 0 : A(i, j) = SUM;
5733 : }
5734 : }
5735 :
5736 : // Solve the simultaneous equations using Gauss elimination
5737 0 : NM1 = N - 1;
5738 0 : for (int K = 1; K <= NM1; ++K) {
5739 0 : KP1 = K + 1;
5740 0 : for (int i = KP1; i <= N; ++i) {
5741 0 : ACON = A(K, i) / A(K, K);
5742 0 : B(i) -= B(K) * ACON;
5743 0 : for (int j = K; j <= N; ++j) {
5744 0 : A(j, i) -= A(j, K) * ACON;
5745 : }
5746 : }
5747 : }
5748 :
5749 : // Perform back substituion
5750 0 : CoeffsCurve(N) = B(N) / A(N, N);
5751 0 : LP1 = N;
5752 0 : int L = N - 1;
5753 :
5754 0 : while (L > 0) {
5755 0 : SUM = 0.0;
5756 0 : for (int j = LP1; j <= N; ++j) {
5757 0 : SUM += A(j, L) * CoeffsCurve(j);
5758 : }
5759 0 : CoeffsCurve(L) = (B(L) - SUM) / A(L, L);
5760 0 : LP1 = L;
5761 0 : --L;
5762 : }
5763 0 : } // W5LsqFit2()
5764 :
5765 : //***********************************************************************
5766 :
5767 24930 : Real64 DiffuseAverage(Array1S<Real64> const PropertyValue) // Property value at angles of incidence
5768 : {
5769 :
5770 : // FUNCTION INFORMATION:
5771 : // AUTHOR Fred Winkelmann
5772 : // DATE WRITTEN November 1999
5773 : // MODIFIED na
5774 : // RE-ENGINEERED na
5775 :
5776 : // PURPOSE OF THIS FUNCTION:
5777 : // Calculate value of property, such as transmittance, for hemispherical
5778 : // diffuse radiation from property values at angles of incidence from
5779 : // 0 to 90 degrees in 10 degree increments.
5780 :
5781 : // METHODOLOGY EMPLOYED:
5782 : // By Simpson's rule, evaluates the integral from 0 to 90 deg of
5783 : // 2*PropertyValue(phi)*cos(phi)*sin(phi)*dphi (which is same as
5784 : // PropertyValue(phi)*sin(2*phi)*dphi)
5785 :
5786 : // Return value
5787 : Real64 DiffuseAverage;
5788 :
5789 : // Locals
5790 : // SUBROUTINE ARGUMENT DEFINITIONS:
5791 : // 0,10,20,...,80,90 degress
5792 :
5793 24930 : Real64 const DPhiR(10.0 * Constant::DegToRadians); // Half of 10-deg incidence angle increment (radians)
5794 :
5795 24930 : DiffuseAverage = 0.0;
5796 249300 : for (int IPhi = 1; IPhi <= 9; ++IPhi) {
5797 224370 : DiffuseAverage +=
5798 224370 : 0.5 * DPhiR * (PropertyValue(IPhi) * std::sin(2.0 * (IPhi - 1) * DPhiR) + PropertyValue(IPhi + 1) * std::sin(2.0 * IPhi * DPhiR));
5799 : }
5800 24930 : if (DiffuseAverage < 0.0) DiffuseAverage = 0.0;
5801 :
5802 24930 : return DiffuseAverage;
5803 : } // DiffuseAverage()
5804 :
5805 : //*************************************************************************************
5806 :
5807 2244 : Real64 DiffuseAverageProfAngGnd(Array1S<Real64> const Property) // Property value vs. profile angle
5808 : {
5809 :
5810 : // FUNCTION INFORMATION:
5811 : // AUTHOR Fred Winkelmann
5812 : // DATE WRITTEN January 2004
5813 : // MODIFIED na
5814 : // RE-ENGINEERED na
5815 :
5816 : // PURPOSE OF THIS FUNCTION:
5817 : // Calculates diffuse average of Property, such as blind transmittance, over profile angles
5818 : // corresponding to (upgoing) radiation from the ground.
5819 :
5820 : // METHODOLOGY EMPLOYED:
5821 : // Integration by Simpson's rule assuming uniform radiance distribution.
5822 :
5823 : // Return value
5824 : Real64 DiffuseAverageProfAngGnd;
5825 :
5826 : Real64 Phi; // Profile angle (radians)
5827 : Real64 DPhi; // Phi increment
5828 : Real64 Sum; // Sums
5829 : Real64 SumDenom;
5830 :
5831 2244 : Sum = 0.0;
5832 2244 : SumDenom = 0.0;
5833 2244 : DPhi = 5.0 * Constant::DegToRadians;
5834 :
5835 : // Integrate from -90 to 0 deg
5836 42636 : for (int IPhi = 1; IPhi <= (Material::MaxProfAngs / 2); ++IPhi) {
5837 40392 : Phi = -Constant::PiOvr2 + (IPhi - 0.5) * DPhi;
5838 40392 : Sum += std::cos(Phi) * DPhi * InterpProfAng(Phi, Property);
5839 40392 : SumDenom += std::cos(Phi) * DPhi;
5840 : }
5841 :
5842 2244 : DiffuseAverageProfAngGnd = Sum / SumDenom;
5843 2244 : if (DiffuseAverageProfAngGnd < 0.0) DiffuseAverageProfAngGnd = 0.0;
5844 :
5845 2244 : return DiffuseAverageProfAngGnd;
5846 : } // DiffuseAverageProfAngGnd()
5847 :
5848 : //*************************************************************************************
5849 :
5850 2244 : Real64 DiffuseAverageProfAngSky(Array1S<Real64> const Property) // Property value vs. profile angle
5851 : {
5852 :
5853 : // FUNCTION INFORMATION:
5854 : // AUTHOR Fred Winkelmann
5855 : // DATE WRITTEN January 2004
5856 : // MODIFIED na
5857 : // RE-ENGINEERED na
5858 :
5859 : // PURPOSE OF THIS FUNCTION:
5860 : // Calculates diffuse average of Property, such as blind transmittance, over profile angles
5861 : // corresponding to (downgoing) radiation from the sky.
5862 :
5863 : // METHODOLOGY EMPLOYED:
5864 : // Integration by Simpson's rule assuming uniform radiance distribution.
5865 :
5866 : // Return value
5867 : Real64 DiffuseAverageProfAngSky;
5868 :
5869 : Real64 Phi; // Profile angle (radians)
5870 : Real64 DPhi; // Phi increment
5871 : Real64 Sum; // Sums
5872 : Real64 SumDenom;
5873 :
5874 2244 : Sum = 0.0;
5875 2244 : SumDenom = 0.0;
5876 2244 : DPhi = 5.0 * Constant::DegToRadians;
5877 :
5878 : // Integrate from 0 to 90 deg
5879 42636 : for (int IPhi = (Material::MaxProfAngs / 2) + 1; IPhi <= Material::MaxProfAngs - 1; ++IPhi) {
5880 40392 : Phi = -Constant::PiOvr2 + (IPhi - 0.5) * DPhi;
5881 40392 : Sum += std::cos(Phi) * DPhi * InterpProfAng(Phi, Property);
5882 40392 : SumDenom += std::cos(Phi) * DPhi;
5883 : }
5884 :
5885 2244 : DiffuseAverageProfAngSky = Sum / SumDenom;
5886 2244 : if (DiffuseAverageProfAngSky < 0.0) DiffuseAverageProfAngSky = 0.0;
5887 :
5888 2244 : return DiffuseAverageProfAngSky;
5889 : } // DiffuseAverageProfAngSky()
5890 :
5891 : //*************************************************************************************
5892 :
5893 656496 : void CalcWinFrameAndDividerTemps(EnergyPlusData &state,
5894 : int const SurfNum, // Surface number
5895 : Real64 const tout, // Outside air temperature (K)
5896 : Real64 const tin, // Inside air temperature (K)
5897 : Real64 const HOutConv, // Outside convective air film conductance (W/m2-K)
5898 : Real64 const HInConv, // Inside convective air film conductance (W/m2-K)
5899 : Real64 const Outir, // Exterior IR irradiance from sky and ground
5900 : int const ConstrNum // Construction number of window
5901 : )
5902 : {
5903 :
5904 : // SUBROUTINE INFORMATION:
5905 : // AUTHOR F. Winkelmann
5906 : // DATE WRITTEN May 2000
5907 : // MODIFIED Aug 2000, FCW: Add effect of frame and divider projections
5908 : // Jun 2001, FCW: Add frame/divider contribution to WinHeatGain
5909 : // Aug 2003, FCW: Fix calculation of divider outside temp: frame
5910 : // inside temp was being used instead of divider inside temp
5911 : // RE-ENGINEERED na
5912 :
5913 : // PURPOSE OF THIS SUBROUTINE:
5914 : // Calculates window frame divider face temperatures from a linearized
5915 : // heat balance on the inside and outside faces
5916 :
5917 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5918 : Real64 HInRad; // Inside radiative conductance (W/m2-K)
5919 : Real64 HOutRad; // Outside radiative conductance (W/m2-K)
5920 : int FrDivNum; // Frame/divider number
5921 : Real64 TInRad; // Inside radiative temperature (K)
5922 : Real64 TInRadFr; // Effective inside radiative temperature for frame (K)
5923 : Real64 TInRadDiv; // Effective inside radiative temperature for divider (K)
5924 : Real64 TOutRad; // Outside radiative temperature (K)
5925 : Real64 TOutRadFr; // Effective outside radiative temperature for frame (K)
5926 : Real64 TOutRadDiv; // Effective outside radiative temperature for divider (K)
5927 : WinShadingType ShadeFlag; // Window shading flag
5928 : Real64 FrameCon; // Frame conductance (W/m2-K)
5929 :
5930 : Real64 Afac; // Intermediate calculation variables
5931 : Real64 Bfac;
5932 : Real64 Dfac;
5933 : Real64 Efac;
5934 : DataSurfaces::FrameDividerType DivType; // Divider type
5935 : Real64 DivCon; // Divider conductance (W/m2-K)
5936 : Real64 DivEmisIn; // Inside divider emissivity
5937 : Real64 DivEmisOut; // Outside divider emissivity
5938 :
5939 : Real64 ProjCorrFrOut; // Outside correction factor for absorbed radiation
5940 : // for frame with outside projection
5941 : Real64 ProjCorrFrIn; // Inside correction factor for absorbed radiation
5942 : // for frame with inside projection
5943 : Real64 HOutConvFr; // Effective outside convective coeff for frame
5944 : // with outside projection (W/m2-K)
5945 : Real64 HOutConvDiv; // Effective outside convective coeff for divider
5946 : // with outside projection (W/m2-K)
5947 : Real64 HInConvFr; // Effective inside convective coeff for frame
5948 : // with inside projection (W/m2-K)
5949 : Real64 HInConvDiv; // Effective inside convective coeff for divider
5950 : // with inside projection (W/m2-K)
5951 : Real64 EmisGlassOut; // Outside surface emissivity of window glazing
5952 : Real64 EmisGlassIn; // Inside surface emissivity of window glazing
5953 : int TotGlassLayers; // Total number of glass layers
5954 : int TotLayers; // Total number of layers in unshaded construction
5955 : // Real64 DivTempOut; // Outside surface divider temperature (K)
5956 : Real64 FrameHeatGain; // Heat gain to zone from frame (W)
5957 : // Real64 FrameHeatTransfer; // Heat tansfer through frame (W)
5958 : // Real64 ProjCorrWinHeatGain; // Inside projection correction to IR from divider to zone
5959 : // for window heat gain calculation
5960 : Real64 DividerHeatGain; // Heat gain to zone from divider (W)
5961 : // Real64 DividerHeatTransfer; // Heat transfer through divider (W)
5962 :
5963 656496 : auto const &surfWin = state.dataSurface->SurfaceWindow(SurfNum);
5964 :
5965 656496 : TInRad = root_4(state.dataSurface->SurfWinIRfromParentZone(SurfNum) / Constant::StefanBoltzmann);
5966 656496 : TOutRad = root_4(Outir / Constant::StefanBoltzmann);
5967 656496 : ShadeFlag = state.dataSurface->SurfWinShadingFlag(SurfNum);
5968 656496 : FrDivNum = state.dataSurface->Surface(SurfNum).FrameDivider;
5969 656496 : auto const &thisConstruct = state.dataConstruction->Construct(ConstrNum);
5970 656496 : TotLayers = thisConstruct.TotLayers;
5971 656496 : TotGlassLayers = thisConstruct.TotSolidLayers;
5972 656496 : EmisGlassOut = dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(thisConstruct.LayerPoint(1)))->AbsorpThermalFront;
5973 656496 : EmisGlassIn =
5974 656496 : dynamic_cast<Material::MaterialChild const *>(state.dataMaterial->Material(thisConstruct.LayerPoint(TotLayers)))->AbsorpThermalBack;
5975 656496 : FrameHeatGain = 0.0;
5976 656496 : DividerHeatGain = 0.0;
5977 656496 : state.dataSurface->SurfWinFrameHeatGain(SurfNum) = 0.0;
5978 656496 : state.dataSurface->SurfWinFrameHeatLoss(SurfNum) = 0.0;
5979 656496 : state.dataSurface->SurfWinDividerHeatGain(SurfNum) = 0.0;
5980 656496 : state.dataSurface->SurfWinDividerHeatLoss(SurfNum) = 0.0;
5981 :
5982 656496 : if (state.dataSurface->SurfWinFrameArea(SurfNum) > 0.0) {
5983 : // Window has a frame. Note that if a shade, screen or blind is present it covers only the glazed part of the
5984 : // window and is assumed not to shadow long- or short-wave radiation incident on the frame elements.
5985 656496 : ProjCorrFrOut = state.dataSurface->SurfWinProjCorrFrOut(SurfNum);
5986 656496 : ProjCorrFrIn = state.dataSurface->SurfWinProjCorrFrIn(SurfNum);
5987 656496 : TOutRadFr = TOutRad * root_4((1.0 + 0.5 * ProjCorrFrOut) / (1.0 + ProjCorrFrOut));
5988 656496 : TInRadFr = TInRad * root_4((1.0 + 0.5 * ProjCorrFrIn) / (1.0 + ProjCorrFrIn));
5989 656496 : FrameCon = state.dataSurface->SurfWinFrameConductance(SurfNum);
5990 656496 : HInRad = 0.5 * state.dataSurface->SurfWinFrameEmis(SurfNum) * Constant::StefanBoltzmann *
5991 656496 : pow_3(TInRadFr + state.dataSurface->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin);
5992 656496 : HInConvFr = HInConv;
5993 656496 : HOutRad = 0.5 * state.dataSurface->SurfWinFrameEmis(SurfNum) * Constant::StefanBoltzmann *
5994 656496 : pow_3(TOutRadFr + state.dataSurface->SurfWinFrameTempSurfOut(SurfNum) + Constant::Kelvin);
5995 656496 : HOutConvFr = HOutConv;
5996 656496 : auto const &frdiv = state.dataSurface->FrameDivider(FrDivNum);
5997 656496 : if (frdiv.FrameProjectionOut > 0.0) {
5998 524016 : HOutRad *= (1.0 + ProjCorrFrOut);
5999 524016 : HOutConvFr = HOutConv * (1.0 + ProjCorrFrOut);
6000 : // Add long-wave from outside window surface absorbed by frame outside projection
6001 1048032 : state.dataSurface->SurfWinFrameQRadOutAbs(SurfNum) += 0.5 * state.dataSurface->SurfWinProjCorrFrOut(SurfNum) * frdiv.FrameEmis *
6002 524016 : EmisGlassOut * Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[1]);
6003 : }
6004 656496 : if (frdiv.FrameProjectionIn > 0.0) {
6005 524016 : HInRad *= (1.0 + ProjCorrFrIn);
6006 524016 : HInConvFr = HInConv * (1.0 + ProjCorrFrIn);
6007 : // Add long-wave from inside window surface absorbed by frame inside projection
6008 1048032 : state.dataSurface->SurfWinFrameQRadInAbs(SurfNum) += 0.5 * state.dataSurface->SurfWinProjCorrFrIn(SurfNum) * frdiv.FrameEmis *
6009 524016 : EmisGlassIn * Constant::StefanBoltzmann *
6010 524016 : pow_4(surfWin.thetaFace[2 * TotGlassLayers]);
6011 : }
6012 656496 : Afac = (HOutRad * TOutRadFr + HOutConvFr * tout + state.dataSurface->SurfWinFrameQRadOutAbs(SurfNum)) / (HOutRad + FrameCon + HOutConvFr);
6013 656496 : Bfac = FrameCon / (HOutRad + FrameCon + HOutConvFr);
6014 656496 : Dfac = (HInRad * TInRadFr + HInConvFr * tin + state.dataSurface->SurfWinFrameQRadInAbs(SurfNum)) / (HInRad + FrameCon + HInConvFr);
6015 656496 : Efac = FrameCon / (HInRad + FrameCon + HInConvFr);
6016 656496 : state.dataSurface->SurfWinFrameTempIn(SurfNum) = (Dfac + Efac * Afac) / (1.0 - Efac * Bfac) - Constant::Kelvin;
6017 656496 : state.dataSurface->SurfWinFrameTempSurfOut(SurfNum) =
6018 656496 : Afac + Bfac * (state.dataSurface->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin) - Constant::Kelvin;
6019 : // Heat gain to zone from frame
6020 :
6021 : // FrameHeatTransfer = state.dataSurface->SurfWinFrameArea(SurfNum) * FrameCon *
6022 : // (state.dataSurface->SurfWinFrameTempSurfOut(SurfNum) - state.dataSurface->SurfWinFrameTempIn(SurfNum));
6023 656496 : FrameHeatGain = state.dataSurface->SurfWinFrameArea(SurfNum) * (1.0 + state.dataSurface->SurfWinProjCorrFrIn(SurfNum)) *
6024 656496 : (HInConvFr * (state.dataSurface->SurfWinFrameTempIn(SurfNum) + Constant::Kelvin - tin));
6025 :
6026 656496 : if (FrameHeatGain > 0.0) {
6027 124274 : state.dataSurface->SurfWinFrameHeatGain(SurfNum) = FrameHeatGain;
6028 : } else {
6029 532222 : state.dataSurface->SurfWinFrameHeatLoss(SurfNum) = std::abs(FrameHeatGain);
6030 : }
6031 :
6032 656496 : state.dataSurface->SurfWinHeatGain(SurfNum) += FrameHeatGain;
6033 656496 : state.dataSurface->SurfWinGainFrameDividerToZoneRep(SurfNum) = FrameHeatGain;
6034 : } // End of check if window has a frame
6035 :
6036 656496 : if (state.dataSurface->SurfWinDividerArea(SurfNum) > 0.0 && state.dataSurface->SurfWinStormWinFlag(SurfNum) < 1) {
6037 : // Window has divider. Note that if the window has a storm window layer in place (StormWinFlag = 1)
6038 : // the divider heat transfer calculation is not done.
6039 :
6040 327888 : DivType = state.dataSurface->SurfWinDividerType(SurfNum);
6041 327888 : DivCon = state.dataSurface->SurfWinDividerConductance(SurfNum);
6042 :
6043 327888 : if (DivType == DataSurfaces::FrameDividerType::DividedLite) { // Divided lite
6044 298416 : DivEmisIn = state.dataSurface->SurfWinDividerEmis(SurfNum);
6045 298416 : DivEmisOut = DivEmisIn;
6046 : } else { // Suspended (between-glass) divider
6047 29472 : DivEmisOut = state.dataMaterial->Material(thisConstruct.LayerPoint(1))->AbsorpThermalFront;
6048 29472 : DivEmisIn = state.dataMaterial->Material(thisConstruct.LayerPoint(thisConstruct.TotLayers))->AbsorpThermalBack;
6049 : }
6050 :
6051 327888 : TOutRadDiv = TOutRad * root_4((1.0 + state.dataSurface->SurfWinProjCorrDivOut(SurfNum)) /
6052 327888 : (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivOut(SurfNum)));
6053 327888 : TInRadDiv = TInRad * root_4((1.0 + state.dataSurface->SurfWinProjCorrDivIn(SurfNum)) /
6054 327888 : (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum)));
6055 327888 : HInRad =
6056 327888 : 0.5 * DivEmisIn * Constant::StefanBoltzmann * pow_3(TInRadDiv + state.dataSurface->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin);
6057 655776 : HOutRad = 0.5 * DivEmisOut * Constant::StefanBoltzmann *
6058 327888 : pow_3(TOutRadDiv + state.dataSurface->SurfWinDividerTempSurfOut(SurfNum) + Constant::Kelvin);
6059 327888 : HOutConvDiv = HOutConv;
6060 327888 : auto const &frdiv = state.dataSurface->FrameDivider(FrDivNum);
6061 327888 : if (frdiv.DividerProjectionOut > 0.0) {
6062 225072 : HOutRad *= (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivOut(SurfNum));
6063 225072 : if (state.dataSurface->SurfWinShadingFlag(SurfNum) == WinShadingType::ExtShade)
6064 0 : HOutConvDiv = state.dataSurface->SurfWinConvCoeffWithShade(SurfNum);
6065 225072 : HOutConvDiv *= (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivOut(SurfNum));
6066 : // Add long-wave from outside window surface absorbed by divider outside projection
6067 450144 : state.dataSurface->SurfWinDividerQRadOutAbs(SurfNum) += state.dataSurface->SurfWinProjCorrDivOut(SurfNum) * frdiv.DividerEmis *
6068 225072 : EmisGlassOut * Constant::StefanBoltzmann * pow_4(surfWin.thetaFace[1]);
6069 : }
6070 :
6071 327888 : HInConvDiv = HInConv;
6072 :
6073 327888 : if (frdiv.DividerProjectionIn > 0.0) {
6074 225072 : HInRad *= (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum));
6075 225072 : if (state.dataSurface->SurfWinShadingFlag(SurfNum) == WinShadingType::IntShade)
6076 0 : HInConvDiv = state.dataSurface->SurfWinConvCoeffWithShade(SurfNum);
6077 225072 : HInConvDiv *= (1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum));
6078 : // Add long-wave from inside window surface absorbed by divider inside projection
6079 450144 : state.dataSurface->SurfWinDividerQRadInAbs(SurfNum) += state.dataSurface->SurfWinProjCorrDivIn(SurfNum) * frdiv.DividerEmis *
6080 225072 : EmisGlassIn * Constant::StefanBoltzmann *
6081 225072 : pow_4(surfWin.thetaFace[2 * TotGlassLayers]);
6082 : }
6083 327888 : Afac =
6084 327888 : (HOutRad * TOutRadDiv + HOutConvDiv * tout + state.dataSurface->SurfWinDividerQRadOutAbs(SurfNum)) / (HOutRad + DivCon + HOutConvDiv);
6085 327888 : Bfac = DivCon / (HOutRad + DivCon + HOutConvDiv);
6086 327888 : Dfac = (HInRad * TInRadDiv + HInConvDiv * tin + state.dataSurface->SurfWinDividerQRadInAbs(SurfNum)) / (HInRad + DivCon + HInConvDiv);
6087 327888 : Efac = DivCon / (HInRad + DivCon + HInConvDiv);
6088 327888 : state.dataSurface->SurfWinDividerTempIn(SurfNum) = (Dfac + Efac * Afac) / (1 - Efac * Bfac) - Constant::Kelvin;
6089 327888 : state.dataSurface->SurfWinDividerTempSurfOut(SurfNum) =
6090 327888 : Afac + Bfac * (state.dataSurface->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin) - Constant::Kelvin;
6091 : // Contribution of divider to window heat gain
6092 : // ProjCorrWinHeatGain = 1.0 + 2.0 * state.dataSurface->SurfWinProjCorrDivIn(SurfNum);
6093 :
6094 327888 : DividerHeatGain = state.dataSurface->SurfWinDividerArea(SurfNum) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(SurfNum)) *
6095 327888 : (HInConvDiv * (state.dataSurface->SurfWinDividerTempIn(SurfNum) + Constant::Kelvin - tin));
6096 : // DividerHeatTransfer = state.dataSurface->SurfWinDividerArea(SurfNum) * DivCon *
6097 : // (state.dataSurface->SurfWinDividerTempSurfOut(SurfNum) - state.dataSurface->SurfWinDividerTempIn(SurfNum));
6098 :
6099 327888 : if (DividerHeatGain > 0.0) {
6100 57657 : state.dataSurface->SurfWinDividerHeatGain(SurfNum) = DividerHeatGain;
6101 : } else {
6102 270231 : state.dataSurface->SurfWinDividerHeatLoss(SurfNum) = std::abs(DividerHeatGain);
6103 : }
6104 327888 : state.dataSurface->SurfWinHeatGain(SurfNum) += DividerHeatGain;
6105 327888 : state.dataSurface->SurfWinGainFrameDividerToZoneRep(SurfNum) += DividerHeatGain;
6106 : // If interior shade is present it is assumed that both the convective and IR radiative gain
6107 : // from the inside surface of the divider goes directly into the zone air -- i.e., the IR radiative
6108 : // interaction between divider and shade is ignored due to the difficulty of calculating this interaction
6109 : // at the same time that the interaction between glass and shade is calculated.
6110 327888 : if (ANY_INTERIOR_SHADE_BLIND(state.dataSurface->SurfWinShadingFlag(SurfNum)))
6111 742 : state.dataSurface->SurfWinDividerHeatGain(SurfNum) = DividerHeatGain;
6112 : // DivTempOut = state.dataSurface->SurfWinDividerTempSurfOut(SurfNum) + Constant::Kelvin;
6113 : } // End of check if window has dividers
6114 656496 : } // CalcWinFrameAndDividerTemps()
6115 :
6116 : //************************************************************************************
6117 :
6118 2676 : void CalcNominalWindowCond(EnergyPlusData &state,
6119 : int const ConstrNum, // Construction number
6120 : int const WinterSummerFlag, // 1=winter, 2=summer
6121 : Real64 &NominalConductance, // Nominal center-of-glass conductance, including air films
6122 : Real64 &SHGC, // Nominal center-of-glass solar heat gain coefficient for
6123 : Real64 &TSolNorm, // Overall beam solar transmittance at normal incidence
6124 : Real64 &TVisNorm, // Overall beam visible transmittance at normal incidence
6125 : int &errFlag // Error flag
6126 : )
6127 : {
6128 :
6129 : // SUBROUTINE INFORMATION:
6130 : // AUTHOR F. Winkelmann
6131 : // DATE WRITTEN September 2000
6132 : // MODIFIED Oct 2000, FW: add solar heat gain coefficient
6133 : // June 2001, FW: account for blinds; change summer outside air
6134 : // temp from 35.0C to 31.7C to correspond to ASHRAE value
6135 : // Feb 2003, FW: add comments that this routine is not called for
6136 : // between-glass shade/blind constructions.
6137 : // May 2006, RR: account for screens
6138 : // Oct 2007, LKL: change temps to match Window 5 values
6139 : // Feb 2009, BG: Changes for CR7682 (SHGC)
6140 : // RE-ENGINEERED na
6141 :
6142 : // PURPOSE OF THIS SUBROUTINE:
6143 : // Calculates nominal center-of-glass U-value and solar heat gain coefficient
6144 : // (SHGC) of a window construction for ASHRAE winter and summer conditions.
6145 : // Winter:
6146 : // Inside air temperature = 21.C (69.80F)
6147 : // Outside air temperature = -18C (-.4F)
6148 : // Windspeed = 5.5 m/s (12.3 mph)
6149 : // No solar radiation
6150 : // Replaced Winter:
6151 : // Inside air temperature = 21.1C (70F)
6152 : // Outside air temperature = -17.8C (0F)
6153 : // Windspeed = 6.71 m/s (15 mph)
6154 : // No solar radiation
6155 : // Summer:
6156 : // Inside air temperature = 24C (75.2F)
6157 : // Outside air temperature = 32C (89.6F)
6158 : // Windspeed = 2.8 m/s (6.2 mph)
6159 : // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
6160 : // Replaced Summer:
6161 : // Inside air temperature = 24C (75.2F) ! BG changed again Feb. 2009 by 0.1 (per Window5 team)
6162 : // Outside air temperature = 31.7C (89F)
6163 : // Windspeed = 3.35 m/s (7.5 mph)
6164 : // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
6165 : // The window's inside surround is assumed to be a black body at the inside air temp.
6166 : // The window's outside surround is assumed t be a black body at the outside air temp.
6167 : // Note that in this routine we use a value of 26 W/m2 for the outside convective
6168 : // air film conductance for 5.5 m/s (12.3 mph) wind speed.
6169 : // This is the value used in Window 5 and is also the value for which the center-of-glass
6170 : // conductances in the EnergyPlus window construction reference data set were calculated.
6171 : // However, in the time step loop we will have different values of outside film
6172 : // conductance depending on that time step's wind speed, wind direction, surface-to-air temp difference,
6173 : // etc.(see subroutine InitExteriorConvectionCoeff).
6174 : // This routine will return an error and exit for window constructions with between-glass shade or blind
6175 : // until a method is worked out to determine the nominal conductance and SHGC in this case.
6176 : // If an interior or exterior shade or blind is present in the construction,
6177 : // the conductance calculation does not include the effect of the shade or blind.
6178 : // This is because in this case the conductance depends on the natural convective
6179 : // air flow in the shade/glass, screen/glass or blind/glass channel, which in turn is highly dependent
6180 : // on window height and other parameters that are not part of the construction definition.
6181 : // Therefore, the reported conductance value will be too high for windows with a tightly fitting
6182 : // shade, screen or blind with a relatively high thermal resistance.
6183 : // For SHGC calculation, all solar absorbed by interior blind or shade is assumed
6184 : // to go into zone air. (This is not true in general; the fraction of this absorbed solar that
6185 : // is conducted back out is accounted for in the time-step glazing calculation.)
6186 : // For CR 7682, the SHGC calculations were changed to model the absorbed solar arriving at the middle of the layer
6187 : // rather than at the outer face of the layer. The resistances changed by one half the glazing layer, or 0.5/scon(n).
6188 : // (CR 7682 also changed WindowTempsForNominalCond to include absorbed solar, a bigger change)
6189 :
6190 : // Using/Aliasing
6191 : using General::POLYF;
6192 :
6193 : // Locals
6194 : // SUBROUTINE ARGUMENT DEFINITIONS:
6195 : // normal incidence beam solar radiation
6196 :
6197 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6198 : int TotLay; // Total number of layers in a construction
6199 : // (sum of solid layers and gap layers)
6200 : int TotGlassLay; // Total number of glass layers in a construction
6201 : int Lay; // Layer number
6202 : int LayPtr; // Material number for a layer
6203 :
6204 : Real64 BeamSolarInc; // Incident beam radiation at zero angle of incidence (W/m2)
6205 : // Real64 hOutRad; // Radiative conductance of outside and inside airfilm [W/m2-K]
6206 : // Real64 hInRad;
6207 : // Real64 rOut; // Combined radiative and conductive outside and inside film
6208 : // Real64 rIn;
6209 : // resistance [m2-K/W]
6210 : Array1D<Real64> hgap(
6211 2676 : maxGlassLayers); // Conductive gap conductance [W/m2-K]
6212 : // Array1D<Real64> hGapTot(5); // Combined radiative and conductive gap conductance [W/m2-K]
6213 : // Real64 Rbare; // Nominal center-of-glass resistance without air films [m2-K/W]
6214 : WinShadingType ShadeFlag; // Shading flag
6215 : Real64 ShadeRes; // Thermal resistance of shade
6216 : int MatOutside; // Material number of outside layer of construction
6217 : int MatInside; // Material number of inside layer of construction
6218 : int MatShade; // Material number of shade layer
6219 2676 : Array1D<Real64> AbsBeamNorm(maxGlassLayers); // Beam absorptance at normal incidence for each glass layer
6220 : Real64 AbsBeamShadeNorm; // Shade solar absorptance at normal incidence
6221 : int ConstrNum1; // Construction counter
6222 : int ConstrNumBare; // Construction without shading device
6223 : int BlNum; // Blind number
6224 : int ScNum; // Screen number
6225 : bool VarSlats; // True if slats in blind are variable angle
6226 : Real64 SlatAng; // Slat angle (rad)
6227 : int LayPtrSh; // Layer pointer of blind
6228 : Real64 TBmBm; // Bare glass normal incidence beam-beam transmittance
6229 : Real64 TBmBmVis;
6230 : Real64 TBlBmBm; // Normal incidence blind beam-beam transmittance
6231 : Real64 TScBmBm; // Screen incident beam-beam transmittance
6232 : Real64 TScBmBmVis;
6233 : Real64 TBmBmBl; // TBmBm * TBlBmBm, TBmBmVis * TBlBmBm
6234 : Real64 TBmBmBlVis;
6235 : Real64 RGlDiffBack; // Bare glass back sol/vis reflectance
6236 : Real64 RGlDiffBackVis;
6237 : Real64 RGlDiffFront; // Bare glass front sol/vis reflectance
6238 : Real64 RGlDiffFrontVis;
6239 : Real64 RhoBlFront; // Blind normal front beam-diffuse sol/vis reflectance
6240 : Real64 RhoBlFrontVis;
6241 : Real64 RhoBlBack; // Blind normal back beam-diffuse sol/vis reflectance
6242 : Real64 RhoBlBackVis;
6243 : Real64 RScBack; // Screen back beam-diffuse sol/vis reflectance (same as front)
6244 : Real64 RScBackVis;
6245 : Real64 AbsBlFront; // Blind normal front beam solar absorptance
6246 : Real64 AbsBlBack; // Blind normal back beam solar absorptance
6247 : Real64 RhoBlDiffFront; // Blind front diffuse-diffuse sol/vis reflectance
6248 : Real64 RhoBlDiffFrontVis;
6249 : Real64 AbsBlDiffFront; // Blind front diffuse solar absorptance
6250 : Real64 AbsBlDiffBack; // Blind back diffuse solar absorptance
6251 : Real64 RGlFront; // Bare glass normal front beam sol/vis reflectance
6252 : Real64 RGlFrontVis;
6253 : Real64 RhoBlDiffBack; // Blind back diffuse-diffuse sol/vis reflectance
6254 : Real64 RhoBlDiffBackVis;
6255 : Real64 RScDifBack; // Screen back diffuse-diffuse sol/vis reflectance (doesn't change with sun angle)
6256 : Real64 RScDifBackVis;
6257 : Real64 TBlBmDif; // Blind front normal beam-diffuse sol/vis transmittance
6258 : Real64 TBlBmDifVis;
6259 : Real64 TBlDifDif; // Blind front diffuse-diffuse sol/vis transmittance
6260 : Real64 TBlDifDifVis;
6261 : Real64 TScBmDif; // Screen front beam-diffuse sol/vis transmittance
6262 : Real64 TScBmDifVis;
6263 : Real64 TDif; // Bare glass diffuse sol/vis transmittance
6264 : Real64 TDifVis;
6265 : Real64 AGlDiffBack; // Back diffuse solar absorptance of a glass layer
6266 :
6267 2676 : auto &wm = state.dataWindowManager;
6268 : // Autodesk:Uninit Initialize variables used uninitialized
6269 : // Rbare = 0.0; // Autodesk:Uninit Force default initialization
6270 :
6271 2676 : NominalConductance = 0.0;
6272 2676 : errFlag = 0;
6273 2676 : TotLay = state.dataConstruction->Construct(ConstrNum).TotLayers;
6274 2676 : TotGlassLay = state.dataConstruction->Construct(ConstrNum).TotGlassLayers;
6275 2676 : wm->ngllayer = TotGlassLay; // Autodesk:Uninit This routine needs to check/enforce 1<=ngllayer<=4
6276 : // EPTeam - believe that is done on input.
6277 2676 : wm->nglface = 2 * wm->ngllayer;
6278 2676 : wm->tilt = 90.0; // Assume vertical window
6279 :
6280 2676 : if (WinterSummerFlag == 1) { // Winter
6281 : // LKL Oct 2007: According to Window5, Winter environmental conditions are:
6282 1350 : wm->tin = 294.15; // Inside air temperature (69.8F, 21.C)
6283 1350 : wm->tout = 255.15; // Outside air temperature (-.4F, -18C)
6284 1350 : wm->hcout = 26.0; // Outside convective film conductance for 5.5 m/s (12.3 mph) wind speed
6285 : // (the value used in Window 5)
6286 : // tin = 294.26 ! Inside air temperature (70F, 21.1C)
6287 : // tout = 255.35 ! Outside air temperature (0F, -17.8C)
6288 : // hcout = 25.47 ! Outside convective film conductance for 6.71 m/s (15 mph) wind speed
6289 : // ! (the value used in Window 4)
6290 1350 : BeamSolarInc = 0.0;
6291 : } else { // Summer
6292 : // LKL Oct 2007: According to Window5, Summer environmental conditions are:
6293 : // tin = 297.05d0 ! Inside air temperature (75.2F, 24C)
6294 : // BG Feb. 2009: According to Window5 Expert Christian Kohler, it is exactly 24C or 297.15
6295 1326 : wm->tin = 297.15;
6296 1326 : wm->tout = 305.15; // Outside air temperature (89.6F, 32C)
6297 1326 : wm->hcout = 15.0; // Outside convective film conductance for 2.8 m/s (6.2 mph) wind speed
6298 : // (the value used in Window 5)
6299 : // tin = 297.05 ! Inside air temperature (75F, 23.9C)
6300 : // !tout = 308.15 ! Outside air temperature (95F, 35.0C)
6301 : // ! Changed 6/20/01 by FCW to make consistent with Window 4 and 5.
6302 : // tout = 304.82 ! Outside air temperature (89F, 31.7C)
6303 : // hcout = 18.86 ! Outside convective film conductance for 3.35 m/s (7.5 mph) wind speed
6304 : // ! (average of Window 4 0 m/s and 6.71 m/s values)
6305 1326 : BeamSolarInc = 783.0;
6306 : }
6307 :
6308 : // IR incident on inside of glazing (inside surround assumed to be
6309 : // a black body at inside air temperature)
6310 2676 : wm->Rmir = Constant::StefanBoltzmann * pow_4(wm->tin);
6311 :
6312 : // IR incident on outside of glazing
6313 : // (outside surround is assumed to be a black body at outside air temperature)
6314 2676 : wm->Outir = Constant::StefanBoltzmann * pow_4(wm->tout);
6315 :
6316 : // Determine whether construction has an exterior or interior shade or blind
6317 2676 : ShadeFlag = WinShadingType::NoShade;
6318 2676 : ShadeRes = 0.0;
6319 2676 : MatOutside = state.dataConstruction->Construct(ConstrNum).LayerPoint(1);
6320 2676 : MatInside = state.dataConstruction->Construct(ConstrNum).LayerPoint(TotLay);
6321 2676 : if (state.dataMaterial->Material(MatOutside)->group == Material::Group::Shade) { // Exterior shade present
6322 5 : MatShade = MatOutside;
6323 5 : ShadeFlag = WinShadingType::ExtShade;
6324 : // Set glazing outside convection coefficient to Window 4 still-air value
6325 5 : wm->hcout = 12.25;
6326 2671 : } else if (state.dataMaterial->Material(MatOutside)->group == Material::Group::Screen) { // Exterior screen present
6327 4 : MatShade = MatOutside;
6328 4 : ShadeFlag = WinShadingType::ExtScreen;
6329 4 : wm->hcout = 12.25;
6330 2667 : } else if (state.dataMaterial->Material(MatOutside)->group == Material::Group::WindowBlind) { // Exterior blind present
6331 4 : MatShade = MatOutside;
6332 4 : ShadeFlag = WinShadingType::ExtBlind;
6333 4 : BlNum = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(MatShade))->BlindDataPtr;
6334 4 : wm->hcout = 12.25;
6335 2663 : } else if (state.dataMaterial->Material(MatInside)->group == Material::Group::Shade) { // Interior shade present
6336 40 : MatShade = MatInside;
6337 40 : ShadeFlag = WinShadingType::IntShade;
6338 2623 : } else if (state.dataMaterial->Material(MatInside)->group == Material::Group::WindowBlind) { // Interior blind present
6339 23 : MatShade = MatInside;
6340 23 : BlNum = dynamic_cast<Material::MaterialChild *>(state.dataMaterial->Material(MatShade))->BlindDataPtr;
6341 23 : ShadeFlag = WinShadingType::IntBlind;
6342 2600 : } else if (TotGlassLay == 2) {
6343 982 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3))->group == Material::Group::Shade)
6344 1 : ShadeFlag = WinShadingType::BGShade;
6345 982 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(3))->group == Material::Group::WindowBlind)
6346 2 : ShadeFlag = WinShadingType::BGBlind;
6347 1618 : } else if (TotGlassLay == 3) {
6348 132 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5))->group == Material::Group::Shade)
6349 1 : ShadeFlag = WinShadingType::BGShade;
6350 132 : if (state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(5))->group == Material::Group::WindowBlind)
6351 1 : ShadeFlag = WinShadingType::BGBlind;
6352 : }
6353 :
6354 2676 : if (ANY_BETWEENGLASS_SHADE_BLIND(ShadeFlag)) {
6355 5 : errFlag = 2;
6356 5 : return;
6357 : }
6358 :
6359 2671 : TSolNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransSolBeamCoef);
6360 2671 : TVisNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).TransVisBeamCoef);
6361 2671 : AbsBeamShadeNorm = 0.0;
6362 2671 : if (ShadeFlag == WinShadingType::IntShade || ShadeFlag == WinShadingType::ExtShade) { // Exterior or interior shade on
6363 45 : AbsBeamShadeNorm = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamShadeCoef);
6364 : // Exterior blind or screen or interior blind on
6365 2626 : } else if (ShadeFlag == WinShadingType::IntBlind || ShadeFlag == WinShadingType::ExtBlind || ShadeFlag == WinShadingType::ExtScreen) {
6366 : // Find unshaded construction that goes with this construction w/blind or screen
6367 31 : ConstrNumBare = 0;
6368 197 : for (int ConstrNum1 = 1; ConstrNum1 <= state.dataHeatBal->TotConstructs; ++ConstrNum1) {
6369 197 : if (ConstrNum1 != ConstrNum && state.dataConstruction->Construct(ConstrNum1).TypeIsWindow &&
6370 429 : state.dataConstruction->Construct(ConstrNum1).TotGlassLayers == state.dataConstruction->Construct(ConstrNum1).TotSolidLayers &&
6371 35 : state.dataConstruction->Construct(ConstrNum1).TotGlassLayers == state.dataConstruction->Construct(ConstrNum).TotGlassLayers) {
6372 : // We have an unshaded window construction with the same number of glass layers as ConstrNum;
6373 : // see if the glass and gas layers match
6374 33 : ConstrNumBare = ConstrNum1;
6375 70 : for (int Lay = 1; Lay <= state.dataConstruction->Construct(ConstrNum1).TotLayers; ++Lay) {
6376 37 : LayPtr = state.dataConstruction->Construct(ConstrNum1).LayerPoint(Lay);
6377 37 : if (ShadeFlag == WinShadingType::IntBlind) { // The shaded construction has an interior blind
6378 23 : LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
6379 : } else { // The shaded construction has an exterior blind or screen
6380 14 : LayPtrSh = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay + 1);
6381 : }
6382 37 : if (LayPtrSh != LayPtr) ConstrNumBare = 0;
6383 : }
6384 33 : if (ConstrNumBare != 0) break;
6385 : }
6386 : }
6387 31 : if (ConstrNumBare == 0) {
6388 : // No matching bare construction found for this construction with blind or screen
6389 0 : errFlag = 1;
6390 0 : return;
6391 : }
6392 :
6393 31 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6394 31 : TBmBm = POLYF(1.0, constructBare.TransSolBeamCoef);
6395 31 : TBmBmVis = POLYF(1.0, constructBare.TransVisBeamCoef);
6396 31 : if (ShadeFlag == WinShadingType::ExtScreen) {
6397 : // Don't need to call subroutine, use normal incident properties (SUBROUTINE CalcNominalWindowCond)
6398 : // Last call to CalcScreenTransmittance(ISurf) was done at direct normal angle (0,0) in CalcWindowScreenProperties
6399 4 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(state.dataMaterial->Material(MatShade));
6400 4 : assert(matScreen != nullptr);
6401 4 : auto const &btar = matScreen->btars[0][0];
6402 4 : TScBmBm = btar.BmTrans;
6403 4 : TScBmBmVis = btar.BmTransVis;
6404 4 : TScBmDif = btar.DfTrans;
6405 4 : TScBmDifVis = btar.DfTransVis;
6406 4 : TDif = constructBare.TransDiff;
6407 4 : TDifVis = constructBare.TransDiffVis;
6408 4 : RScBack = matScreen->ShadeRef;
6409 4 : RScBackVis = matScreen->ShadeRefVis;
6410 4 : RScDifBack = matScreen->DfRef;
6411 4 : RScDifBackVis = matScreen->DfRefVis;
6412 4 : RGlFront = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6413 4 : RGlFrontVis = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6414 4 : RGlDiffFront = constructBare.ReflectSolDiffFront;
6415 4 : RGlDiffFrontVis = constructBare.ReflectVisDiffFront;
6416 4 : TSolNorm = TScBmBm * (TBmBm + TDif * RGlFront * RScBack / (1 - RGlDiffFront * RScDifBack)) +
6417 4 : TScBmDif * TDif / (1 - RGlDiffFront * RScDifBack);
6418 4 : TVisNorm = TScBmBmVis * (TBmBmVis + TDifVis * RGlFrontVis * RScBackVis / (1 - RGlDiffFrontVis * RScDifBackVis)) +
6419 4 : TScBmDifVis * TDifVis / (1 - RGlDiffFrontVis * RScDifBackVis);
6420 : } else {
6421 27 : auto const &blind = state.dataMaterial->Blind(BlNum);
6422 27 : VarSlats = false;
6423 27 : if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Variable) VarSlats = true;
6424 27 : SlatAng = blind.SlatAngle * Constant::DegToRadians;
6425 27 : TBlBmBm = BlindBeamBeamTrans(0.0, SlatAng, blind.SlatWidth, blind.SlatSeparation, blind.SlatThickness);
6426 27 : TBmBmBl = TBmBm * TBlBmBm;
6427 27 : TBmBmBlVis = TBmBmVis * TBlBmBm;
6428 27 : TBlBmDif = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolFrontBeamDiffTrans);
6429 27 : TBlBmDifVis = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.VisFrontBeamDiffTrans);
6430 27 : TDif = constructBare.TransDiff;
6431 27 : TDifVis = constructBare.TransDiffVis;
6432 27 : if (ShadeFlag == WinShadingType::IntBlind) {
6433 23 : RGlDiffBack = constructBare.ReflectSolDiffBack;
6434 23 : RGlDiffBackVis = constructBare.ReflectVisDiffBack;
6435 23 : RhoBlFront = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolFrontBeamDiffRefl);
6436 23 : RhoBlFrontVis = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.VisFrontBeamDiffRefl);
6437 23 : AbsBlFront = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolFrontBeamAbs);
6438 23 : RhoBlDiffFront = InterpSlatAng(SlatAng, VarSlats, blind.SolFrontDiffDiffRefl);
6439 23 : RhoBlDiffFrontVis = InterpSlatAng(SlatAng, VarSlats, blind.VisFrontDiffDiffRefl);
6440 23 : AbsBlDiffFront = InterpSlatAng(SlatAng, VarSlats, blind.SolFrontDiffAbs);
6441 23 : AbsBeamShadeNorm = TBmBm * (AbsBlFront + RhoBlFront * RGlDiffBack * AbsBlDiffFront / (1.0 - RhoBlDiffFront * RGlDiffBack));
6442 23 : TBlDifDif = InterpSlatAng(SlatAng, VarSlats, blind.SolFrontDiffDiffTrans);
6443 23 : TBlDifDifVis = InterpSlatAng(SlatAng, VarSlats, blind.VisFrontDiffDiffTrans);
6444 23 : TSolNorm = TBmBm * (TBlBmBm + TBlBmDif + TBlDifDif * RhoBlFront * RGlDiffBack / (1.0 - RhoBlDiffFront * RGlDiffBack));
6445 : // use of TBlBmBm here is correct, visible and IR transmittance are the same (reference deleted CR6925 on 3/20/2006)
6446 23 : TVisNorm = TBmBmVis *
6447 23 : (TBlBmBm + TBlBmDifVis + TBlDifDifVis * RhoBlFrontVis * RGlDiffBackVis / (1.0 - RhoBlDiffFrontVis * RGlDiffBackVis));
6448 : } // (IntBlind)
6449 27 : if (ShadeFlag == WinShadingType::ExtBlind) {
6450 4 : TBlBmBm = BlindBeamBeamTrans(0.0, SlatAng, blind.SlatWidth, blind.SlatSeparation, blind.SlatThickness);
6451 4 : RGlFront = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6452 4 : RGlFrontVis = POLYF(1.0, constructBare.ReflSolBeamFrontCoef);
6453 4 : AbsBlFront = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolFrontBeamAbs);
6454 4 : AbsBlBack = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolBackBeamAbs);
6455 4 : AbsBlDiffBack = InterpSlatAng(SlatAng, VarSlats, blind.SolBackDiffAbs);
6456 4 : RGlDiffFront = constructBare.ReflectSolDiffFront;
6457 4 : RGlDiffFrontVis = constructBare.ReflectVisDiffFront;
6458 4 : RhoBlDiffBack = InterpSlatAng(SlatAng, VarSlats, blind.SolBackDiffDiffRefl);
6459 4 : RhoBlDiffBackVis = InterpSlatAng(SlatAng, VarSlats, blind.VisBackDiffDiffRefl);
6460 4 : RhoBlBack = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolBackBeamDiffRefl);
6461 4 : RhoBlBackVis = InterpProfSlatAng(0.0, SlatAng, VarSlats, blind.SolBackBeamDiffRefl);
6462 4 : AbsBeamShadeNorm =
6463 4 : AbsBlFront + AbsBlBack * RGlFront * TBlBmBm +
6464 4 : (AbsBlDiffBack * RGlDiffFront / (1.0 - RhoBlDiffBack * RGlDiffFront)) * (RGlFront * TBlBmBm * RhoBlBack + TBlBmDif);
6465 4 : RGlDiffFront = constructBare.ReflectSolDiffFront;
6466 4 : TSolNorm = TBlBmBm * (TBmBm + TDif * RGlFront * RhoBlBack / (1 - RGlDiffFront * RhoBlDiffBack)) +
6467 4 : TBlBmDif * TDif / (1.0 - RGlDiffFront * RhoBlDiffBack);
6468 4 : TVisNorm = TBlBmBm * (TBmBmVis + TDifVis * RGlFrontVis * RhoBlBackVis / (1 - RGlDiffFrontVis * RhoBlDiffBackVis)) +
6469 4 : TBlBmDifVis * TDifVis / (1.0 - RGlDiffFrontVis * RhoBlDiffBackVis);
6470 : } // (ExtBlind)
6471 : } // (Screen or Blind)
6472 : } // (Shade, Blind, or Screen)
6473 :
6474 : // Fill the layer properties needed for the thermal calculation.
6475 :
6476 : // The layer and face numbering are as follows (for the triple glazing case):
6477 : // Glass layers are 1,2 and 3, where 1 is the outside (outside environment facing)
6478 : // layer and 3 is the inside (room-facing) layer;
6479 : // Faces (also called surfaces) are 1,2,3,4,5 and 6, where face 1 is the
6480 : // outside (front) face of glass layer 1, face 2 is the inside (back)
6481 : // face of glass layer 1, face 3 is the outer face of glass layer 2, face 4 is the
6482 : // inner face of glass layer 2, etc.
6483 : // Gap layers are 1 and 2, where gap layer 1 is between glass layers 1 and 2
6484 : // and gap layer 2 is between glass layers 2 and 3.
6485 :
6486 2671 : int IGlass = 0;
6487 2671 : int IGap = 0;
6488 :
6489 8062 : for (int Lay = 1; Lay <= TotLay; ++Lay) {
6490 5391 : LayPtr = state.dataConstruction->Construct(ConstrNum).LayerPoint(Lay);
6491 5391 : auto const *mat = state.dataMaterial->Material(LayPtr);
6492 :
6493 5391 : if ((mat->group == Material::Group::WindowGlass) || (mat->group == Material::Group::WindowSimpleGlazing)) {
6494 3979 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
6495 3979 : assert(thisMaterial != nullptr);
6496 :
6497 3979 : ++IGlass;
6498 3979 : wm->thick[IGlass - 1] = thisMaterial->Thickness;
6499 3979 : wm->scon[IGlass - 1] = thisMaterial->Conductivity / thisMaterial->Thickness;
6500 3979 : wm->emis[2 * IGlass - 2] = thisMaterial->AbsorpThermalFront;
6501 3979 : wm->emis[2 * IGlass - 1] = thisMaterial->AbsorpThermalBack;
6502 3979 : wm->tir[2 * IGlass - 2] = thisMaterial->TransThermal;
6503 3979 : wm->tir[2 * IGlass - 1] = thisMaterial->TransThermal;
6504 3979 : AbsBeamNorm(IGlass) = POLYF(1.0, state.dataConstruction->Construct(ConstrNum).AbsBeamCoef(IGlass));
6505 3979 : if (ShadeFlag == WinShadingType::IntBlind) { // Interior blind on
6506 23 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6507 23 : AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
6508 23 : AGlDiffBack = constructBare.AbsDiffBack(IGlass);
6509 23 : AbsBeamNorm(IGlass) += TBmBm * AGlDiffBack * RhoBlFront / (1.0 - RhoBlFront * RGlDiffBack);
6510 3956 : } else if (ShadeFlag == WinShadingType::ExtBlind) { // Exterior blind on
6511 4 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6512 4 : AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
6513 8 : AbsBeamNorm(IGlass) = TBlBmBm * AbsBeamNorm(IGlass) + (TBlBmBm * RGlFront * RhoBlBack + TBlBmDif) *
6514 4 : constructBare.AbsDiff(IGlass) / (1.0 - RGlDiffFront * RhoBlDiffBack);
6515 3952 : } else if (ShadeFlag == WinShadingType::ExtScreen) { // Exterior screen on
6516 6 : auto const &constructBare = state.dataConstruction->Construct(ConstrNumBare);
6517 6 : AbsBeamNorm(IGlass) = POLYF(1.0, constructBare.AbsBeamCoef(IGlass));
6518 12 : AbsBeamNorm(IGlass) = TScBmBm * AbsBeamNorm(IGlass) + (TScBmBm * RGlFront * RScBack + TScBmDif) * constructBare.AbsDiff(IGlass) /
6519 6 : (1.0 - RGlDiffFront * RScDifBack);
6520 : }
6521 3979 : wm->AbsRadGlassFace[2 * IGlass - 2] = 0.5 * BeamSolarInc * AbsBeamNorm(IGlass);
6522 3979 : wm->AbsRadGlassFace[2 * IGlass - 1] = 0.5 * BeamSolarInc * AbsBeamNorm(IGlass);
6523 : }
6524 5391 : if (mat->group == Material::Group::WindowGas || mat->group == Material::Group::WindowGasMixture ||
6525 4098 : mat->group == Material::Group::ComplexWindowGap) { // Gap layer
6526 1322 : ++IGap;
6527 : // Simon: Need to re-reference gas data in casee of complex fenestration gap
6528 1322 : if (mat->group == Material::Group::ComplexWindowGap) {
6529 29 : auto const *matCW = dynamic_cast<Material::MaterialChild const *>(mat);
6530 29 : assert(matCW != nullptr);
6531 29 : LayPtr = matCW->GasPointer;
6532 : }
6533 1322 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(state.dataMaterial->Material(LayPtr));
6534 1322 : assert(matGas != nullptr);
6535 1322 : wm->gaps[IGap - 1].width = matGas->Thickness;
6536 1322 : wm->gaps[IGap - 1].numGases = matGas->numGases;
6537 2680 : for (int IMix = 0; IMix < wm->gaps[IGap - 1].numGases; ++IMix) {
6538 1358 : wm->gaps[IGap - 1].gases[IMix] = matGas->gases[IMix];
6539 1358 : wm->gaps[IGap - 1].gasFracts[IMix] = matGas->gasFracts[IMix];
6540 : }
6541 : }
6542 : } // for (Lay)
6543 :
6544 : // Factors used in glass temperature solution
6545 2671 : if (wm->ngllayer >= 2) {
6546 1152 : wm->A23P = -wm->emis[2] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
6547 1152 : wm->A32P = wm->emis[1] / (1.0 - (1.0 - wm->emis[1]) * (1.0 - wm->emis[2]));
6548 1152 : wm->A23 = wm->emis[1] * Constant::StefanBoltzmann * wm->A23P;
6549 : }
6550 :
6551 2671 : if (wm->ngllayer >= 3) {
6552 144 : wm->A45P = -wm->emis[4] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
6553 144 : wm->A54P = wm->emis[3] / (1.0 - (1.0 - wm->emis[3]) * (1.0 - wm->emis[4]));
6554 144 : wm->A45 = wm->emis[3] * Constant::StefanBoltzmann * wm->A45P;
6555 : }
6556 :
6557 2671 : if (wm->ngllayer == 4) {
6558 12 : wm->A67P = -wm->emis[6] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
6559 12 : wm->A76P = wm->emis[5] / (1.0 - (1.0 - wm->emis[5]) * (1.0 - wm->emis[6]));
6560 12 : wm->A67 = wm->emis[5] * Constant::StefanBoltzmann * wm->A67P;
6561 : }
6562 :
6563 2671 : wm->thetas = {0.0};
6564 :
6565 2671 : WindowTempsForNominalCond(state, ConstrNum, hgap, 1.0);
6566 :
6567 2671 : if (!ANY_INTERIOR_SHADE_BLIND(ShadeFlag)) AbsBeamShadeNorm = 0.0;
6568 :
6569 : // Get center-of-glass conductance and solar heat gain coefficient
6570 : // including inside and outside air films
6571 2671 : Real64 inputU = state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->SimpleWindowUfactor;
6572 :
6573 : // Calculate the NominalConductance glazing only (before adjusted)
6574 2671 : EvalNominalWindowCond(state, AbsBeamShadeNorm, AbsBeamNorm, hgap, NominalConductance, SHGC, TSolNorm);
6575 :
6576 2671 : if (WinterSummerFlag == 1) {
6577 1345 : state.dataHeatBal->NominalUBeforeAdjusted(ConstrNum) = NominalConductance;
6578 1345 : if (inputU > 0) { // only compute adjustment ratio when there is valid user input U
6579 132 : Real64 wettedAreaAdjRatio = 1; // Adjustment ratio for the wetted area
6580 132 : Real64 hcoutRated = wm->hcout;
6581 : // Adjustment ratio applies to convective film coefficients when input U value is above the limit of the simple glazing nominal U
6582 : // Representing the nominal highly conductive frame effects. Solved iteratively.
6583 132 : Real64 adjLower = 1.0;
6584 132 : Real64 adjUpper = 2.0;
6585 132 : int MaxIter = 100;
6586 148 : while (std::abs(inputU - NominalConductance) > 0.01 && MaxIter > 0) {
6587 16 : wettedAreaAdjRatio = (adjLower + adjUpper) / 2;
6588 16 : WindowTempsForNominalCond(
6589 : state, ConstrNum, hgap, wettedAreaAdjRatio); // reeval hcout at each iteration, hcin is not linear to wetted area
6590 16 : wm->hcout = hcoutRated * wettedAreaAdjRatio; // reeval hcout
6591 16 : EvalNominalWindowCond(state, AbsBeamShadeNorm, AbsBeamNorm, hgap, NominalConductance, SHGC, TSolNorm);
6592 16 : if (NominalConductance < inputU) {
6593 5 : adjLower = wettedAreaAdjRatio;
6594 : } else {
6595 11 : adjUpper = wettedAreaAdjRatio;
6596 : }
6597 16 : MaxIter -= 1;
6598 : }
6599 132 : state.dataHeatBal->CoeffAdjRatio(ConstrNum) = wettedAreaAdjRatio;
6600 : }
6601 : }
6602 :
6603 : // EPTeam - again -- believe that is enforced in input //Autodesk But this routine is not self-protecting: Add as an assert
6604 :
6605 : // init the surface convective and radiative adjustment ratio
6606 34141 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
6607 62988 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
6608 31518 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
6609 31518 : int const firstSurfWin = thisSpace.WindowSurfaceFirst;
6610 31518 : int const lastSurfWin = thisSpace.WindowSurfaceLast;
6611 101025 : for (int SurfNum = firstSurfWin; SurfNum <= lastSurfWin; ++SurfNum) {
6612 69507 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == ExternalEnvironment) {
6613 69475 : int ConstrNum2 = state.dataSurface->Surface(SurfNum).Construction;
6614 69475 : state.dataHeatBalSurf->SurfWinCoeffAdjRatio(SurfNum) = state.dataHeatBal->CoeffAdjRatio(ConstrNum2);
6615 : }
6616 : }
6617 31470 : }
6618 : }
6619 :
6620 : // Need to add variables writing here since this routine will override previously calcualted values from WinCalc-Engine
6621 2671 : if (wm->inExtWindowModel->isExternalLibraryModel()) {
6622 3 : TSolNorm = GetSolarTransDirectHemispherical(state, ConstrNum);
6623 3 : TVisNorm = GetVisibleTransDirectHemispherical(state, ConstrNum);
6624 : }
6625 2681 : } // CalcNominalWindowCond()
6626 :
6627 2687 : void EvalNominalWindowCond(EnergyPlusData &state,
6628 : Real64 const AbsBeamShadeNorm, // Shade solar absorptance at normal incidence
6629 : Array1D<Real64> const AbsBeamNorm, // Beam absorptance at normal incidence for each glass layer
6630 : Array1D<Real64> const hgap, // Conductive gap conductance [W/m2-K]
6631 : Real64 &NominalConductance, // Nominal center-of-glass conductance, including air films
6632 : Real64 &SHGC, // Nominal center-of-glass solar heat gain coefficient for
6633 : Real64 &TSolNorm // Overall beam solar transmittance at normal incidence
6634 : )
6635 : {
6636 2687 : Array1D<Real64> hGapTot(5); // Combined radiative and conductive gap conductance [W/m2-K]
6637 :
6638 2687 : auto &wm = state.dataWindowManager;
6639 2687 : Real64 hOutRad = wm->emis[0] * Constant::StefanBoltzmann * 0.5 * pow_3(wm->tout + wm->thetas[0]);
6640 2687 : Real64 rOut = 1.0 / (hOutRad + wm->hcout);
6641 2687 : Real64 hInRad = wm->emis[wm->nglface - 1] * Constant::StefanBoltzmann * 0.5 * pow_3(wm->tin + wm->thetas[wm->nglface - 1]);
6642 2687 : Real64 rIn = 1.0 / (hInRad + wm->hcin);
6643 2687 : Real64 Rbare = 0;
6644 :
6645 2687 : switch (wm->ngllayer) {
6646 : // the switch cases here are just the integer number of layers, not exactly "magic" numbers 1, 2, 3. and 4.
6647 1535 : case 1: {
6648 1535 : Rbare = 1.0 / wm->scon[0];
6649 1535 : wm->Rtot = rOut + Rbare + rIn;
6650 1535 : SHGC = AbsBeamNorm(1) * (rOut + (0.5 / wm->scon[0])) / wm->Rtot; // BG changed for CR7682 (solar absorbed in middle of layer)
6651 1535 : SHGC += AbsBeamShadeNorm;
6652 1535 : SHGC += TSolNorm;
6653 1535 : } break;
6654 :
6655 1008 : case 2: {
6656 1008 : hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
6657 1008 : Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1];
6658 1008 : wm->Rtot = rOut + Rbare + rIn;
6659 1008 : SHGC = AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
6660 1008 : AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot; // CR7682
6661 1008 : SHGC += AbsBeamShadeNorm;
6662 1008 : SHGC += TSolNorm;
6663 1008 : } break;
6664 :
6665 132 : case 3: {
6666 132 : hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
6667 132 : hGapTot(2) = hgap(2) + std::abs(wm->A45) * 0.5 * pow_3(wm->thetas[3] + wm->thetas[4]);
6668 132 : Rbare = 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 1.0 / wm->scon[1] + 1.0 / hGapTot(2) + 1.0 / wm->scon[2];
6669 132 : wm->Rtot = rOut + Rbare + rIn;
6670 132 : SHGC =
6671 132 : AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
6672 132 : AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot +
6673 132 : 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;
6674 132 : SHGC += AbsBeamShadeNorm;
6675 132 : SHGC += TSolNorm;
6676 132 : } break;
6677 :
6678 12 : case 4: {
6679 12 : hGapTot(1) = hgap(1) + std::abs(wm->A23) * 0.5 * pow_3(wm->thetas[1] + wm->thetas[2]);
6680 12 : hGapTot(2) = hgap(2) + std::abs(wm->A45) * 0.5 * pow_3(wm->thetas[3] + wm->thetas[4]);
6681 12 : hGapTot(3) = hgap(3) + std::abs(wm->A67) * 0.5 * pow_3(wm->thetas[5] + wm->thetas[6]);
6682 12 : 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) +
6683 12 : 1.0 / wm->scon[3];
6684 12 : wm->Rtot = rOut + Rbare + rIn;
6685 12 : SHGC =
6686 12 : AbsBeamNorm(1) * (rOut + 0.5 / wm->scon[0]) / wm->Rtot +
6687 12 : AbsBeamNorm(2) * (rOut + 1.0 / wm->scon[0] + 1.0 / hGapTot(1) + 0.5 / wm->scon[1]) / wm->Rtot +
6688 12 : 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 +
6689 12 : AbsBeamNorm(4) *
6690 12 : (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) +
6691 12 : 0.5 / wm->scon[3]) /
6692 12 : wm->Rtot; // CR7682
6693 12 : SHGC += AbsBeamShadeNorm;
6694 12 : SHGC += TSolNorm;
6695 12 : } break;
6696 0 : default:
6697 0 : break;
6698 : }
6699 2687 : NominalConductance = 1.0 / (rOut + Rbare + rIn);
6700 2687 : } // EvalNominalWindowCond()
6701 :
6702 : //****************************************************************************
6703 :
6704 2687 : void WindowTempsForNominalCond(EnergyPlusData &state,
6705 : int const ConstrNum, // Construction number
6706 : Array1A<Real64> hgap, // Gap gas conductive conductance (W/m2-K)
6707 : Real64 const adjRatio // adjusment Ratio to hcin
6708 : )
6709 : {
6710 :
6711 : // SUBROUTINE INFORMATION:
6712 : // AUTHOR F. Winkelmann
6713 : // DATE WRITTEN September 2000
6714 : // MODIFIED Nov 2002, FW: increase MaxIterations from 15 to 100, add face
6715 : // temperature relaxation, and increase convergence tolerance by
6716 : // a factor of 10 if no convergence after MaxIterations,
6717 : // all for consistency with SolveForWindowTemperatures.
6718 : // Mar 2003, FW: increase convergence tolerance from 0.01 to 0.02;
6719 : // remove redundant relaxation on radiative conductances (both of
6720 : // these were also done in SolveForWindowTemperatures).
6721 : // Jan 2009, BG: changed interior convection coefficient correlation to match
6722 : // ISO 15099.
6723 : // Feb 2009, BG: extended coefficient to include absorbed radiation
6724 : // to cover summer conditions for SHGC determination.
6725 : // RE-ENGINEERED na
6726 :
6727 : // PURPOSE OF THIS SUBROUTINE:
6728 : // This is a shortened form of SolveForWindowTemperatures tailored
6729 : // for calculation of the nominal center-of-glass U-value for a window
6730 : // construction at ASHRAE winter conditions and for determining conditions at
6731 : // summer conditions for calculationg SHGC.
6732 : // Evaluates the coefficients Aface and Bface in the system of linear
6733 : // algebraic equations
6734 : // Sum [Aface(i,j)*thetas(j)] = Bface(i), i = 1,nglface
6735 : // j=1,nglface
6736 : // where
6737 : // nglface = number of glass faces (= 2 * number of layers) and
6738 : // thetas(j) = temperature of face j
6739 :
6740 : // METHODOLOGY EMPLOYED:
6741 : // The Aface and Bface coefficients are determined by the equations for
6742 : // heat balance at the glass faces. The system of linear equations is solved
6743 : // by LU decomposition.
6744 :
6745 : using Psychrometrics::PsyRhoAirFnPbTdbW;
6746 :
6747 : // Argument array dimensioning
6748 2687 : hgap.dim(5);
6749 :
6750 2687 : int constexpr MaxIterations(100); // Maximum allowed number of iterations
6751 2687 : Real64 constexpr errtemptol(0.02); // Tolerance on errtemp for convergence
6752 : static constexpr std::string_view RoutineName("WindowTempsForNominalCond");
6753 :
6754 2687 : Array1D<Real64> hr(10); // Radiative conductance (W/m2-K)
6755 : Real64 hcinprev; // Value of hcin from previous iteration
6756 : int d; // +1 if number of row interchanges is even,
6757 : // -1 if odd (in LU decomposition)
6758 2687 : Array1D_int indx(10); // Vector of row permutations in LU decomposition
6759 5374 : Array2D<Real64> Aface(10, 10); // Coefficient in equation Aface*thetas = Bface
6760 2687 : Array1D<Real64> Bface(10); // Coefficient in equation Aface*thetas = Bface
6761 : int iter; // Iteration number
6762 : Real64 errtemp; // Absolute value of sum of face temperature differences
6763 : // between iterations, divided by number of faces
6764 : Real64 TmeanFilm; // mean film temperature
6765 : Real64 TmeanFilmKelvin; // mean film temperature for property evaluation
6766 : Real64 rho; // density of (apparently dry) air [kg/m3]
6767 : Real64 g; // acceleration due to gravity [m/s2]
6768 : Real64 Height; // window cavity height [m]
6769 : Real64 Cp; // specific heat of air [J/kg-K]
6770 : Real64 lambda; // thermal conductivity of air [W/m-K]
6771 : Real64 mu; // dynamic viscosity of air [kg/m-s]
6772 : Real64 RaH; // Rayleigh number for cavity height [ Non dim]
6773 : Real64 TiltDeg; // glazing tilt in degrees
6774 : Real64 sineTilt; // sine of glazing tilt
6775 : Real64 Nuint; // Nusselt number for interior surface convection
6776 :
6777 2687 : auto &wm = state.dataWindowManager;
6778 :
6779 2687 : iter = 0;
6780 :
6781 : // Initialize face temperatures
6782 2687 : StartingWinTempsForNominalCond(state);
6783 :
6784 : // Calculate radiative conductance
6785 2687 : errtemp = errtemptol * 2.0;
6786 :
6787 2687 : TiltDeg = 90.0;
6788 :
6789 2687 : sineTilt = std::sin(TiltDeg * Constant::DegToRadians); // degrees as arg
6790 :
6791 18045 : while (iter < MaxIterations && errtemp > errtemptol) {
6792 62742 : for (int i = 1; i <= wm->nglface; ++i) {
6793 47384 : hr(i) = wm->emis[i - 1] * Constant::StefanBoltzmann * pow_3(wm->thetas[i - 1]);
6794 : //! fw 3/4/03 if ( iter >= 1 ) hr(i) = 0.5*(hrprev(i)+hr(i))
6795 : }
6796 :
6797 15358 : Aface = 0.0;
6798 15358 : Bface = 0.0;
6799 :
6800 : // Inside convective film conductance for vertical window
6801 15358 : if (iter >= 1) {
6802 12671 : hcinprev = wm->hcin;
6803 : }
6804 : // CR7670 BG this next correlation was used for hcin but is not "standard" for windows
6805 : // hcin = 1.31d0*((ABS(thetas(nglface)-tin))**0.3333d0)
6806 : // Begin calculating for ISO 15099 method.
6807 : // mean film temperature
6808 15358 : TmeanFilmKelvin = wm->tin + 0.25 * (wm->thetas[wm->nglface - 1] - wm->tin); // eq. 133 in ISO 15099
6809 15358 : TmeanFilm = TmeanFilmKelvin - 273.15;
6810 : // the following properties are constants or linear relations for "standard" type reporting
6811 15358 : rho = PsyRhoAirFnPbTdbW(state, 101325.0, TmeanFilm, 0.0, RoutineName); // dry air assumption
6812 15358 : g = 9.81;
6813 15358 : Height = 1.0; // standard window rating practice is to use 1 meter (rather than actual)
6814 :
6815 15358 : lambda = 2.873E-3 + 7.76E-5 * TmeanFilmKelvin; // Table B.1 in ISO 15099
6816 15358 : mu = 3.723E-6 + 4.94E-8 * TmeanFilmKelvin; // Table B.2 in ISO 15099
6817 15358 : Cp = 1002.737 + 1.2324E-2 * TmeanFilmKelvin; // Table B.3 in ISO 15099
6818 :
6819 : // eq 132 in ISO 15099
6820 15358 : RaH = (pow_2(rho) * pow_3(Height) * g * Cp * (std::abs(wm->thetas[wm->nglface - 1] - wm->tin))) / (TmeanFilmKelvin * mu * lambda);
6821 :
6822 15358 : Nuint = 0.56 * root_4(RaH * sineTilt); // eq. 135 in ISO 15099 (only need this one because tilt is 90 deg
6823 :
6824 15358 : wm->hcin = Nuint * lambda / Height;
6825 :
6826 : // End calculations for ISO 15099 method.
6827 :
6828 15358 : if (iter >= 1) wm->hcin = 0.5 * (hcinprev + wm->hcin);
6829 :
6830 15358 : wm->hcin *= adjRatio;
6831 :
6832 15358 : ++iter;
6833 :
6834 15358 : GetHeatBalanceEqCoefMatrixSimple(state, wm->ngllayer, hr, hgap, Aface, Bface);
6835 :
6836 15358 : LUdecomposition(state, Aface, wm->nglface, indx, d); // Note that these routines change Aface;
6837 15358 : LUsolution(state, Aface, wm->nglface, indx, Bface); // face temperatures are returned in Bface
6838 :
6839 15358 : errtemp = 0.0;
6840 62742 : for (int i = 1; i <= wm->nglface; ++i) {
6841 47384 : errtemp += std::abs(wm->thetas[i - 1] - Bface(i)) / wm->nglface;
6842 : }
6843 :
6844 62742 : for (int i = 1; i <= wm->nglface; ++i) {
6845 47384 : wm->thetas[i - 1] = 0.5 * (wm->thetas[i - 1] + Bface(i));
6846 : }
6847 : }
6848 :
6849 : // No convergence after MaxIterations; and/or error tolerance
6850 2687 : if (errtemp >= 10 * errtemptol) {
6851 : // Fatal error: didn't converge
6852 0 : ShowFatalError(
6853 : state,
6854 0 : format("Convergence error in WindowTempsForNominalCond for construction {}", state.dataConstruction->Construct(ConstrNum).Name));
6855 : }
6856 2687 : } // WindowTempsForNominalCond()
6857 :
6858 : //****************************************************************************
6859 :
6860 2687 : void StartingWinTempsForNominalCond(EnergyPlusData &state)
6861 : {
6862 :
6863 : // SUBROUTINE INFORMATION:
6864 : // AUTHOR F. Winkelmann
6865 : // DATE WRITTEN September 2000
6866 : // MODIFIED na
6867 : // RE-ENGINEERED na
6868 :
6869 : // PURPOSE OF THIS SUBROUTINE:
6870 : // Initializes face temperature distribution prior to iteration.
6871 : // This is a shortened form of StartingWindowTemps for use in calculating
6872 : // the nominal center-of-glass U-value.
6873 :
6874 2687 : Real64 constexpr hrad(5.3); // Typical radiative conductance (W/m2-K)
6875 2687 : Real64 constexpr hcinStartValue(3.2); // Starting value for inside air film convective
6876 : // conductance (estimated for typical double glazing
6877 : // using 1.31(dT**0.333), where dT =
6878 : // room air temp - inside surface temp = 14.2K)
6879 2687 : Real64 constexpr resgap(0.21); // Typical gap resistance (m2-K/W)
6880 :
6881 2687 : Array1D<Real64> rguess(11); // Combined radiative/convective resistance (m2-K/W) of
6882 : // inside or outside air film, or gap
6883 : Real64 restot; // Total window resistance including outside
6884 : // and inside air films (m2-K/W)
6885 : Real64 temdiff; // Inside/outside air temperature difference (K)
6886 : Real64 ressum; // Resistance sum (m2-K/W)
6887 :
6888 2687 : auto &wm = state.dataWindowManager;
6889 :
6890 2687 : rguess(1) = 1.0 / (wm->hcout + hrad);
6891 2687 : rguess(wm->nglface + 1) = 1.0 / (hcinStartValue + hrad);
6892 :
6893 6682 : for (int i = 2; i <= wm->nglface; i += 2) {
6894 3995 : rguess(i) = 1.0 / wm->scon[i / 2 - 1];
6895 3995 : if (i < wm->nglface) rguess(i + 1) = resgap;
6896 : }
6897 2687 : restot = 0.0;
6898 :
6899 13364 : for (int i = 1; i <= wm->nglface + 1; ++i) {
6900 10677 : restot += rguess(i);
6901 : }
6902 :
6903 2687 : temdiff = wm->tin - wm->tout;
6904 2687 : if (std::abs(temdiff) < 0.5) temdiff = 2.0;
6905 2687 : ressum = 0.0;
6906 :
6907 10677 : for (int i = 1; i <= wm->nglface; ++i) {
6908 7990 : ressum += rguess(i);
6909 7990 : wm->thetas[i - 1] = (ressum / restot) * temdiff + wm->tout;
6910 : }
6911 2687 : } // StartingWinTempsForNominalCond()
6912 :
6913 : //****************************************************************************
6914 :
6915 793 : void ReportGlass(EnergyPlusData &state)
6916 : {
6917 :
6918 : // SUBROUTINE INFORMATION:
6919 : // AUTHOR Linda K. Lawrie
6920 : // DATE WRITTEN March 2000
6921 : // MODIFIED na
6922 : // RE-ENGINEERED na
6923 :
6924 : // PURPOSE OF THIS SUBROUTINE:
6925 : // This routine gives a detailed report to the user about
6926 : // the calculation parameters for windows and their associated
6927 : // materials.
6928 :
6929 : using General::POLYF;
6930 :
6931 : using General::ScanForReports;
6932 : using WindowComplexManager::CalcComplexWindowThermal;
6933 : using WindowComplexManager::UpdateComplexWindows;
6934 :
6935 793 : static Array1D_string const Roughness({0, 5}, {"VeryRough", "Rough", "MediumRough", "MediumSmooth", "Smooth", "VerySmooth"});
6936 :
6937 793 : Real64 TempVar(0.0); // just temporary usage for complex fenestration
6938 :
6939 : int ThisNum;
6940 : int Layer;
6941 : int BlNum; // Blind number
6942 : Real64 NominalConductanceWinter; // Nominal center-of-glass conductance of a window construction
6943 : // for ASHRAE winter conditions (W/m2-K):
6944 : // Inside air temperature = 21.1C (70F)
6945 : // Outside air temperature = -17.8C (0F)
6946 : // Windspeed = 6.71 m/s (15 mph)
6947 : // No solar radiation
6948 : Real64 NominalConductanceSummer; // Nominal center-of-glass conductance of a window construction
6949 : // for ASHRAE summer conditions (W/m2-K):
6950 : // Inside air temperature = 23.9C (75F)
6951 : // Outside air temperature = 35.0C (95F)
6952 : // Windspeed = 3.35 m/s (7.5 mph)
6953 : // 783 W/m2 (248 Btu/h-ft2) incident beam solar radiation normal to glazing
6954 793 : Real64 SHGCWinter(0.0); // Center-of-glass solar heat gain coefficient for ASHRAE
6955 793 : Real64 SHGCSummer(0.0);
6956 : // winter and summer conditions
6957 : Real64 TransSolNorm; // Window construction solar transmittance at normal incidence
6958 : Real64 TransVisNorm; // Window construction visible transmittance at normal incidence
6959 : int errFlag; // Error flag
6960 793 : std::string SolarDiffusing; // 'Yes' if glass is solar diffusing; otherwise 'No' (clear glass)
6961 793 : std::string SpectralDataName;
6962 793 : std::string OpticalDataType;
6963 793 : std::string SlateOrientation;
6964 :
6965 793 : auto &wm = state.dataWindowManager;
6966 :
6967 793 : ScanForReports(state, "Constructions", wm->DoReport, "Constructions");
6968 :
6969 793 : if (std::any_of(state.dataConstruction->Construct.begin(),
6970 793 : state.dataConstruction->Construct.end(),
6971 4515 : [](Construction::ConstructionProps const &e) { return e.TypeIsWindow; }))
6972 696 : wm->HasWindows = true;
6973 793 : if (std::any_of(state.dataConstruction->Construct.begin(),
6974 793 : state.dataConstruction->Construct.end(),
6975 6023 : [](Construction::ConstructionProps const &e) { return e.WindowTypeBSDF; }))
6976 9 : wm->HasComplexWindows = true; // Yes, this is a bit different than actually using them.
6977 793 : if (std::any_of(state.dataConstruction->Construct.begin(),
6978 793 : state.dataConstruction->Construct.end(),
6979 6025 : [](Construction::ConstructionProps const &e) { return e.WindowTypeEQL; }))
6980 1 : wm->HasEQLWindows = true; // for reporting purpose only
6981 793 : if (wm->DoReport && (wm->HasWindows || wm->HasComplexWindows || wm->HasEQLWindows)) {
6982 : // Write Descriptions
6983 268 : print(state.files.eio,
6984 : "{}\n",
6985 : "! <WindowConstruction>,Construction Name,Index,#Layers,Roughness,Conductance {W/m2-K},Conductance (Before Adjusted) {W/m2-K},"
6986 : "Convection Coefficient Adjustment Ratio,SHGC,"
6987 : "Solar Transmittance at Normal Incidence,Visible Transmittance at Normal Incidence");
6988 268 : if ((state.dataHeatBal->TotSimpleWindow > 0) || (state.dataHeatBal->W5GlsMat > 0) || (state.dataHeatBal->W5GlsMatAlt > 0))
6989 262 : print(state.files.eio,
6990 : "{}\n",
6991 : "! <WindowMaterial:Glazing>, Material Name, Optical Data Type, Spectral Data Set Name, "
6992 : "Thickness {m}, Solar Transmittance,Front Solar Reflectance, Back Solar Reflectance, Visible "
6993 : "Transmittance, Front Visible Reflectance,Back Visible Reflectance,Infrared Transmittance, "
6994 : "Front Thermal Emissivity, Back Thermal Emissivity,Conductivity {W/m-K},Dirt Factor,Solar "
6995 : "Diffusing");
6996 268 : if ((state.dataHeatBal->W5GasMat > 0) || (state.dataHeatBal->W5GasMatMixture > 0))
6997 87 : print(state.files.eio, "{}\n", "! <WindowMaterial:Gas>,Material Name,GasType,Thickness {m}");
6998 268 : if (state.dataHeatBal->TotShades > 0)
6999 7 : print(state.files.eio,
7000 : "{}\n",
7001 : "! <WindowMaterial:Shade>,Material Name,Thickness {m},Conductivity {W/m-K},Thermal "
7002 : "Absorptance,Transmittance,Visible Transmittance,Shade Reflectance");
7003 268 : if (state.dataHeatBal->TotScreens > 0)
7004 2 : print(state.files.eio,
7005 : "{}\n",
7006 : "! <WindowMaterial:Screen>,Material Name,Thickness {m},Conductivity {W/m-K},Thermal "
7007 : "Absorptance,Transmittance,Reflectance,Visible Reflectance,Diffuse Reflectance,Diffuse Visible "
7008 : "Reflectance,Screen Material Diameter To Spacing Ratio,Screen To GlassDistance {m}");
7009 268 : if (state.dataHeatBal->TotBlinds > 0)
7010 16 : print(state.files.eio,
7011 : "{}\n",
7012 : "! <WindowMaterial:Blind>,Material Name,Slat Width {m},Slat Separation {m},Slat Thickness "
7013 : "{m},Slat Angle {deg},Slat Beam Solar Transmittance,Slat Beam Solar Front Reflectance,Blind To "
7014 : "Glass Distance {m}");
7015 :
7016 268 : if (wm->HasComplexWindows)
7017 8 : print(state.files.eio,
7018 : "{}\n",
7019 : "! <WindowConstruction:Complex>,Construction Name,Index,#Layers,U-factor {W/m2-K},SHGC"
7020 : "NFRC Product Type,Assembly U-Factor {W/m2-K},Assembly SHGC,Assembly Visible Transmittance");
7021 :
7022 268 : if (wm->HasEQLWindows)
7023 1 : print(state.files.eio,
7024 : "{}\n",
7025 : "! <Construction:WindowEquivalentLayer>,Construction Name,Index,#Layers,U-factor {W/m2-K},SHGC, "
7026 : "Solar Transmittance at Normal Incidence");
7027 268 : if (state.dataHeatBal->W5GlsMatEQL > 0)
7028 1 : print(state.files.eio,
7029 : "{}\n",
7030 : "! <WindowMaterial:Glazing:EquivalentLayer>, Material Name, Optical Data Type, Spectral Data "
7031 : "Set Name, Front Side Beam-Beam Solar Transmittance, Back Side Beam-Beam Solar Transmittance, "
7032 : "Front Side Beam-Beam Solar Reflectance, Back Side Beam-Beam Solar Reflectance, Front Side "
7033 : "Beam-Diffuse Solar Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side "
7034 : "Beam-Diffuse Solar Reflectance, Back Side Beam-Diffuse Solar Reflectance, Diffuse-Diffuse "
7035 : "Solar Transmittance, Front Side Diffuse-Diffuse Solar Reflectance, Back Side Diffuse-Diffuse "
7036 : "Solar Reflectance, Infrared Transmittance, Front Side Infrared Emissivity, Back Side Infrared "
7037 : "Emissivity");
7038 268 : if (state.dataHeatBal->TotShadesEQL > 0)
7039 1 : print(state.files.eio,
7040 : "{}\n",
7041 : "! <WindowMaterial:Shade:EquivalentLayer>, Material Name, Front Side Beam-Beam Solar "
7042 : "Transmittance, Back Side Beam-Beam Solar Transmittance, Front Side Beam-Diffuse Solar "
7043 : "Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side Beam-Diffuse Solar "
7044 : "Reflectance, Back Side Beam-Diffuse Solar Reflectance, Infrared Transmittance, Front Side "
7045 : "Infrared Emissivity, Back Side Infrared Emissivity");
7046 :
7047 268 : if (state.dataHeatBal->TotDrapesEQL > 0)
7048 0 : print(state.files.eio,
7049 : "{}\n",
7050 : "! <WindowMaterial:Drape:EquivalentLayer>, Material Name, Front Side Beam-Beam Solar "
7051 : "Transmittance, Back Side Beam-Beam Solar Transmittance, Front Side Beam-Diffuse Solar "
7052 : "Transmittance, Back Side Beam-Diffuse Solar Transmittance, , Front Side Beam-Diffuse Solar "
7053 : "Reflectance, Back Side Beam-Diffuse Solar Reflectance, Infrared Transmittance, Front Side "
7054 : "Infrared Emissivity, Back Side Infrared Emissivity, Width of Pleated Fabric, Length of Pleated "
7055 : "Fabric");
7056 :
7057 268 : if (state.dataHeatBal->TotBlindsEQL > 0)
7058 0 : print(state.files.eio,
7059 : "{}\n",
7060 : "! <WindowMaterial:Blind:EquivalentLayer>, Material Name, Slat Orientation, Slat Width, Slat "
7061 : "Separation, Slat Crown, Slat Angle, Front Side Slate Beam-Diffuse Solar Transmittance, Back "
7062 : "Side Slate Beam-Diffuse Solar Transmittance, Front Side Slate Beam-Diffuse Solar Reflectance, "
7063 : "Back Side Slate Beam-Diffuse Solar Reflectance, Slat Diffuse-Diffuse Solar Transmittance, "
7064 : "Front Side Slat Diffuse-Diffuse Solar Reflectance, Back Side Slat Diffuse-Diffuse Solar "
7065 : "Reflectance, Infrared Transmittance, Front Side Infrared Emissivity, Back Side Infrared "
7066 : "Emissivity, Slat Angle Control");
7067 268 : if (state.dataHeatBal->TotScreensEQL > 0)
7068 1 : print(state.files.eio,
7069 : "{}\n",
7070 : "! <WindowMaterial:Screen:EquivalentLayer>, Material Name, Screen Beam-Beam Solar "
7071 : "Transmittance, Screen Beam-Diffuse Solar Transmittance, Screen Beam-Diffuse Solar Reflectance, "
7072 : "Screen Infrared Transmittance, Screen Infrared Emissivity, Screen Wire Spacing, Screen Wire "
7073 : "Diameter");
7074 268 : if (state.dataHeatBal->W5GapMatEQL > 0)
7075 1 : print(state.files.eio, "{}\n", "! <WindowMaterial:Gap:EquivalentLayer>, Material Name, GasType, Gap Thickness {m}, Gap Vent Type");
7076 :
7077 3095 : for (int ThisNum = 1; ThisNum <= state.dataHeatBal->TotConstructs; ++ThisNum) {
7078 2827 : auto &construct = state.dataConstruction->Construct(ThisNum);
7079 2827 : if (construct.WindowTypeBSDF) {
7080 :
7081 11 : int i = ThisNum;
7082 11 : CalcComplexWindowThermal(state, 0, i, TempVar, TempVar, TempVar, TempVar, DataBSDFWindow::Condition::Winter);
7083 11 : CalcComplexWindowThermal(state, 0, i, TempVar, TempVar, TempVar, TempVar, DataBSDFWindow::Condition::Summer);
7084 :
7085 : static constexpr std::string_view Format_800(" WindowConstruction:Complex,{},{},{},{:.3R},{:.3R}\n");
7086 11 : print(state.files.eio,
7087 : Format_800,
7088 11 : construct.Name,
7089 : ThisNum,
7090 11 : construct.TotSolidLayers,
7091 11 : state.dataHeatBal->NominalU(ThisNum),
7092 11 : construct.SummerSHGC);
7093 :
7094 2816 : } else if (construct.TypeIsWindow) {
7095 : // Calculate for ASHRAE winter and summer conditions:
7096 : // (1) nominal center-of-glass conductance, including inside and outside air films,
7097 : // (2) solar heat gain coefficient (SHGC),
7098 : // (3) solar transmittance at normal incidence, and (4) visible transmittance at normal incidence.
7099 :
7100 675 : if (construct.WindowTypeEQL) {
7101 : // for equivalent layer Window already calculated
7102 : // NominalU(ThisNum)=NominalConductanceWinter
7103 : // Save the SHGC for later use in tabular report IVRS
7104 : // Construct(ThisNum)%SummerSHGC = SHGCSummer
7105 3 : construct.VisTransNorm = 0.0; // TODO list
7106 :
7107 : static constexpr std::string_view Format_799(" Construction:WindowEquivalentLayer,{},{},{},{:.3R},{:.3R},{:.3R}\n");
7108 3 : print(state.files.eio,
7109 : Format_799,
7110 3 : construct.Name,
7111 : ThisNum,
7112 3 : construct.TotSolidLayers,
7113 3 : state.dataHeatBal->NominalU(ThisNum),
7114 3 : construct.SummerSHGC,
7115 3 : construct.SolTransNorm);
7116 :
7117 : } else {
7118 :
7119 672 : CalcNominalWindowCond(state, ThisNum, 1, NominalConductanceWinter, SHGCWinter, TransSolNorm, TransVisNorm, errFlag);
7120 :
7121 672 : if (errFlag == 1) {
7122 0 : ShowWarningError(state, format("Window construction {} has an interior or exterior blind", construct.Name));
7123 0 : ShowContinueError(state, "but the corresponding construction without the blind cannot be found.");
7124 0 : ShowContinueError(state, "The ReportGlass entry for this construction will not be printed in eplusout.eio.");
7125 0 : continue;
7126 : }
7127 :
7128 : // Skip constructions with between-glass shade/blind until method is worked out to determine
7129 : // nominal conductance and SHGC.
7130 :
7131 672 : if (errFlag == 2) {
7132 5 : ShowWarningError(state, format("Window construction {} has a between-glass shade or blind", construct.Name));
7133 5 : ShowContinueError(state, "The ReportGlass entry for this construction will not be printed in eplusout.eio.");
7134 5 : continue;
7135 : }
7136 :
7137 667 : state.dataHeatBal->NominalU(ThisNum) = NominalConductanceWinter;
7138 667 : if (!construct.WindowTypeEQL) {
7139 667 : CalcNominalWindowCond(state, ThisNum, 2, NominalConductanceSummer, SHGCSummer, TransSolNorm, TransVisNorm, errFlag);
7140 : }
7141 : // Save the SHGC for later use in tabular report IVRS
7142 667 : construct.SummerSHGC = SHGCSummer;
7143 667 : construct.VisTransNorm = TransVisNorm;
7144 667 : construct.SolTransNorm = TransSolNorm;
7145 :
7146 : static constexpr std::string_view Format_700(" WindowConstruction,{},{},{},{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
7147 1334 : print(state.files.eio,
7148 : Format_700,
7149 667 : construct.Name,
7150 : ThisNum,
7151 667 : construct.TotLayers,
7152 667 : Roughness(static_cast<int>(construct.OutsideRoughness)),
7153 : NominalConductanceWinter,
7154 667 : state.dataHeatBal->NominalUBeforeAdjusted(ThisNum),
7155 667 : state.dataHeatBal->CoeffAdjRatio(ThisNum),
7156 : SHGCSummer,
7157 : TransSolNorm,
7158 : TransVisNorm);
7159 : }
7160 : // Write(OutputFileConstrainParams, 705) TRIM(Construct(ThisNum)%Name), SHGCSummer ,TransVisNorm
7161 :
7162 2099 : for (int i = 1; i <= construct.TotLayers; ++i) {
7163 1429 : Layer = construct.LayerPoint(i);
7164 1429 : auto const *mat = state.dataMaterial->Material(Layer);
7165 :
7166 1429 : switch (mat->group) {
7167 347 : case Material::Group::WindowGas: {
7168 347 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
7169 347 : assert(matGas != nullptr);
7170 : static constexpr std::string_view Format_702(" WindowMaterial:Gas,{},{},{:.3R}\n");
7171 347 : print(state.files.eio, Format_702, matGas->Name, Material::gasTypeNames[(int)matGas->gases[0].type], matGas->Thickness);
7172 : //! fw CASE(WindowGasMixture)
7173 347 : } break;
7174 18 : case Material::Group::Shade: {
7175 18 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
7176 18 : assert(thisMaterial != nullptr);
7177 :
7178 : static constexpr std::string_view Format_703(" WindowMaterial:Shade,,{},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
7179 18 : print(state.files.eio,
7180 : Format_703,
7181 18 : thisMaterial->Name,
7182 18 : thisMaterial->Thickness,
7183 18 : thisMaterial->Conductivity,
7184 18 : thisMaterial->AbsorpThermal,
7185 18 : thisMaterial->Trans,
7186 18 : thisMaterial->TransVis,
7187 18 : thisMaterial->ReflectShade);
7188 18 : } break;
7189 13 : case Material::Group::WindowBlind: {
7190 13 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
7191 13 : assert(thisMaterial != nullptr);
7192 13 : BlNum = thisMaterial->BlindDataPtr;
7193 13 : auto const &blind = state.dataMaterial->Blind(BlNum);
7194 : static constexpr std::string_view Format_704(
7195 : " WindowMaterial:Blind,{},{:.4R},{:.4R},{:.4R},{:.3R},{:.3R},{:.3R},{:.3R}\n");
7196 13 : print(state.files.eio,
7197 : Format_704,
7198 13 : thisMaterial->Name,
7199 13 : blind.SlatWidth,
7200 13 : blind.SlatSeparation,
7201 13 : blind.SlatThickness,
7202 13 : blind.SlatAngle,
7203 13 : blind.SlatTransSolBeamDiff,
7204 13 : blind.SlatFrontReflSolBeamDiff,
7205 13 : blind.BlindToGlassDist);
7206 13 : } break;
7207 2 : case Material::Group::Screen: {
7208 2 : auto const *matScreen = dynamic_cast<Material::MaterialScreen const *>(mat);
7209 2 : assert(matScreen != nullptr);
7210 2 : auto const &btar = matScreen->btars[0][0]; // AR: Going with normal incidence here
7211 :
7212 : static constexpr std::string_view Format_706 =
7213 : " WindowMaterial:Screen,{},{:.5R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R},{:.3R}\n";
7214 :
7215 : // AR: assuming normal incidence
7216 2 : print(state.files.eio,
7217 : Format_706,
7218 2 : matScreen->Name,
7219 2 : matScreen->Thickness,
7220 2 : matScreen->Conductivity,
7221 2 : matScreen->AbsorpThermal,
7222 2 : btar.BmTrans,
7223 2 : btar.RefSolFront,
7224 2 : btar.RefVisFront,
7225 2 : matScreen->DfRef,
7226 2 : matScreen->DfRefVis,
7227 2 : matScreen->diameterToSpacingRatio,
7228 2 : matScreen->toGlassDist);
7229 2 : } break;
7230 1022 : case Material::Group::WindowGlass:
7231 : case Material::Group::WindowSimpleGlazing: {
7232 1022 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
7233 1022 : assert(thisMaterial != nullptr);
7234 1022 : SolarDiffusing = "No";
7235 1022 : if (thisMaterial->SolarDiffusing) SolarDiffusing = "Yes";
7236 1022 : OpticalDataType = "SpectralAverage";
7237 1022 : SpectralDataName = "";
7238 1022 : if (thisMaterial->GlassSpectralDataPtr > 0) {
7239 181 : OpticalDataType = "Spectral";
7240 181 : SpectralDataName = state.dataHeatBal->SpectralData(thisMaterial->GlassSpectralDataPtr).Name;
7241 : }
7242 1022 : if (thisMaterial->GlassSpectralAndAngle) {
7243 0 : OpticalDataType = "SpectralAndAngle";
7244 0 : SpectralDataName = state.dataCurveManager->PerfCurve(thisMaterial->GlassSpecAngTransDataPtr)->Name + ", " +
7245 0 : state.dataCurveManager->PerfCurve(thisMaterial->GlassSpecAngFRefleDataPtr)->Name + ", " +
7246 0 : state.dataCurveManager->PerfCurve(thisMaterial->GlassSpecAngBRefleDataPtr)->Name;
7247 : }
7248 : static constexpr std::string_view Format_707(
7249 : " WindowMaterial:Glazing,{},{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{"
7250 : ":.5R},{:.5R},{:.5R},{:.5R},{:.5R},{}\n");
7251 1022 : print(state.files.eio,
7252 : Format_707,
7253 1022 : thisMaterial->Name,
7254 : OpticalDataType,
7255 : SpectralDataName,
7256 1022 : thisMaterial->Thickness,
7257 1022 : thisMaterial->Trans,
7258 1022 : thisMaterial->ReflectSolBeamFront,
7259 1022 : thisMaterial->ReflectSolBeamBack,
7260 1022 : thisMaterial->TransVis,
7261 1022 : thisMaterial->ReflectVisBeamFront,
7262 1022 : thisMaterial->ReflectVisBeamBack,
7263 1022 : thisMaterial->TransThermal,
7264 1022 : thisMaterial->AbsorpThermalFront,
7265 1022 : thisMaterial->AbsorpThermalBack,
7266 1022 : thisMaterial->Conductivity,
7267 1022 : thisMaterial->GlassTransDirtFactor,
7268 : SolarDiffusing);
7269 1022 : } break;
7270 8 : case Material::Group::GlassEquivalentLayer: {
7271 8 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
7272 8 : assert(thisMaterial != nullptr);
7273 8 : OpticalDataType = "SpectralAverage";
7274 8 : SpectralDataName = "";
7275 : static constexpr std::string_view Format_708(
7276 : " WindowMaterial:Glazing:EquivalentLayer,{},{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}"
7277 : ",{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}\n");
7278 8 : print(state.files.eio,
7279 : Format_708,
7280 8 : thisMaterial->Name,
7281 : OpticalDataType,
7282 : SpectralDataName,
7283 8 : thisMaterial->TausFrontBeamBeam,
7284 8 : thisMaterial->TausBackBeamBeam,
7285 8 : thisMaterial->ReflFrontBeamBeam,
7286 8 : thisMaterial->ReflBackBeamBeam,
7287 8 : thisMaterial->TausFrontBeamDiff,
7288 8 : thisMaterial->TausBackBeamDiff,
7289 8 : thisMaterial->ReflFrontBeamDiff,
7290 8 : thisMaterial->ReflBackBeamDiff,
7291 8 : thisMaterial->TausDiffDiff,
7292 8 : thisMaterial->ReflFrontDiffDiff,
7293 8 : thisMaterial->ReflBackDiffDiff,
7294 8 : thisMaterial->TausThermal,
7295 8 : thisMaterial->EmissThermalFront,
7296 8 : thisMaterial->EmissThermalBack);
7297 8 : } break;
7298 2 : case Material::Group::ShadeEquivalentLayer: {
7299 2 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
7300 2 : assert(thisMaterial != nullptr);
7301 : static constexpr std::string_view Format_709(
7302 : " WindowMaterial:Shade:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R}\n");
7303 2 : print(state.files.eio,
7304 : Format_709,
7305 2 : thisMaterial->Name,
7306 2 : thisMaterial->TausFrontBeamBeam,
7307 2 : thisMaterial->TausBackBeamBeam,
7308 2 : thisMaterial->TausFrontBeamDiff,
7309 2 : thisMaterial->TausBackBeamDiff,
7310 2 : thisMaterial->ReflFrontBeamDiff,
7311 2 : thisMaterial->ReflBackBeamDiff,
7312 2 : thisMaterial->TausThermal,
7313 2 : thisMaterial->EmissThermalFront,
7314 2 : thisMaterial->EmissThermalBack);
7315 2 : } break;
7316 0 : case Material::Group::DrapeEquivalentLayer: {
7317 0 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
7318 0 : assert(thisMaterial != nullptr);
7319 : static constexpr std::string_view Format_710(
7320 : " WindowMaterial:Drape:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},"
7321 : "{:.4R},{:.4R},{:.5R},{:.5R}\n");
7322 0 : print(state.files.eio,
7323 : Format_710,
7324 0 : thisMaterial->Name,
7325 0 : thisMaterial->TausFrontBeamBeam,
7326 0 : thisMaterial->TausFrontBeamDiff,
7327 0 : thisMaterial->TausBackBeamDiff,
7328 0 : thisMaterial->ReflFrontBeamDiff,
7329 0 : thisMaterial->ReflBackBeamDiff,
7330 0 : thisMaterial->TausThermal,
7331 0 : thisMaterial->EmissThermalFront,
7332 0 : thisMaterial->EmissThermalBack,
7333 0 : thisMaterial->PleatedDrapeWidth,
7334 0 : thisMaterial->PleatedDrapeLength);
7335 0 : } break;
7336 1 : case Material::Group::ScreenEquivalentLayer: {
7337 1 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
7338 1 : assert(thisMaterial != nullptr);
7339 : static constexpr std::string_view Format_711(
7340 : " WindowMaterial:Screen:EquivalentLayer,{},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R},{:.4R}"
7341 : ",{:.4R},{:.4R},{:.5R},{:.5R}\n");
7342 1 : print(state.files.eio,
7343 : Format_711,
7344 1 : thisMaterial->Name,
7345 1 : thisMaterial->TausFrontBeamBeam,
7346 1 : thisMaterial->TausFrontBeamDiff,
7347 1 : thisMaterial->TausBackBeamDiff,
7348 1 : thisMaterial->ReflFrontBeamDiff,
7349 1 : thisMaterial->ReflBackBeamDiff,
7350 1 : thisMaterial->TausThermal,
7351 1 : thisMaterial->EmissThermalFront,
7352 1 : thisMaterial->EmissThermalBack,
7353 1 : thisMaterial->ScreenWireSpacing,
7354 1 : thisMaterial->ScreenWireDiameter);
7355 1 : } break;
7356 0 : case Material::Group::BlindEquivalentLayer: {
7357 0 : auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
7358 0 : assert(thisMaterial != nullptr);
7359 0 : SlateOrientation = "Horizontal";
7360 0 : if (thisMaterial->SlatOrientation == DataWindowEquivalentLayer::Orientation::Vertical) {
7361 0 : SlateOrientation = "Vertical";
7362 : }
7363 : // Formats
7364 : static constexpr std::string_view Format_712(
7365 : " WindowMaterial:Blind:EquivalentLayer,{},{},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:."
7366 : "5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R},{:.5R}");
7367 0 : print(state.files.eio,
7368 : Format_712,
7369 0 : thisMaterial->Name,
7370 : SlateOrientation,
7371 0 : thisMaterial->SlatWidth,
7372 0 : thisMaterial->SlatSeparation,
7373 0 : thisMaterial->SlatCrown,
7374 0 : thisMaterial->SlatAngle,
7375 0 : thisMaterial->TausFrontBeamDiff,
7376 0 : thisMaterial->TausBackBeamDiff,
7377 0 : thisMaterial->ReflFrontBeamDiff,
7378 0 : thisMaterial->ReflBackBeamDiff,
7379 0 : thisMaterial->TausDiffDiff,
7380 0 : thisMaterial->ReflFrontDiffDiff,
7381 0 : thisMaterial->ReflBackDiffDiff,
7382 0 : thisMaterial->TausThermal,
7383 0 : thisMaterial->EmissThermalFront,
7384 0 : thisMaterial->EmissThermalBack);
7385 0 : } break;
7386 8 : case Material::Group::GapEquivalentLayer: {
7387 8 : auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
7388 8 : assert(matGas != nullptr);
7389 : static constexpr std::string_view Format_713(" WindowMaterial:Gap:EquivalentLayer,{},{},{:.3R},{}\n");
7390 8 : print(state.files.eio,
7391 : Format_713,
7392 8 : matGas->Name,
7393 8 : Material::gasTypeNames[(int)matGas->gases[0].type],
7394 8 : matGas->Thickness,
7395 8 : Material::gapVentTypeNames[(int)matGas->gapVentType]);
7396 8 : } break;
7397 8 : default:
7398 8 : break;
7399 : }
7400 : } // for (i)
7401 : } // if (construct.TypeIsWindow)
7402 : } // for (ThisNum)
7403 :
7404 525 : } else if (wm->HasWindows) {
7405 :
7406 3407 : for (int ThisNum = 1; ThisNum <= state.dataHeatBal->TotConstructs; ++ThisNum) {
7407 2979 : auto &construct = state.dataConstruction->Construct(ThisNum);
7408 2979 : if (!construct.TypeIsWindow) continue;
7409 678 : if (construct.WindowTypeEQL) continue; // skip if equivalent layer window
7410 :
7411 : // Calculate for ASHRAE winter and summer conditions: (1)nominal center-of-glass conductance,
7412 : // (2) solar heat gain coefficient (SHGC), including inside and outside air films,
7413 : // (3) solar transmittance at normal incidence, and (4) visible transmittance at normal incidence.
7414 :
7415 678 : CalcNominalWindowCond(state, ThisNum, 1, NominalConductanceWinter, SHGCWinter, TransSolNorm, TransVisNorm, errFlag);
7416 678 : if (errFlag == 1 || errFlag == 2) continue;
7417 678 : state.dataHeatBal->NominalU(ThisNum) = NominalConductanceWinter;
7418 : // Need to have this because of window assembly reports (Simon)
7419 678 : construct.SummerSHGC = SHGCSummer;
7420 678 : construct.VisTransNorm = TransVisNorm;
7421 : }
7422 : }
7423 793 : } // ReportGlass()
7424 :
7425 : //*************************************************************************************
7426 :
7427 18 : void CalcWindowBlindProperties(EnergyPlusData &state)
7428 : {
7429 :
7430 : // SUBROUTINE INFORMATION:
7431 : // AUTHOR Hans Simmler
7432 : // DATE WRITTEN July-Aug 1995
7433 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
7434 : // Dec 2001 (FCW): add variable slat angle
7435 : // RE-ENGINEERED na
7436 :
7437 : // PURPOSE OF THIS SUBROUTINE:
7438 : // Calculates solar-optical properties of a window blind
7439 : // from slat properties and solar profile angle. Assumes flat slats.
7440 :
7441 : // METHODOLOGY EMPLOYED:
7442 : // The solar profile angle is varied from -90 to +90 deg and slat angle is varied from 0 to 180deg,
7443 : // covering the full range of possible profile angles and slat angles.
7444 : // (The profile angle is defined as the angle of incidence when the radiation
7445 : // source is located in a plane that (1)is perpendicular to the plane of the blinds [which is
7446 : // the same as the window plane] and (2) contains the slat normal vector.)
7447 :
7448 : // In the time-step calculation,the blind properties vs. profile angle and slat angle
7449 : // that are calculated here will be applicable to windows and slats
7450 : // of arbitrary orientation, and to arbitrary sun positions, as long as the appropiate
7451 : // profile angle is used. The slat angle for a particular window with blinds is determined
7452 : // each time step in subroutine WindowShadingManager on the basis of user-specified
7453 : // slat control options.
7454 :
7455 : // REFERENCES:
7456 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
7457 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
7458 :
7459 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7460 :
7461 18 : Array1D<Real64> bld_pr(15); // Slat properties
7462 18 : Array1D<Real64> st_lay(16); // Solar-optical blind/glazing system properties
7463 : Real64 sun_el; // Solar profile angle (radians)
7464 18 : Array1D<Real64> sun_el_deg(Material::MaxProfAngs); // Solar profile angle (deg) corresponding to sun_el values
7465 : Real64 bld_el; // Slat angle (elevation of slat normal vector in plane
7466 : // perpendicular to window and containing the slat normal vector) (radians)
7467 : int IProfAng; // Profile angle index
7468 :
7469 39 : for (int BlindNum = 1; BlindNum <= state.dataHeatBal->TotBlinds; ++BlindNum) {
7470 21 : auto &blind = state.dataMaterial->Blind(BlindNum);
7471 :
7472 21 : bld_pr(2) = blind.SlatWidth;
7473 21 : bld_pr(3) = blind.SlatSeparation;
7474 :
7475 63 : for (int ISolVis = 1; ISolVis <= 2; ++ISolVis) {
7476 42 : if (ISolVis == 1) { // For solar calculation
7477 21 : bld_pr(4) = 0.0;
7478 21 : bld_pr(5) = 0.0;
7479 21 : bld_pr(6) = 0.0;
7480 21 : bld_pr(7) = blind.SlatTransSolBeamDiff;
7481 21 : bld_pr(8) = blind.SlatFrontReflSolBeamDiff;
7482 21 : bld_pr(9) = blind.SlatBackReflSolBeamDiff;
7483 21 : bld_pr(10) = blind.SlatTransSolDiffDiff;
7484 21 : bld_pr(11) = blind.SlatFrontReflSolDiffDiff;
7485 21 : bld_pr(12) = blind.SlatBackReflSolDiffDiff;
7486 : } else { // For visible calculation
7487 21 : bld_pr(4) = 0.0;
7488 21 : bld_pr(5) = 0.0;
7489 21 : bld_pr(6) = 0.0;
7490 21 : bld_pr(7) = blind.SlatTransVisBeamDiff;
7491 21 : bld_pr(8) = blind.SlatFrontReflVisBeamDiff;
7492 21 : bld_pr(9) = blind.SlatBackReflVisBeamDiff;
7493 21 : bld_pr(10) = blind.SlatTransVisDiffDiff;
7494 21 : bld_pr(11) = blind.SlatFrontReflVisDiffDiff;
7495 21 : bld_pr(12) = blind.SlatBackReflVisDiffDiff;
7496 : }
7497 : // For IR calculation
7498 42 : bld_pr(13) = blind.SlatTransIR;
7499 42 : bld_pr(14) = blind.SlatFrontEmissIR;
7500 42 : bld_pr(15) = blind.SlatBackEmissIR;
7501 :
7502 : // Calculate diffuse properties of blind. If blind has variable slat angle, &
7503 : // vary slat angle from 0 to 180 deg in 10-deg steps (for Material::MaxSlatAngs = 19).
7504 : // If blind has fixed slat angle, calculate properties at that angle only.
7505 :
7506 1128 : for (int ISlatAng = 1; ISlatAng <= Material::MaxSlatAngs; ++ISlatAng) {
7507 :
7508 1122 : st_lay = 0.0;
7509 1122 : if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) {
7510 36 : bld_el = blind.SlatAngle * Constant::DegToRadians;
7511 : } else { // Variable slat angle
7512 1086 : bld_el = (Constant::Pi / (Material::MaxSlatAngs - 1)) * (ISlatAng - 1); // 0 <= bld_el <= 180 deg
7513 : }
7514 1122 : BlindOpticsDiffuse(state, BlindNum, ISolVis, bld_pr, bld_el, st_lay);
7515 :
7516 1122 : if (ISolVis == 1) { // Fill blind diffuse solar and IR properties
7517 561 : blind.SolFrontDiffDiffTrans(ISlatAng) = st_lay(9);
7518 561 : blind.SolFrontDiffDiffRefl(ISlatAng) = st_lay(10);
7519 561 : blind.SolBackDiffDiffTrans(ISlatAng) = st_lay(11);
7520 561 : blind.SolBackDiffDiffRefl(ISlatAng) = st_lay(12);
7521 561 : blind.SolFrontDiffAbs(ISlatAng) = max(0.0, 1.0 - st_lay(9) - st_lay(10));
7522 561 : blind.SolBackDiffAbs(ISlatAng) = max(0.0, 1.0 - st_lay(11) - st_lay(12));
7523 561 : blind.IRFrontTrans(ISlatAng) = st_lay(13);
7524 561 : blind.IRFrontEmiss(ISlatAng) = st_lay(14);
7525 561 : blind.IRBackTrans(ISlatAng) = st_lay(13);
7526 561 : blind.IRBackEmiss(ISlatAng) = st_lay(15);
7527 : } else { // Fill blind diffuse visible properties
7528 561 : blind.VisFrontDiffDiffTrans(ISlatAng) = st_lay(9);
7529 561 : blind.VisFrontDiffDiffRefl(ISlatAng) = st_lay(10);
7530 561 : blind.VisBackDiffDiffTrans(ISlatAng) = st_lay(11);
7531 561 : blind.VisBackDiffDiffRefl(ISlatAng) = st_lay(12);
7532 : }
7533 :
7534 1122 : if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) break;
7535 : } // End of slat angle loop
7536 :
7537 : // Calculate beam properties of blind. Vary profile angle from -90 to +90 deg in 5-deg steps.
7538 : // If blind has variable slat angle, vary slat angle from 0 to 180 deg in 10-deg steps
7539 : // (for Material::MaxSlatAngs = 19). If blind has fixed slat angle, calculate properties at that angle only.
7540 :
7541 1596 : for (int IProfAng = 1; IProfAng <= Material::MaxProfAngs; ++IProfAng) {
7542 1554 : sun_el = -Constant::Pi / 2.0 + (Constant::Pi / 36.0) * (IProfAng - 1);
7543 1554 : sun_el_deg(IProfAng) = 57.2958 * sun_el;
7544 :
7545 41736 : for (int ISlatAng = 1; ISlatAng <= Material::MaxSlatAngs; ++ISlatAng) {
7546 41514 : st_lay = 0.0;
7547 41514 : if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) {
7548 1332 : bld_el = blind.SlatAngle * Constant::DegToRadians;
7549 : } else { // Variable slat angle
7550 40182 : bld_el = (Constant::Pi / (Material::MaxSlatAngs - 1)) * (ISlatAng - 1); // 0 <= bld_el <= 180 deg
7551 : }
7552 :
7553 : // Beam solar-optical properties of blind for given profile angle and slat angle
7554 :
7555 41514 : BlindOpticsBeam(state, BlindNum, bld_pr, bld_el, sun_el, st_lay);
7556 :
7557 41514 : if (ISolVis == 1) { // Fill blind beam solar properties
7558 20757 : blind.SolFrontBeamBeamTrans(ISlatAng, IProfAng) = st_lay(1);
7559 20757 : blind.SolFrontBeamBeamRefl(ISlatAng, IProfAng) = st_lay(2);
7560 20757 : blind.SolBackBeamBeamTrans(ISlatAng, IProfAng) = st_lay(3);
7561 20757 : blind.SolBackBeamBeamRefl(ISlatAng, IProfAng) = st_lay(4);
7562 20757 : blind.SolFrontBeamDiffTrans(ISlatAng, IProfAng) = st_lay(5);
7563 20757 : blind.SolFrontBeamDiffRefl(ISlatAng, IProfAng) = st_lay(6);
7564 20757 : blind.SolBackBeamDiffTrans(ISlatAng, IProfAng) = st_lay(7);
7565 20757 : blind.SolBackBeamDiffRefl(ISlatAng, IProfAng) = st_lay(8);
7566 20757 : blind.SolFrontBeamAbs(ISlatAng, IProfAng) = max(0.0, 1.0 - st_lay(6) - st_lay(1) - st_lay(5));
7567 20757 : blind.SolBackBeamAbs(ISlatAng, IProfAng) = max(0.0, 1.0 - st_lay(7) - st_lay(3) - st_lay(8));
7568 :
7569 : } else { // Fill blind beam visible properties
7570 20757 : blind.VisFrontBeamBeamTrans(ISlatAng, IProfAng) = st_lay(1);
7571 20757 : blind.VisFrontBeamBeamRefl(ISlatAng, IProfAng) = st_lay(2);
7572 20757 : blind.VisBackBeamBeamTrans(ISlatAng, IProfAng) = st_lay(3);
7573 20757 : blind.VisBackBeamBeamRefl(ISlatAng, IProfAng) = st_lay(4);
7574 20757 : blind.VisFrontBeamDiffTrans(ISlatAng, IProfAng) = st_lay(5);
7575 20757 : blind.VisFrontBeamDiffRefl(ISlatAng, IProfAng) = st_lay(6);
7576 20757 : blind.VisBackBeamDiffTrans(ISlatAng, IProfAng) = st_lay(7);
7577 20757 : blind.VisBackBeamDiffRefl(ISlatAng, IProfAng) = st_lay(8);
7578 : }
7579 :
7580 41514 : if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) break;
7581 : } // End of loop over slat angles
7582 : } // End of loop over profile angles
7583 :
7584 42 : if (ISolVis == 1) {
7585 564 : for (int ISlatAng = 1; ISlatAng <= Material::MaxSlatAngs; ++ISlatAng) {
7586 1122 : blind.SolFrontDiffDiffTransGnd(ISlatAng) =
7587 1122 : DiffuseAverageProfAngGnd(blind.SolFrontBeamBeamTrans(ISlatAng, {1, Material::MaxProfAngs})) +
7588 561 : DiffuseAverageProfAngGnd(blind.SolFrontBeamDiffTrans(ISlatAng, {1, Material::MaxProfAngs}));
7589 1122 : blind.SolFrontDiffDiffTransSky(ISlatAng) =
7590 1122 : DiffuseAverageProfAngSky(blind.SolFrontBeamBeamTrans(ISlatAng, {1, Material::MaxProfAngs})) +
7591 561 : DiffuseAverageProfAngSky(blind.SolFrontBeamDiffTrans(ISlatAng, {1, Material::MaxProfAngs}));
7592 561 : blind.SolFrontDiffAbsGnd(ISlatAng) = DiffuseAverageProfAngGnd(blind.SolFrontBeamAbs(ISlatAng, {1, Material::MaxProfAngs}));
7593 561 : blind.SolFrontDiffAbsSky(ISlatAng) = DiffuseAverageProfAngSky(blind.SolFrontBeamAbs(ISlatAng, {1, Material::MaxProfAngs}));
7594 1122 : blind.SolFrontDiffDiffReflGnd(ISlatAng) =
7595 561 : DiffuseAverageProfAngGnd(blind.SolFrontBeamDiffRefl(ISlatAng, {1, Material::MaxProfAngs}));
7596 1122 : blind.SolFrontDiffDiffReflSky(ISlatAng) =
7597 561 : DiffuseAverageProfAngSky(blind.SolFrontBeamDiffRefl(ISlatAng, {1, Material::MaxProfAngs}));
7598 :
7599 : // TH 2/17/2010. Added. Loop only for movable slat blinds
7600 561 : if (blind.SlatAngleType == DataWindowEquivalentLayer::AngleType::Fixed) break;
7601 : }
7602 : }
7603 :
7604 : } // End of loop over solar vs. visible properties
7605 :
7606 : } // End of loop over blinds
7607 18 : } // CalcWindowBlindProperties()
7608 :
7609 : //*************************************************************************************
7610 :
7611 2 : void CalcWindowScreenProperties(EnergyPlusData &state)
7612 : {
7613 :
7614 : // SUBROUTINE INFORMATION:
7615 : // AUTHOR Richard Raustad
7616 : // DATE WRITTEN April 2006
7617 : // MODIFIED na
7618 : // RE-ENGINEERED na
7619 :
7620 : // PURPOSE OF THIS SUBROUTINE:
7621 : // Initialize static properties of window screens.
7622 :
7623 : // METHODOLOGY EMPLOYED:
7624 : // Loop through all surfaces to determine which window has an exterior screen. Static
7625 : // variables are defined here, dynamic variables are calculated in CalcScreenTransmittance.
7626 :
7627 : // Locals
7628 : // SUBROUTINE PARAMETER DEFINITIONS:
7629 2 : int constexpr M(18);
7630 2 : int constexpr N(18);
7631 :
7632 : int ScreenNum; // Index to each screen used on exterior of window
7633 : int ConstrNumSh; // Index to shaded construction
7634 : int MatNum; // Index to material number
7635 : Real64 SumTrans; // Integration variable for transmittance
7636 : Real64 SumTransVis; // Integration variable for visible transmittance
7637 : Real64 SumReflect; // Integration variable for reflectance
7638 : Real64 SumReflectVis; // Integration variable for visible reflectance
7639 : Real64 SumArea; // Integration variable for area of quarter hemisphere
7640 : bool FoundMaterial; // Flag to avoid printing screen transmittance data multiple times when Material:WindowScreen
7641 : // is used on multiple surfaces
7642 : bool PrintTransMap; // Flag used to print transmittance map
7643 :
7644 2 : ScreenNum = 0;
7645 :
7646 : // Pre-calculate these constants
7647 2 : std::vector<Real64> sunAzimuth;
7648 2 : std::vector<Real64> sin_sunAzimuth;
7649 2 : std::vector<Real64> cos_sunAzimuth;
7650 2 : std::vector<Real64> sunAltitude;
7651 2 : std::vector<Real64> sin_sunAltitude;
7652 2 : std::vector<Real64> cos_sunAltitude;
7653 2 : std::vector<Real64> skyArea; // Area of integration
7654 2 : Array2D<Real64> relativeAzimuth; // Relative azimuth angle of sun with respect to surface outward normal
7655 2 : Array2D<Real64> relativeAltitude; // Relative altitude angle of sun with respect to surface outward normal
7656 :
7657 2 : relativeAzimuth.allocate(N, M);
7658 2 : relativeAltitude.allocate(N, M);
7659 :
7660 38 : for (int j = 0; j <= N - 1; ++j) {
7661 36 : Real64 currAzimuth = (90.0 / N) * j * Constant::DegToRadians;
7662 36 : sunAzimuth.push_back(currAzimuth); // Azimuth angle of sun during integration
7663 36 : sin_sunAzimuth.push_back(std::sin(currAzimuth));
7664 36 : cos_sunAzimuth.push_back(std::cos(currAzimuth));
7665 : }
7666 :
7667 38 : for (int i = 0; i <= M - 1; ++i) {
7668 36 : Real64 currAltitude = (90.0 / M) * i * Constant::DegToRadians;
7669 36 : sunAltitude.push_back(currAltitude); // Altitude angle of sun during integration
7670 36 : sin_sunAltitude.push_back(std::sin(currAltitude));
7671 36 : cos_sunAltitude.push_back(std::cos(currAltitude));
7672 36 : skyArea.push_back(sin_sunAltitude[i] * cos_sunAltitude[i]);
7673 : }
7674 :
7675 38 : for (int j = 1; j <= N; ++j) {
7676 684 : for (int i = 1; i <= M; ++i) {
7677 : // Integrate transmittance using coordinate transform
7678 648 : relativeAzimuth(i, j) = std::asin(sin_sunAltitude[i - 1] * cos_sunAzimuth[j - 1]); // phi prime
7679 648 : relativeAltitude(i, j) = std::atan(std::tan(sunAltitude[i - 1]) * sin_sunAzimuth[j - 1]); // alpha
7680 : }
7681 : }
7682 :
7683 2 : PrintTransMap = false;
7684 :
7685 192 : for (int SurfNum = 1; SurfNum <= state.dataSurface->TotSurfaces; ++SurfNum) {
7686 190 : auto const &surf = state.dataSurface->Surface(SurfNum);
7687 :
7688 216 : if (!surf.HasShadeControl) continue;
7689 :
7690 28 : if (state.dataSurface->WindowShadingControl(surf.activeWindowShadingControl).ShadingType != WinShadingType::ExtScreen) continue;
7691 :
7692 8 : ConstrNumSh = surf.activeShadedConstruction;
7693 8 : MatNum = state.dataConstruction->Construct(ConstrNumSh).LayerPoint(1);
7694 8 : auto *matScreen = dynamic_cast<Material::MaterialScreen *>(state.dataMaterial->Material(MatNum));
7695 8 : assert(matScreen != nullptr);
7696 8 : state.dataSurface->SurfaceWindow(SurfNum).screenNum = MatNum;
7697 :
7698 8 : if (matScreen->isUsed) continue; // Has already been initalized
7699 :
7700 2 : matScreen->isUsed = true;
7701 2 : if (matScreen->mapDegResolution > 0) PrintTransMap = true;
7702 :
7703 : // If a screen material is used more than once, the Material structure's screen data pointer holds the screen number
7704 : // of the last window surface. Use this method to access the screen parameter's only for static variables such as
7705 : // diffuse properties (InitGlassOpticalCalculations). For all cases where the screen properties are a function of
7706 : // sun azimuth and altitude angles, use the Screens structure.
7707 : // Invert calculation done in GetMaterialInput to find Diameter to Spacing ratio (Props(7)/Props(6))
7708 : // dataMaterial.Material(MaterNum)%Trans = (1 - MaterialProps(7)/MaterialProps(6))**2.0
7709 2 : matScreen->diameterToSpacingRatio = 1.0 - std::sqrt(matScreen->Trans);
7710 :
7711 : // Reflectance of screen material only
7712 2 : matScreen->CylinderRef = matScreen->ShadeRef / (1 - matScreen->Trans);
7713 2 : matScreen->CylinderRefVis = matScreen->ShadeRefVis / (1 - matScreen->Trans);
7714 :
7715 : // Integrate the transmittance over a quarter hemisphere for use in diffuse calculations
7716 2 : SumTrans = 0.0;
7717 2 : SumTransVis = 0.0;
7718 2 : SumReflect = 0.0;
7719 2 : SumReflectVis = 0.0;
7720 2 : SumArea = 0.0;
7721 : // Integration over quarter hemisphere in polar coordinates and converting to rectangular to call screen model.
7722 : // Proceed in reverse order such that the last calculation yields zero sun angle to window screen normal (angles=0,0).
7723 : // The properties calculated at zero sun angle are then used elsewhere prior to the start of the actual simulation.
7724 :
7725 2 : Material::ScreenBmTransAbsRef btar;
7726 :
7727 38 : for (int j = N; j >= 1; --j) {
7728 684 : for (int i = M; i >= 1; --i) {
7729 : // Integrate transmittance using coordinate transform
7730 : // TODO: switch to interpolation?
7731 648 : CalcScreenTransmittance(state, matScreen, relativeAltitude(i, j), relativeAzimuth(i, j), btar);
7732 648 : SumTrans += (btar.BmTrans + btar.DfTrans) * skyArea[i - 1];
7733 648 : SumTransVis += (btar.BmTransVis + btar.DfTransVis) * skyArea[i - 1];
7734 648 : SumReflect += btar.RefSolFront * skyArea[i - 1];
7735 648 : SumReflectVis += btar.RefVisFront * skyArea[i - 1];
7736 648 : SumArea += skyArea[i - 1];
7737 : }
7738 : }
7739 :
7740 : // Reflectance of overall screen including openings and scattered transmittance
7741 2 : matScreen->ShadeRef = matScreen->CylinderRef * (1.0 - (btar.BmTrans + btar.DfTrans));
7742 2 : matScreen->ShadeRefVis = matScreen->CylinderRefVis * (1.0 - (btar.BmTransVis + btar.DfTransVis));
7743 :
7744 2 : if (SumArea != 0) {
7745 2 : matScreen->DfTrans = SumTrans / SumArea;
7746 2 : matScreen->DfTransVis = SumTransVis / SumArea;
7747 2 : matScreen->DfRef = SumReflect / SumArea;
7748 2 : matScreen->DfRefVis = SumReflectVis / SumArea;
7749 : }
7750 2 : matScreen->DfAbs = max(0.0, (1.0 - matScreen->DfTrans - matScreen->DfRef));
7751 :
7752 2 : matScreen->AbsorpThermalBack = matScreen->DfAbs;
7753 2 : matScreen->AbsorpThermalFront = matScreen->DfAbs;
7754 2 : matScreen->ReflectSolBeamFront = matScreen->DfRef;
7755 2 : matScreen->ReflectSolBeamBack = matScreen->DfRef;
7756 :
7757 : // Initialize incident-angle dependent beam matrix (will interpolate from this)
7758 76 : for (int ip = 0; ip < Material::maxIPhi; ++ip) {
7759 74 : Real64 Phi = ip * matScreen->dPhi;
7760 2812 : for (int it = 0; it < Material::maxITheta; ++it) {
7761 2738 : Real64 Theta = it * matScreen->dTheta;
7762 2738 : CalcScreenTransmittance(state, matScreen, Phi, Theta, matScreen->btars[ip][it]);
7763 : }
7764 : }
7765 :
7766 : } // for (SurfNum)
7767 :
7768 : // Write transmittance versus direct normal angle to csv file
7769 :
7770 2 : if (PrintTransMap) {
7771 : // Fortran version did not have error handling in case of file open failure. This one does.
7772 : // Which is correct?
7773 4 : auto screenCsvFile = state.files.screenCsv.open(state, "CalcWindowScreenComponents", state.files.outputControl.screen);
7774 :
7775 : // WRITE(ScreenTransUnitNo,*)' '
7776 41 : for (auto *mat : state.dataMaterial->Material) {
7777 :
7778 39 : if (mat->group != Material::Group::Screen) continue;
7779 2 : if (!mat->isUsed) continue;
7780 :
7781 2 : auto *screen = dynamic_cast<Material::MaterialScreen *>(mat);
7782 2 : assert(screen != nullptr);
7783 :
7784 : // Do not print transmittance map if angle increment is equal to 0
7785 2 : if (screen->mapDegResolution == 0) continue;
7786 :
7787 2 : int maxIPrint = int(90 / screen->mapDegResolution);
7788 :
7789 2 : print(screenCsvFile, "MATERIAL:WINDOWSCREEN:{}\n", screen->Name);
7790 2 : print(screenCsvFile,
7791 : "Tabular data for beam solar transmittance at varying \"relative\" azimuth (row) and "
7792 : "altitude (column) angles (deg) [relative to surface normal].\n");
7793 40 : for (int it = maxIPrint; it >= 0; --it) {
7794 38 : print(screenCsvFile, ",{}", it * screen->mapDegResolution);
7795 : }
7796 2 : print(screenCsvFile, "\n");
7797 :
7798 40 : for (int it = 0; it <= maxIPrint; ++it) {
7799 38 : print(screenCsvFile, "{}", it * screen->mapDegResolution);
7800 760 : for (int ip = maxIPrint; ip >= 0; --ip) {
7801 722 : Real64 phi = ip * screen->mapDegResolution * Constant::DegToRad;
7802 722 : Real64 theta = it * screen->mapDegResolution * Constant::DegToRad;
7803 : int ip1, ip2, it1, it2;
7804 : General::BilinearInterpCoeffs coeffs;
7805 722 : Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2);
7806 722 : GetBilinearInterpCoeffs(
7807 722 : phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs);
7808 722 : Real64 bmTrans = BilinearInterp(screen->btars[ip1][it1].BmTrans,
7809 722 : screen->btars[ip1][it2].BmTrans,
7810 722 : screen->btars[ip2][it1].BmTrans,
7811 722 : screen->btars[ip2][it2].BmTrans,
7812 722 : coeffs);
7813 : // bmTrans = screen->btars[ip][it].BmTrans;
7814 722 : print(screenCsvFile, ",{:.6R}", bmTrans);
7815 : }
7816 38 : print(screenCsvFile, "\n");
7817 : }
7818 2 : print(screenCsvFile, "\n\n");
7819 :
7820 2 : print(screenCsvFile, "MATERIAL:WINDOWSCREEN:{}\n", screen->Name);
7821 2 : print(screenCsvFile,
7822 : "Tabular data for scattered solar transmittance at varying \"relative\" azimuth (row) and "
7823 : "altitude (column) angles (deg) [relative to surface normal].\n");
7824 :
7825 40 : for (int it = 0; it <= maxIPrint; ++it) {
7826 38 : print(screenCsvFile, ",{}", it * screen->mapDegResolution);
7827 : }
7828 2 : print(screenCsvFile, "\n");
7829 :
7830 40 : for (int it = 0; it <= maxIPrint; ++it) {
7831 38 : print(screenCsvFile, "{}", it * screen->mapDegResolution);
7832 760 : for (int ip = 0; ip <= maxIPrint; ++ip) {
7833 722 : Real64 phi = ip * screen->mapDegResolution * Constant::DegToRad;
7834 722 : Real64 theta = it * screen->mapDegResolution * Constant::DegToRad;
7835 : int ip1, ip2, it1, it2;
7836 : General::BilinearInterpCoeffs coeffs;
7837 722 : Material::GetPhiThetaIndices(phi, theta, screen->dPhi, screen->dTheta, ip1, ip2, it1, it2);
7838 722 : GetBilinearInterpCoeffs(
7839 722 : phi, theta, ip1 * screen->dPhi, ip2 * screen->dPhi, it1 * screen->dTheta, it2 * screen->dTheta, coeffs);
7840 722 : Real64 dfTrans = BilinearInterp(screen->btars[ip1][it1].DfTrans,
7841 722 : screen->btars[ip1][it2].DfTrans,
7842 722 : screen->btars[ip2][it1].DfTrans,
7843 722 : screen->btars[ip2][it2].DfTrans,
7844 722 : coeffs);
7845 :
7846 : // dfTrans = screen->btars[ip][it].DfTrans;
7847 722 : print(screenCsvFile, ",{:.6R}", dfTrans);
7848 : }
7849 38 : print(screenCsvFile, "\n");
7850 : }
7851 2 : print(screenCsvFile, "\n\n");
7852 2 : }
7853 2 : } // if (PrintTransMap)
7854 2 : } // CalcWindowScreenProperties()
7855 :
7856 1122 : void BlindOpticsDiffuse(EnergyPlusData &state,
7857 : int const BlindNum, // Blind number
7858 : int const ISolVis, // 1 = solar and IR calculation; 2 = visible calculation
7859 : Array1A<Real64> const c, // Slat properties
7860 : Real64 const b_el, // Slat elevation (radians)
7861 : Array1A<Real64> p // Blind properties
7862 : )
7863 : {
7864 :
7865 : // SUBROUTINE INFORMATION:
7866 : // AUTHOR Hans Simmler
7867 : // DATE WRITTEN July-Aug 1995
7868 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
7869 : // Aug 2002 (FCW): make corrections so that calculations are consistent with
7870 : // G(i) = Sum over j of J(j)*F(j,i). Previously, i,j was
7871 : // interchanged in F, so that
7872 : // G(i) = Sum over j of J(j)*F(i,j), which is wrong.
7873 : // This change was made to resolve discrepancies between EnergyPlus results
7874 : // and blind transmittance measurements made at Oklahoma State Univ.
7875 : // Feb 2004 (FCW): modify slat edge correction calc to avoid possible divide by zero
7876 : // RE-ENGINEERED na
7877 :
7878 : // PURPOSE OF THIS SUBROUTINE:
7879 : // From the slat properties, calculates the diffuse solar, diffuse visible and IR
7880 : // transmission and reflection properties of a window blind.
7881 :
7882 : // METHODOLOGY EMPLOYED:
7883 : // na
7884 :
7885 : // REFERENCES:
7886 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
7887 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
7888 :
7889 : // Argument array dimensioning
7890 1122 : c.dim(15);
7891 1122 : p.dim(16);
7892 :
7893 : Real64 ri; // Front and back IR slat reflectance
7894 : Real64 rib;
7895 : Real64 phib; // Elevation of slat normal vector (radians)
7896 : Real64 phis; // Source elevation (radians)
7897 : Real64 delphis; // Angle increment for integration over source distribution (radians)
7898 1122 : Array1D<Real64> fEdgeSource(10); // Slat edge correction factor vs source elevation
7899 1122 : Array1D<Real64> fEdgeA(2); // Average slat edge correction factor for upper and lower quadrants
7900 : // seen by window blind
7901 : Real64 gamma; // phib - phis
7902 : int Iphis; // Source elevation counter
7903 : int IUpDown; // =1 for source in upper quadrant, =2 for source in lower quadrant
7904 : Real64 fEdge; // Slat edge correction factor
7905 : Real64 fEdge1;
7906 1122 : Array1D<Real64> j(6); // Slat section radiosity vector
7907 1122 : Array1D<Real64> G(6); // Slat section irradiance vector
7908 1122 : Array1D<Real64> Q(6); // Slat section radiance vector
7909 2244 : Array2D<Real64> F(6, 6); // View factor array
7910 2244 : Array2D<Real64> X(4, 4); // Exchange matrix
7911 2244 : Array2D<Real64> Xinv(4, 4); // Inverse of exchange matrix
7912 : int k; // Array indices
7913 : int m;
7914 1122 : Array1D_int indx(4); // LU decomposition indices
7915 : Real64 BlindIRreflFront; // Blind front IR reflectance
7916 : Real64 BlindIRreflBack; // Blind back IR reflectance
7917 :
7918 : // The slat input properties are:
7919 : // c(1) 0. (unused)
7920 : // c(2) Slat width (m)
7921 : // c(3) Slat separation (m)
7922 : // c(4) 0. (unused)
7923 : // c(5) 0. (unused)
7924 : // c(6) 0. (unused)
7925 : // The following are solar or visible properties
7926 : // c(7) trans beam-diff
7927 : // c(8) refl front beam-diff
7928 : // c(9) refl back beam-diff
7929 : // c(10) trans diff-diff
7930 : // c(11) refl front diff-diff
7931 : // c(12) refl back diff-diff
7932 : // The following are hemispherical thermal IR properties
7933 : // c(13) trans diff-diff
7934 : // c(14) emiss front diff
7935 : // c(15) emiss back diff
7936 :
7937 : // The calculated blind properties are:
7938 : // The following are solar or visible properties
7939 : // p(1) trans front beam-beam
7940 : // p(2) refl front beam-beam
7941 : // p(3) trans back beam-beam
7942 : // p(4) refl back beam-beam
7943 : // p(5) trans front beam-diff
7944 : // p(6) refl front beam-diff
7945 : // p(7) trans back beam-diff
7946 : // p(8) refl back beam-diff
7947 : // p(9) trans front diff-diff
7948 : // p(10) refl front diff-diff
7949 : // p(11) trans back diff-diff
7950 : // p(12) refl back diff-diff
7951 : // The following are IR properties
7952 : // p(13) IR trans front (same as IR trans back)
7953 : // p(14) IR emissivity front
7954 : // p(15) IR emissivity back
7955 : // p(16) 0.0 (unused)
7956 :
7957 1122 : auto &blind = state.dataMaterial->Blind(BlindNum);
7958 : // Calculate view factors between slat sections (slat is divided longitudinally into two equal parts)
7959 :
7960 1122 : ViewFac(c(2), c(3), b_el, Constant::PiOvr2, F);
7961 :
7962 : // Set up exchange matrix X for diffuse properties
7963 :
7964 3366 : for (int k = 3; k <= 5; k += 2) {
7965 11220 : for (int m = 3; m <= 6; ++m) {
7966 8976 : X(m - 2, k - 2) = -c(12) * F(k, m) - c(10) * F(k + 1, m);
7967 8976 : X(m - 2, k - 1) = -c(10) * F(k, m) - c(11) * F(k + 1, m);
7968 : }
7969 : }
7970 :
7971 5610 : for (int k = 1; k <= 4; ++k) {
7972 4488 : ++X(k, k);
7973 : }
7974 :
7975 1122 : indx = 0;
7976 1122 : InvertMatrix(state, X, Xinv, indx, 4); // Autodesk:Note X modified by this call
7977 :
7978 : //---------Calculate diffuse short-wave properties for the front side of the blind
7979 :
7980 : // Sources
7981 :
7982 1122 : Q(3) = c(12) * F(3, 1) + c(10) * F(4, 1);
7983 1122 : Q(4) = c(10) * F(3, 1) + c(11) * F(4, 1);
7984 1122 : Q(5) = c(12) * F(5, 1) + c(10) * F(6, 1);
7985 1122 : Q(6) = c(10) * F(5, 1) + c(11) * F(6, 1);
7986 :
7987 : // Radiosities
7988 :
7989 1122 : j(1) = 1.0;
7990 1122 : j(2) = 0.0;
7991 5610 : for (int k = 3; k <= 6; ++k) {
7992 4488 : j(k) = 0.0;
7993 22440 : for (int m = 3; m <= 6; ++m) {
7994 17952 : j(k) += Xinv(m - 2, k - 2) * Q(m);
7995 : }
7996 : }
7997 :
7998 : // Irradiances
7999 :
8000 7854 : for (int k = 1; k <= 6; ++k) {
8001 6732 : G(k) = 0.0;
8002 47124 : for (int m = 1; m <= 6; ++m) {
8003 : // G(k)=G(k)+F(k,m)*J(m)
8004 40392 : G(k) += j(m) * F(k, m);
8005 : }
8006 : }
8007 :
8008 : // Slat edge correction factor
8009 1122 : phib = b_el;
8010 1122 : delphis = Constant::PiOvr2 / 10.0;
8011 3366 : for (int IUpDown = 1; IUpDown <= 2; ++IUpDown) {
8012 24684 : for (int Iphis = 1; Iphis <= 10; ++Iphis) {
8013 22440 : phis = -(Iphis - 0.5) * delphis;
8014 22440 : if (IUpDown == 2) phis = (Iphis - 0.5) * delphis;
8015 22440 : fEdgeSource(Iphis) = 0.0;
8016 22440 : fEdge1 = 0.0;
8017 22440 : gamma = phib - phis;
8018 22440 : if (std::abs(std::sin(gamma)) > 0.01) {
8019 22200 : if ((phib > 0.0 && phib <= Constant::PiOvr2 && phis <= phib) ||
8020 10720 : (phib > Constant::PiOvr2 && phib <= Constant::Pi && phis > -(Constant::Pi - phib))) {
8021 16620 : fEdge1 = blind.SlatThickness * std::abs(std::sin(gamma)) /
8022 16620 : ((blind.SlatSeparation + blind.SlatThickness / std::abs(std::sin(phib))) * std::cos(phis));
8023 : }
8024 22200 : fEdgeSource(Iphis) = min(1.0, std::abs(fEdge1));
8025 : }
8026 : }
8027 2244 : fEdgeA(IUpDown) = DiffuseAverage(fEdgeSource);
8028 : }
8029 1122 : fEdge = 0.5 * (fEdgeA(1) + fEdgeA(2));
8030 :
8031 : // Front diffuse-diffuse transmittance (transmittance of slat edge assumed zero)
8032 1122 : p(9) = G(2) * (1.0 - fEdge);
8033 :
8034 : // Front diffuse-diffuse reflectance (edge of slat is assumed to have same diffuse
8035 : // reflectance as front side of slat, c(11))
8036 1122 : p(10) = G(1) * (1.0 - fEdge) + fEdge * c(11);
8037 :
8038 : //-----------Calculate diffuse short-wave properties for the back side of the blind
8039 :
8040 : // Sources
8041 :
8042 1122 : Q(3) = c(12) * F(3, 2) + c(10) * F(4, 2);
8043 1122 : Q(4) = c(10) * F(3, 2) + c(11) * F(4, 2);
8044 1122 : Q(5) = c(12) * F(5, 2) + c(10) * F(6, 2);
8045 1122 : Q(6) = c(10) * F(5, 2) + c(11) * F(6, 2);
8046 :
8047 : // Radiosities
8048 :
8049 1122 : j(1) = 0.0;
8050 1122 : j(2) = 1.0;
8051 5610 : for (int k = 3; k <= 6; ++k) {
8052 4488 : j(k) = 0.0;
8053 22440 : for (int m = 3; m <= 6; ++m) {
8054 17952 : j(k) += Xinv(m - 2, k - 2) * Q(m);
8055 : }
8056 : }
8057 :
8058 : // Irradiances
8059 :
8060 7854 : for (int k = 1; k <= 6; ++k) {
8061 6732 : G(k) = 0.0;
8062 47124 : for (int m = 1; m <= 6; ++m) {
8063 : // G(k)=G(k)+F(k,m)*J(m)
8064 40392 : G(k) += j(m) * F(k, m);
8065 : }
8066 : }
8067 :
8068 : // Back diffuse-diffuse transmittance
8069 1122 : p(11) = G(1) * (1.0 - fEdge);
8070 :
8071 : // Back hemi-hemi reflectance
8072 1122 : p(12) = G(2) * (1.0 - fEdge) + fEdge * c(11);
8073 :
8074 1122 : if (ISolVis == 1) {
8075 :
8076 : //-----------Calculate IR properties of the blind
8077 : // (use same set of view factors as for diffuse short-wave properties)
8078 :
8079 : // Front and back slat IR reflectances
8080 561 : ri = 1 - c(13) - c(14);
8081 561 : rib = 1 - c(13) - c(15);
8082 :
8083 : // Set up exchange matrix X for diffuse properties
8084 :
8085 1683 : for (int k = 3; k <= 5; k += 2) {
8086 5610 : for (int m = 3; m <= 6; ++m) {
8087 4488 : X(m - 2, k - 2) = -rib * F(k, m) - c(13) * F(k + 1, m);
8088 4488 : X(m - 2, k - 1) = -c(13) * F(k, m) - ri * F(k + 1, m);
8089 : }
8090 : }
8091 :
8092 2805 : for (int k = 1; k <= 4; ++k) {
8093 2244 : ++X(k, k);
8094 : }
8095 :
8096 561 : indx = 0;
8097 561 : InvertMatrix(state, X, Xinv, indx, 4); // Autodesk:Note X modified by this call
8098 :
8099 : //---------Calculate diffuse IR properties for the FRONT side of the blind
8100 :
8101 : // Sources
8102 :
8103 561 : Q(3) = rib * F(3, 1) + c(13) * F(4, 1);
8104 561 : Q(4) = c(13) * F(3, 1) + ri * F(4, 1);
8105 561 : Q(5) = rib * F(5, 1) + c(13) * F(6, 1);
8106 561 : Q(6) = c(13) * F(5, 1) + ri * F(6, 1);
8107 :
8108 : // Radiosities
8109 :
8110 561 : j(1) = 1.0;
8111 561 : j(2) = 0.0;
8112 2805 : for (int k = 3; k <= 6; ++k) {
8113 2244 : j(k) = 0.0;
8114 11220 : for (int m = 3; m <= 6; ++m) {
8115 8976 : j(k) += Xinv(m - 2, k - 2) * Q(m);
8116 : }
8117 : }
8118 :
8119 : // Irradiances
8120 3927 : for (int k = 1; k <= 6; ++k) {
8121 3366 : G(k) = 0.0;
8122 23562 : for (int m = 1; m <= 6; ++m) {
8123 : // G(k)=G(k)+F(k,m)*J(m)
8124 20196 : G(k) += j(m) * F(k, m);
8125 : }
8126 : }
8127 :
8128 : // Front diffuse-diffuse IR transmittance (transmittance of slat edge assumed zero)
8129 561 : p(13) = G(2) * (1.0 - fEdge);
8130 :
8131 : // Front diffuse-diffuse IR reflectance (edge of slat is assumed to have same IR
8132 : // reflectance as front side of slat, ri)
8133 561 : BlindIRreflFront = G(1) * (1.0 - fEdge) + fEdge * ri;
8134 :
8135 : // Front IR emissivity
8136 561 : p(14) = max(0.0001, 1.0 - p(13) - BlindIRreflFront);
8137 :
8138 : //-----------Calculate diffuse IR properties for the BACK side of the blind
8139 :
8140 : // Sources
8141 :
8142 561 : Q(3) = rib * F(3, 2) + c(13) * F(4, 2);
8143 561 : Q(4) = c(13) * F(3, 2) + ri * F(4, 2);
8144 561 : Q(5) = rib * F(5, 2) + c(13) * F(6, 2);
8145 561 : Q(6) = c(13) * F(5, 2) + ri * F(6, 2);
8146 :
8147 : // Radiosities
8148 :
8149 561 : j(1) = 0.0;
8150 561 : j(2) = 1.0;
8151 2805 : for (int k = 3; k <= 6; ++k) {
8152 2244 : j(k) = 0.0;
8153 11220 : for (int m = 3; m <= 6; ++m) {
8154 8976 : j(k) += Xinv(m - 2, k - 2) * Q(m);
8155 : }
8156 : }
8157 :
8158 : // Irradiances
8159 :
8160 3927 : for (int k = 1; k <= 6; ++k) {
8161 3366 : G(k) = 0.0;
8162 23562 : for (int m = 1; m <= 6; ++m) {
8163 : // G(k)=G(k)+F(k,m)*J(m)
8164 20196 : G(k) += j(m) * F(k, m);
8165 : }
8166 : }
8167 :
8168 : // Back diffuse-diffuse IR reflectance
8169 561 : BlindIRreflBack = G(2) * (1.0 - fEdge) + fEdge * ri;
8170 :
8171 : // Back IR emissivity
8172 561 : p(15) = max(0.0001, 1.0 - p(13) - BlindIRreflBack);
8173 :
8174 : } // End of IR properties calculation
8175 1122 : } // BlindOpticsDiffuse()
8176 :
8177 : //**********************************************************************************************
8178 :
8179 41514 : void BlindOpticsBeam(EnergyPlusData &state,
8180 : int const BlindNum, // Blind number
8181 : Array1A<Real64> const c, // Slat properties (equivalent to BLD_PR)
8182 : Real64 const b_el, // Slat elevation (radians)
8183 : Real64 const s_el, // Solar profile angle (radians)
8184 : Array1A<Real64> p // Blind properties (equivalent to ST_LAY)
8185 : )
8186 : {
8187 :
8188 : // SUBROUTINE INFORMATION:
8189 : // AUTHOR Hans Simmler
8190 : // DATE WRITTEN July-Aug 1995
8191 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
8192 : // Aug 2002 (FCW): make corrections so that calculations are consistent with
8193 : // G(i) = Sum over j of J(j)*F(j,i). Previously, i,j was
8194 : // interchanged in F, so that
8195 : // G(i) = Sum over j of J(j)*F(i,j), which is wrong.
8196 : // This change was made to resolve discrepancies between EnergyPlus results
8197 : // and blind transmittance measurements made at Oklahoma State Univ.
8198 : // RE-ENGINEERED na
8199 :
8200 : // PURPOSE OF THIS SUBROUTINE:
8201 : // Calculates the beam radiation properties of a
8202 : // window blind consisting of flat slats with known material properties.
8203 : // The calculation for the reverse direction is done with the radiation source
8204 : // reflected at the window plane.
8205 :
8206 : // REFERENCES:
8207 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
8208 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
8209 :
8210 : // Argument array dimensioning
8211 41514 : c.dim(15);
8212 41514 : p.dim(16);
8213 :
8214 : struct BlindInputs
8215 : {
8216 : Real64 slatWidth;
8217 : Real64 slatSeparation;
8218 : Real64 BmDfTrans;
8219 : Real64 BmDfRefFront;
8220 : Real64 BmDfRefBack;
8221 : Real64 DfDfTrans;
8222 : Real64 DfDfRefFront;
8223 : Real64 DfDfRefBack;
8224 : Real64 DfDfTransIR;
8225 : Real64 DfEmissFront;
8226 : Real64 DfEmissBack;
8227 : };
8228 :
8229 : // The slat input properties are:
8230 : // c(1) 0. (unused)
8231 : // c(2) Slat width (m)
8232 : // c(3) Slat separation (m)
8233 : // c(4) 0. (unused)
8234 : // c(5) 0. (unused)
8235 : // c(6) 0. (unused)
8236 : // The following are solar or visible properties
8237 : // c(7) trans beam-diff
8238 : // c(8) refl front beam-diff
8239 : // c(9) refl back beam-diff
8240 : // c(10) trans diff-diff
8241 : // c(11) refl front diff-diff
8242 : // c(12) refl back diff-diff
8243 : // The following are hemispherical thermal IR properties
8244 : // c(13) trans diff-diff
8245 : // c(14) emiss front diff
8246 : // c(15) emiss back diff
8247 :
8248 : struct BlindOutputs
8249 : {
8250 : Real64 BmBmTransFront;
8251 : Real64 BmBmRefFront;
8252 : Real64 BmBmTransBack;
8253 : Real64 BmBmRefBack;
8254 : Real64 BmDfTransFront;
8255 : Real64 BmDfRefFront;
8256 : Real64 BmDfTransBack;
8257 : Real64 BmDfRefBack;
8258 : Real64 DfDfTransFront;
8259 : Real64 DfDfRefFront;
8260 : Real64 DfDfTransBack;
8261 : Real64 DfDfRefBack;
8262 :
8263 : Real64 TransFrontIR;
8264 : Real64 TransBackIR;
8265 : Real64 EmissFrontIR;
8266 : Real64 EmissBackIR;
8267 : };
8268 :
8269 : // The calculated blind properties are:
8270 : // The following are solar or visible properties
8271 : // p(1) trans front beam-beam
8272 : // p(2) refl front beam-beam
8273 : // p(3) trans back beam-beam
8274 : // p(4) refl back beam-beam
8275 : // p(5) trans front beam-diff
8276 : // p(6) refl front beam-diff
8277 : // p(7) trans back beam-diff
8278 : // p(8) refl back beam-diff
8279 : // p(9) trans front diff-diff
8280 : // p(10) refl front diff-diff
8281 : // p(11) trans back diff-diff
8282 : // p(12) refl back diff-diff
8283 : // The following are IR properties
8284 : // p(13) IR trans front (same as IR trans back)
8285 : // p(14) IR emissivity front
8286 : // p(15) IR emissivity back
8287 : // p(16) 0.0 (unused)
8288 :
8289 : Real64 phib; // Elevation angle of normal vector to front of slat (0 to pi radians)
8290 : Real64 phis; // Elevation angle of source vector; same as "profile angle" (-pi/2 to pi/2 radians)
8291 : Real64 gamma; // phib - phis (radians)
8292 41514 : Array1D<Real64> j(6); // Slat surface section radiosity vector
8293 41514 : Array1D<Real64> G(6); // Slat surface section irradiance vector
8294 41514 : Array1D<Real64> Q(6); // Slat surface section source vector
8295 83028 : Array2D<Real64> F(6, 6); // View factor array
8296 83028 : Array2D<Real64> X(4, 4); // X*J = Q
8297 83028 : Array2D<Real64> Xinv(4, 4); // J = Xinv*Q
8298 : Real64 fEdge; // Slat edge correction factor
8299 : Real64 fEdge1;
8300 41514 : Array1D_int indx(4); // Indices for LU decomposition
8301 :
8302 41514 : auto const &blind = state.dataMaterial->Blind(BlindNum);
8303 :
8304 41514 : p = 0.0;
8305 :
8306 : // Elevation of radiation source; source is assumed to be in a plane that
8307 : // (1) contains the slat outward normal and (2) is perpendicular to plane of the blinds.
8308 41514 : phis = s_el;
8309 :
8310 : // Elevation of slat outward normal
8311 41514 : phib = b_el;
8312 :
8313 : // Loop twice for front and back side properties of blind
8314 124542 : for (int i = 0; i <= 2; i += 2) {
8315 :
8316 : // For back-side properties, reflect the source position so that it is the mirror
8317 : // image of the original source position, where the "mirror" is in the plane of the
8318 : // blinds. This is equivalent to keeping the original source position but rotating
8319 : // the slats so that the original slat angle (e.g., 45 deg) becomes 180 - original slat
8320 : // angle (135 deg).
8321 :
8322 83028 : if (i == 2) {
8323 41514 : phib = Constant::Pi - phib;
8324 : }
8325 :
8326 : // Correction factor that accounts for finite thickness of slats. It is used to modify the
8327 : // blind transmittance and reflectance to account for reflection and absorption by the
8328 : // edge of the slat. fEdge is ratio of area subtended by edge of slat
8329 : // to area between tops of adjacent slats.
8330 :
8331 83028 : fEdge = 0.0;
8332 83028 : fEdge1 = 0.0;
8333 83028 : gamma = phib - phis;
8334 83028 : if (std::abs(std::sin(gamma)) > 0.01) {
8335 82500 : if ((phib > 0.0 && phib <= Constant::PiOvr2 && phis <= phib) ||
8336 41040 : (phib > Constant::PiOvr2 && phib <= Constant::Pi && phis > -(Constant::Pi - phib))) {
8337 61116 : fEdge1 = blind.SlatThickness * std::abs(std::sin(gamma)) /
8338 61116 : ((blind.SlatSeparation + blind.SlatThickness / std::abs(std::sin(phib))) * std::cos(phis));
8339 : }
8340 82500 : fEdge = min(1.0, std::abs(fEdge1));
8341 : }
8342 :
8343 : // Direct-to-direct transmittance (portion of beam that passes between slats without
8344 : // without touching them
8345 :
8346 83028 : p(1 + i) = BlindBeamBeamTrans(phis, phib, blind.SlatWidth, blind.SlatSeparation, blind.SlatThickness);
8347 : // Direct-to-direct reflectance; this is zero for now since all reflection is assumed to be diffuse.
8348 83028 : p(2 + i) = 0.0;
8349 :
8350 : // View factors between slat sections for calculating direct-to-diffuse transmittance and reflectance
8351 83028 : ViewFac(c(2), c(3), phib, phis, F);
8352 :
8353 : // Set up exchange matrix X for calculating direct-to-diffuse properties
8354 :
8355 249084 : for (int k = 3; k <= 5; k += 2) {
8356 830280 : for (int m = 3; m <= 6; ++m) {
8357 664224 : X(m - 2, k - 2) = -c(12) * F(k, m) - c(10) * F(k + 1, m);
8358 664224 : X(m - 2, k - 1) = -c(10) * F(k, m) - c(11) * F(k + 1, m);
8359 : }
8360 : }
8361 :
8362 415140 : for (int k = 1; k <= 4; ++k) {
8363 332112 : ++X(k, k);
8364 : }
8365 :
8366 83028 : indx = 0;
8367 : // In the following, note that InvertMatrix changes X
8368 83028 : InvertMatrix(state, X, Xinv, indx, 4);
8369 :
8370 : // Set up sources for direct-diffuse slat properties
8371 83028 : if (std::abs(phis - phib) <= Constant::PiOvr2) { // Beam hits front of slat
8372 41706 : Q(3) = c(4) + c(7); // beam-beam trans of slat + beam-diff trans of slat
8373 41706 : Q(4) = c(5) + c(8); // front beam-beam refl of slat + front beam-diff refl of slat
8374 : } else { // Beam hits back of slat
8375 41322 : Q(3) = c(6) + c(9); // back beam-beam refl of slat + back beam-diff refl of slat
8376 41322 : Q(4) = c(4) + c(7); // beam-beam trans of slat + beam-diff trans of slat
8377 : }
8378 :
8379 : // Correct for fraction of beam that is not directly transmitted; 1 - this fraction is
8380 : // the fraction of the incoming beam that is incident on the front or back surfaces of the slats.
8381 83028 : Q(3) *= (1.0 - p(1 + i));
8382 83028 : Q(4) *= (1.0 - p(1 + i));
8383 :
8384 : // Radiosities (radiance of slat sections)
8385 83028 : j(1) = 0.0;
8386 83028 : j(2) = 0.0;
8387 415140 : for (int k = 3; k <= 6; ++k) {
8388 332112 : j(k) = 0.0;
8389 996336 : for (int m = 3; m <= 4; ++m) {
8390 664224 : j(k) += Xinv(m - 2, k - 2) * Q(m);
8391 : }
8392 : }
8393 :
8394 : // Irradiance on slat sections
8395 581196 : for (int k = 1; k <= 6; ++k) {
8396 498168 : G(k) = 0.0;
8397 2490840 : for (int m = 3; m <= 6; ++m) {
8398 1992672 : G(k) += j(m) * F(k, m);
8399 : }
8400 : }
8401 :
8402 : // Direct-to-diffuse transmittance
8403 83028 : p(5 + i) = G(2) * (1.0 - fEdge);
8404 :
8405 : // Direct-to-diffuse reflectance (assuming the edge reflectance is the same as the
8406 : // reflectance of the front side of the slat, C(8))
8407 83028 : p(6 + i) = G(1) * (1.0 - fEdge) + fEdge * c(8);
8408 :
8409 : } // End of loop over front and back side properties of blind
8410 41514 : } // BlindOpticsBeam()
8411 :
8412 80784 : Real64 InterpProfAng(Real64 const ProfAng, // Profile angle (rad)
8413 : Array1S<Real64> const PropArray // Array of blind properties
8414 : )
8415 : {
8416 :
8417 : // SUBROUTINE INFORMATION:
8418 : // AUTHOR Fred Winkelmann
8419 : // DATE WRITTEN May 2001
8420 : // MODIFIED na
8421 : // RE-ENGINEERED na
8422 :
8423 : // PURPOSE OF THIS SUBROUTINE:
8424 : // Does profile-angle interpolation of window blind solar-thermal properties
8425 :
8426 : // METHODOLOGY EMPLOYED:
8427 : // Linear interpolation.
8428 :
8429 : // DeltaAng = Pi/36
8430 80784 : if (ProfAng > Constant::PiOvr2 || ProfAng < -Constant::PiOvr2) {
8431 0 : return 0.0;
8432 : } else {
8433 80784 : Real64 constexpr DeltaAngRad(Constant::Pi / 36.0); // Profile angle increment (rad)
8434 80784 : int IAlpha = 1 + int((ProfAng + Constant::PiOvr2) / DeltaAngRad); // Profile angle index
8435 80784 : Real64 InterpFac = (ProfAng - (-Constant::PiOvr2 + DeltaAngRad * (IAlpha - 1))) / DeltaAngRad; // Interpolation factor
8436 80784 : return (1.0 - InterpFac) * PropArray(IAlpha) + InterpFac * PropArray(IAlpha + 1);
8437 : }
8438 : } // InterpProfAng()
8439 :
8440 5527 : Real64 InterpSlatAng(Real64 const SlatAng, // Slat angle (rad)
8441 : bool const VarSlats, // True if slat angle is variable
8442 : Array1S<Real64> const PropArray // Array of blind properties as function of slat angle
8443 : )
8444 : {
8445 :
8446 : // SUBROUTINE INFORMATION:
8447 : // AUTHOR Fred Winkelmann
8448 : // DATE WRITTEN Dec 2001
8449 : // MODIFIED na
8450 : // RE-ENGINEERED na
8451 :
8452 : // PURPOSE OF THIS SUBROUTINE:
8453 : // Does slat-angle interpolation of window blind solar-thermal properties that
8454 : // do not depend on profile angle
8455 :
8456 : // METHODOLOGY EMPLOYED:
8457 : // Linear interpolation.
8458 :
8459 5527 : if (VarSlats) { // Variable-angle slats
8460 21 : Real64 SlatAng1 = std::clamp(SlatAng, 0.0, Constant::Pi);
8461 : static Real64 constexpr DeltaAng(Constant::Pi / (double(Material::MaxSlatAngs) - 1.0));
8462 : static Real64 constexpr DeltaAng_inv((double(Material::MaxSlatAngs) - 1.0) / Constant::Pi);
8463 21 : int IBeta = 1 + int(SlatAng1 * DeltaAng_inv); // Slat angle index
8464 21 : Real64 InterpFac = (SlatAng1 - DeltaAng * (IBeta - 1)) * DeltaAng_inv; // Interpolation factor
8465 21 : return PropArray(IBeta) + InterpFac * (PropArray(min(Material::MaxSlatAngs, IBeta + 1)) - PropArray(IBeta));
8466 : } else { // Fixed-angle slats or shade
8467 5506 : return PropArray(1);
8468 : }
8469 : } // InterpSlatAng()
8470 :
8471 139 : Real64 InterpProfSlatAng(Real64 const ProfAng, // Profile angle (rad)
8472 : Real64 const SlatAng, // Slat angle (rad)
8473 : bool const VarSlats, // True if variable-angle slats
8474 : Array2A<Real64> const PropArray // Array of blind properties
8475 : )
8476 : {
8477 :
8478 : // SUBROUTINE INFORMATION:
8479 : // AUTHOR Fred Winkelmann
8480 : // DATE WRITTEN Dec 2001
8481 : // MODIFIED na
8482 : // RE-ENGINEERED na
8483 :
8484 : // PURPOSE OF THIS SUBROUTINE:
8485 : // Does simultaneous profile-angle and slat-angle interpolation of window
8486 : // blind solar-thermal properties that depend on profile angle and slat angle
8487 :
8488 : // METHODOLOGY EMPLOYED:
8489 : // Linear interpolation.
8490 :
8491 : // Argument array dimensioning
8492 139 : PropArray.dim(Material::MaxSlatAngs, Material::MaxProfAngs);
8493 :
8494 139 : Real64 SlatAng1 = std::clamp(SlatAng, 0.0, Constant::Pi);
8495 :
8496 : // This is not correct, fixed 2/17/2010
8497 : // ProfAng1 = MIN(MAX(SlatAng,-PiOvr2),PiOvr2)
8498 139 : Real64 ProfAng1 = std::clamp(ProfAng, -Constant::PiOvr2, Constant::PiOvr2);
8499 :
8500 139 : Real64 constexpr DeltaProfAng(Constant::Pi / 36.0);
8501 139 : int IAlpha = int((ProfAng1 + Constant::PiOvr2) / DeltaProfAng) + 1; // Profile angle index
8502 139 : Real64 ProfAngRatio = (ProfAng1 + Constant::PiOvr2 - (IAlpha - 1) * DeltaProfAng) / DeltaProfAng; // Profile angle interpolation factor
8503 :
8504 : Real64 Val1;
8505 : Real64 Val2;
8506 139 : if (VarSlats) { // Variable-angle slats: interpolate in profile angle and slat angle
8507 27 : Real64 constexpr DeltaSlatAng(Constant::Pi / (double(Material::MaxSlatAngs) - 1.0));
8508 27 : int IBeta = int(SlatAng1 / DeltaSlatAng) + 1; // Slat angle index
8509 27 : Real64 SlatAngRatio = (SlatAng1 - (IBeta - 1) * DeltaSlatAng) / DeltaSlatAng; // Slat angle interpolation factor
8510 27 : Val1 = PropArray(IBeta, IAlpha); // Property values at points enclosing the given ProfAngle and SlatAngle
8511 27 : Val2 = PropArray(min(Material::MaxSlatAngs, IBeta + 1), IAlpha);
8512 27 : Real64 Val3 = PropArray(IBeta, min(Material::MaxProfAngs, IAlpha + 1));
8513 27 : Real64 Val4 = PropArray(min(Material::MaxSlatAngs, IBeta + 1), min(Material::MaxProfAngs, IAlpha + 1));
8514 27 : Real64 ValA = Val1 + SlatAngRatio * (Val2 - Val1); // Property values at given SlatAngle to be interpolated in profile angle
8515 27 : Real64 ValB = Val3 + SlatAngRatio * (Val4 - Val3);
8516 27 : return ValA + ProfAngRatio * (ValB - ValA);
8517 : } else { // Fixed-angle slats: interpolate only in profile angle
8518 112 : Val1 = PropArray(1, IAlpha);
8519 112 : Val2 = PropArray(1, min(Material::MaxProfAngs, IAlpha + 1));
8520 112 : return Val1 + ProfAngRatio * (Val2 - Val1);
8521 : }
8522 : } // InterpProfSlatAng()
8523 :
8524 161907 : Real64 BlindBeamBeamTrans(Real64 const ProfAng, // Solar profile angle (rad)
8525 : Real64 const SlatAng, // Slat angle (rad)
8526 : Real64 const SlatWidth, // Slat width (m)
8527 : Real64 const SlatSeparation, // Slat separation (distance between surfaces of adjacent slats) (m)
8528 : Real64 const SlatThickness // Slat thickness (m)
8529 : )
8530 : {
8531 :
8532 : // FUNCTION INFORMATION:
8533 : // AUTHOR Fred Winkelmann
8534 : // DATE WRITTEN Jan 2002
8535 : // MODIFIED na
8536 : // RE-ENGINEERED na
8537 :
8538 : // PURPOSE OF THIS SUBROUTINE:
8539 : // Calculates beam-to-beam transmittance of a window blind
8540 :
8541 : // METHODOLOGY EMPLOYED:
8542 : // Based on solar profile angle and slat geometry
8543 :
8544 161907 : Real64 CosProfAng = std::cos(ProfAng); // Cosine of profile angle
8545 161907 : Real64 gamma = SlatAng - ProfAng;
8546 161907 : Real64 wbar = SlatSeparation;
8547 161907 : if (CosProfAng != 0.0) wbar = SlatWidth * std::cos(gamma) / CosProfAng;
8548 161907 : Real64 BlindBeamBeamTrans = max(0.0, 1.0 - std::abs(wbar / SlatSeparation));
8549 :
8550 161907 : if (BlindBeamBeamTrans > 0.0) {
8551 :
8552 : // Correction factor that accounts for finite thickness of slats. It is used to modify the
8553 : // blind transmittance to account for reflection and absorption by the slat edges.
8554 : // fEdge is ratio of area subtended by edge of slat to area between tops of adjacent slats.
8555 :
8556 27850 : Real64 fEdge = 0.0; // Slat edge correction factor
8557 27850 : Real64 fEdge1 = 0.0;
8558 27850 : if (std::abs(std::sin(gamma)) > 0.01) {
8559 27850 : if ((SlatAng > 0.0 && SlatAng <= Constant::PiOvr2 && ProfAng <= SlatAng) ||
8560 14022 : (SlatAng > Constant::PiOvr2 && SlatAng <= Constant::Pi && ProfAng > -(Constant::Pi - SlatAng)))
8561 27850 : fEdge1 =
8562 27850 : SlatThickness * std::abs(std::sin(gamma)) / ((SlatSeparation + SlatThickness / std::abs(std::sin(SlatAng))) * CosProfAng);
8563 27850 : fEdge = min(1.0, std::abs(fEdge1));
8564 : }
8565 27850 : BlindBeamBeamTrans *= (1.0 - fEdge);
8566 : }
8567 :
8568 161907 : return BlindBeamBeamTrans;
8569 : } // BlindBeamBeamTrans()
8570 :
8571 : //********************************************************************************************
8572 :
8573 84150 : void ViewFac(Real64 const s, // Slat width (m)
8574 : Real64 const h, // Distance between faces of adjacent slats (m)
8575 : Real64 const phib, // Elevation angle of normal to slat (radians)
8576 : Real64 const phis, // Profile angle of radiation source (radians)
8577 : Array2A<Real64> F // View factor array
8578 : )
8579 : {
8580 :
8581 : // SUBROUTINE INFORMATION:
8582 : // AUTHOR Hans Simmler
8583 : // DATE WRITTEN July-Aug 1995
8584 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
8585 : // Apr 2002 (FCW): prevent sqrt of small negative argument
8586 : // RE-ENGINEERED na
8587 :
8588 : // PURPOSE OF THIS SUBROUTINE:
8589 : // Calculates the view factors between sections of adjacent slats,
8590 : // where each slat is divided longitudinally into two equal sections whose
8591 : // dimensions depend on source profile angle and slat geometry. The view
8592 : // factors are used in BlindOpticsBeam and BlindOpticsDiffuse to determine blind
8593 : // transmittance and reflectance for short-wave and long-wave radiation.
8594 :
8595 : // METHODOLOGY EMPLOYED:
8596 : // Uses expressions for view factor between flat strips with a common edge
8597 : // and flat strips displaced from one another. See engineering documentation.
8598 :
8599 : // REFERENCES:
8600 : // "Solar-Thermal Window Blind Model for DOE-2," H. Simmler, U. Fischer and
8601 : // F. Winkelmann, Lawrence Berkeley National Laboratory, Jan. 1996.
8602 :
8603 : // Argument array dimensioning
8604 84150 : F.dim(6, 6);
8605 :
8606 84150 : Array1D<Real64> L(6); // Length of slat sections: L1 = L2 = h; L3, L5 = length
8607 : Real64 L3;
8608 : Real64 L5;
8609 : // of upper slat sections; L4, L6 = length of lower slat
8610 : // slat sections (m)
8611 : Real64 d1; // Slat geometry variables (m)
8612 : Real64 d2;
8613 : Real64 d3;
8614 : Real64 d4;
8615 : Real64 d5;
8616 : Real64 d6;
8617 : Real64 h2; // h**2
8618 : Real64 ht; // 2*h
8619 : Real64 w; // Slat geometry variable (m)
8620 : Real64 a; // Intermediate variable (m)
8621 : Real64 co; // Cosine of source profile angle
8622 :
8623 84150 : h2 = pow_2(h);
8624 84150 : ht = 2.0 * h;
8625 84150 : co = std::cos(phis);
8626 84150 : if (std::abs(co) < 0.001) co = 0.0;
8627 84150 : w = ht;
8628 84150 : if (co != 0.0) w = s * std::cos(phib - phis) / co;
8629 84150 : L3 = s * h / std::abs(w);
8630 84150 : if (L3 > s) L3 = s;
8631 84150 : L5 = s - L3;
8632 84150 : a = ht * std::cos(phib);
8633 : // MAX(0.,...) in the following prevents small negative argument for sqrt
8634 84150 : d1 = std::sqrt(max(0.0, s * s + h2 + a * s));
8635 84150 : d2 = std::sqrt(max(0.0, s * s + h2 - a * s));
8636 84150 : d3 = std::sqrt(max(0.0, L3 * L3 + h2 + a * L3));
8637 84150 : d4 = std::sqrt(max(0.0, L3 * L3 + h2 - a * L3));
8638 84150 : d5 = std::sqrt(max(0.0, L5 * L5 + h2 - a * L5));
8639 84150 : d6 = std::sqrt(max(0.0, L5 * L5 + h2 + a * L5));
8640 589050 : for (int i = 1; i <= 6; ++i) {
8641 504900 : F(i, i) = 0.0;
8642 : }
8643 84150 : F(1, 1) = 0.0;
8644 84150 : F(2, 1) = (d1 + d2 - 2.0 * s) / ht;
8645 84150 : F(3, 1) = (h + L3 - d3) / ht;
8646 84150 : F(4, 1) = (h + L3 - d4) / ht;
8647 84150 : F(5, 1) = (L5 + d3 - d1) / ht;
8648 84150 : F(6, 1) = (L5 + d4 - d2) / ht;
8649 84150 : F(3, 2) = (L3 + d5 - d2) / ht;
8650 84150 : F(4, 2) = (L3 + d6 - d1) / ht;
8651 84150 : F(5, 2) = (h + L5 - d5) / ht;
8652 84150 : F(6, 2) = (h + L5 - d6) / ht;
8653 84150 : F(4, 3) = (d3 + d4 - ht) / (2.0 * L3);
8654 84150 : F(5, 3) = 0.0;
8655 84150 : F(6, 3) = (d2 + h - d4 - d5) / (2.0 * L3);
8656 84150 : F(5, 4) = (d1 + h - d3 - d6) / (2.0 * L3);
8657 84150 : F(6, 4) = 0.0;
8658 84150 : F(6, 5) = 0.0;
8659 84150 : if (L5 > 0.0) F(6, 5) = (d5 + d6 - ht) / (2.0 * L5);
8660 84150 : L(1) = h;
8661 84150 : L(2) = h;
8662 84150 : L(3) = L3;
8663 84150 : L(4) = L3;
8664 84150 : L(5) = L5;
8665 84150 : L(6) = L5;
8666 504900 : for (int i = 2; i <= 6; ++i) {
8667 1683000 : for (int j = 1; j <= i - 1; ++j) {
8668 1262250 : F(j, i) = 0.0;
8669 1262250 : if (L(i) > 0.0) F(j, i) = F(i, j) * L(j) / L(i);
8670 : }
8671 : }
8672 84150 : } // ViewFac()
8673 :
8674 : //*****************************************************************************************
8675 :
8676 84711 : void InvertMatrix(EnergyPlusData &state,
8677 : Array2D<Real64> &a, // Matrix to be inverted
8678 : Array2D<Real64> &y, // Inverse of matrix a
8679 : Array1D_int &indx, // Index vector for LU decomposition
8680 : int const n)
8681 : {
8682 :
8683 : // SUBROUTINE INFORMATION:
8684 : // AUTHOR Hans Simmler
8685 : // DATE WRITTEN July-Aug 1995
8686 : // MODIFIED Aug 2001 (FCW): adapt to EnergyPlus
8687 : // RE-ENGINEERED na
8688 :
8689 : // PURPOSE OF THIS SUBROUTINE:
8690 : // Inverts a matrix.
8691 :
8692 : // METHODOLOGY EMPLOYED:
8693 : // Uses LU decomposition.
8694 :
8695 84711 : Array1D<Real64> tmp(n);
8696 :
8697 : int d;
8698 :
8699 84711 : y = 0.0;
8700 423555 : for (int i = 1; i <= n; ++i) {
8701 338844 : y(i, i) = 1.0;
8702 : }
8703 84711 : indx = 0;
8704 :
8705 84711 : LUdecomposition(state, a, n, indx, d);
8706 :
8707 423555 : for (int j = 1; j <= n; ++j) {
8708 338844 : tmp = 0.0;
8709 338844 : tmp(j) = 1;
8710 338844 : LUsolution(state, a, n, indx, tmp);
8711 1694220 : for (int i = 1; i <= n; ++i)
8712 1355376 : y(j, i) = tmp(i);
8713 : }
8714 84711 : } // InvertMatrix()
8715 :
8716 : // added for custom solar or visible spectrum
8717 :
8718 796 : void CheckAndReadCustomSprectrumData(EnergyPlusData &state)
8719 : {
8720 :
8721 : // SUBROUTINE INFORMATION:
8722 : // AUTHOR T. Hong
8723 : // DATE WRITTEN August 2013
8724 : // MODIFIED
8725 : // RE-ENGINEERED na
8726 :
8727 : // PURPOSE OF THIS SUBROUTINE:
8728 : // Check, read, and assign the custom solar or visible spectrum to:
8729 : // solar: nume, wle(nume), e(nume). nume = 107
8730 : // visible: numt3, wlt3(numt3), y30(numt3). numt3 = 81
8731 : // Three related IDD objects:
8732 : // EnergyManagementSystem:ConstructionIndexVariable
8733 : // Site:SolarAndVisibleSpectrum, Site:SpectrumData
8734 :
8735 : // METHODOLOGY EMPLOYED:
8736 : // Overwriting the default values
8737 :
8738 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8739 796 : bool ErrorsFound(false); // If errors detected in input
8740 : int NumAlphas; // Number of Alphas for each GetobjectItem call
8741 : int NumNumbers; // Number of Numbers for each GetobjectItem call
8742 : int NumArgs;
8743 : int IOStatus;
8744 796 : Array1D_string cAlphaArgs; // Alpha input items for object
8745 796 : Array1D<Real64> rNumericArgs; // Numeric input items for object
8746 :
8747 796 : std::string cCurrentModuleObject;
8748 796 : std::string cSolarSpectrum;
8749 796 : std::string cVisibleSpectrum;
8750 796 : int iSolarSpectrum(0);
8751 796 : int iVisibleSpectrum(0);
8752 796 : int NumSiteSpectrum(0);
8753 : int Loop;
8754 : int iTmp;
8755 :
8756 796 : auto &wm = state.dataWindowManager;
8757 :
8758 796 : if (wm->RunMeOnceFlag) return;
8759 :
8760 : // Step 1 - check whether there is custom solar or visible spectrum
8761 796 : cCurrentModuleObject = "Site:SolarAndVisibleSpectrum";
8762 796 : NumSiteSpectrum = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8763 :
8764 : // no custom spectrum data, done!
8765 796 : if (NumSiteSpectrum == 0) {
8766 795 : wm->RunMeOnceFlag = true;
8767 795 : return;
8768 : }
8769 :
8770 : // read custom spectrum data from Site:SolarAndVisibleSpectrum
8771 1 : if (NumSiteSpectrum > 1) { // throw error
8772 0 : ShowSevereError(state, format("Only one {} object is allowed", cCurrentModuleObject));
8773 0 : ErrorsFound = true;
8774 : }
8775 :
8776 1 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
8777 1 : cAlphaArgs.allocate(NumAlphas);
8778 1 : rNumericArgs.dimension(NumNumbers, 0.0);
8779 :
8780 1 : if (NumSiteSpectrum == 1) {
8781 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8782 : cCurrentModuleObject,
8783 : 1,
8784 1 : state.dataIPShortCut->cAlphaArgs,
8785 : NumAlphas,
8786 1 : state.dataIPShortCut->rNumericArgs,
8787 : NumNumbers,
8788 : IOStatus);
8789 :
8790 : // use default spectrum data, done!
8791 1 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), "Default")) {
8792 0 : wm->RunMeOnceFlag = true;
8793 0 : return;
8794 : }
8795 :
8796 : // now read custom solar and visible spectrum data
8797 1 : cSolarSpectrum = state.dataIPShortCut->cAlphaArgs(3);
8798 1 : cVisibleSpectrum = state.dataIPShortCut->cAlphaArgs(4);
8799 :
8800 1 : cCurrentModuleObject = "Site:SpectrumData";
8801 1 : NumSiteSpectrum = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
8802 1 : if (NumSiteSpectrum == 0) { // throw error
8803 0 : ShowSevereError(state, format("No {} object is found", cCurrentModuleObject));
8804 0 : ErrorsFound = true;
8805 : }
8806 :
8807 1 : cAlphaArgs.deallocate();
8808 1 : rNumericArgs.deallocate();
8809 :
8810 1 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, cCurrentModuleObject, NumArgs, NumAlphas, NumNumbers);
8811 1 : cAlphaArgs.allocate(NumAlphas);
8812 1 : rNumericArgs.dimension(NumNumbers, 0.0);
8813 :
8814 1 : iSolarSpectrum = 0;
8815 1 : iVisibleSpectrum = 0;
8816 2 : for (int Loop = 1; Loop <= NumSiteSpectrum; ++Loop) {
8817 : // Step 2 - read user-defined spectrum data
8818 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
8819 : cCurrentModuleObject,
8820 : Loop,
8821 2 : state.dataIPShortCut->cAlphaArgs,
8822 : NumAlphas,
8823 2 : state.dataIPShortCut->rNumericArgs,
8824 : NumNumbers,
8825 : IOStatus);
8826 2 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), cSolarSpectrum)) {
8827 1 : iSolarSpectrum = Loop;
8828 : // overwrite the default solar spectrum
8829 1 : if (NumNumbers > 2 * nume) {
8830 0 : ShowSevereError(
8831 : state,
8832 0 : format("Solar spectrum data pair is more than 107 - {} - {}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
8833 0 : ErrorsFound = true;
8834 : } else {
8835 : // Step 3 - overwrite default solar spectrum data
8836 108 : for (int iTmp = 1; iTmp <= nume; ++iTmp) {
8837 107 : if (iTmp <= NumNumbers / 2) {
8838 107 : wm->wle[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp - 1);
8839 107 : wm->e[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp);
8840 : } else {
8841 0 : wm->wle[iTmp - 1] = 0.0;
8842 0 : wm->e[iTmp - 1] = 0.0;
8843 : }
8844 : }
8845 : }
8846 : }
8847 2 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), cVisibleSpectrum)) {
8848 1 : iVisibleSpectrum = Loop;
8849 : // overwrite the default solar spectrum
8850 1 : if (NumNumbers > 2 * numt3) {
8851 0 : ShowSevereError(state,
8852 0 : format("Visible spectrum data pair is more than 81 - {} - {}",
8853 : cCurrentModuleObject,
8854 0 : state.dataIPShortCut->cAlphaArgs(1)));
8855 0 : ErrorsFound = true;
8856 : } else {
8857 : // Step 3 - overwrite default visible spectrum data
8858 82 : for (int iTmp = 1; iTmp <= numt3; ++iTmp) {
8859 81 : if (iTmp <= NumNumbers / 2) {
8860 81 : wm->wlt3[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp - 1);
8861 81 : wm->y30[iTmp - 1] = state.dataIPShortCut->rNumericArgs(2 * iTmp);
8862 : } else {
8863 0 : wm->wlt3[iTmp - 1] = 0.0;
8864 0 : wm->y30[iTmp - 1] = 0.0;
8865 : }
8866 : }
8867 : }
8868 : }
8869 2 : if ((iSolarSpectrum > 0) && (iVisibleSpectrum > 0)) break;
8870 : }
8871 : }
8872 :
8873 1 : cAlphaArgs.deallocate();
8874 1 : rNumericArgs.deallocate();
8875 :
8876 1 : if (ErrorsFound) {
8877 0 : ShowFatalError(state, "Errors found in processing input for user-defined solar/visible spectrum");
8878 : }
8879 :
8880 1 : wm->RunMeOnceFlag = true;
8881 3976 : } // CheckAndReadCustomSpectrumData()
8882 :
8883 : //*****************************************************************************************
8884 :
8885 796 : void initWindowModel(EnergyPlusData &state)
8886 : {
8887 796 : const std::string objectName = "WindowsCalculationEngine";
8888 796 : auto &wm = state.dataWindowManager;
8889 796 : wm->inExtWindowModel = CWindowModel::WindowModelFactory(state, objectName);
8890 796 : wm->winOpticalModel = CWindowOpticalModel::WindowOpticalModelFactory(state);
8891 796 : } // InitWindowModel()
8892 :
8893 : //*****************************************************************************************
8894 :
8895 : } // namespace Window
8896 :
8897 : } // namespace EnergyPlus
|