Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, 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 <string>
53 :
54 : // ObjexxFCL Headers
55 : #include <ObjexxFCL/Array.functions.hh>
56 : #include <ObjexxFCL/Fmath.hh>
57 : #include <ObjexxFCL/Vector2.hh>
58 : #include <ObjexxFCL/Vector3.hh>
59 : #include <ObjexxFCL/Vector4.hh>
60 : #include <ObjexxFCL/member.functions.hh>
61 : #include <ObjexxFCL/random.hh>
62 : #include <ObjexxFCL/string.functions.hh>
63 :
64 : // EnergyPlus Headers
65 : #include <EnergyPlus/DElightManagerF.hh>
66 : #include <EnergyPlus/Data/EnergyPlusData.hh>
67 : #include <EnergyPlus/DataBSDFWindow.hh>
68 : #include <EnergyPlus/DataDElight.hh>
69 : #include <EnergyPlus/DataDaylighting.hh>
70 : #include <EnergyPlus/DataDaylightingDevices.hh>
71 : #include <EnergyPlus/DataEnvironment.hh>
72 : #include <EnergyPlus/DataErrorTracking.hh>
73 : #include <EnergyPlus/DataHeatBalance.hh>
74 : #include <EnergyPlus/DataIPShortCuts.hh>
75 : #include <EnergyPlus/DataPrecisionGlobals.hh>
76 : #include <EnergyPlus/DataStringGlobals.hh>
77 : #include <EnergyPlus/DataSurfaces.hh>
78 : #include <EnergyPlus/DataSystemVariables.hh>
79 : #include <EnergyPlus/DataViewFactorInformation.hh>
80 : #include <EnergyPlus/DaylightingDevices.hh>
81 : #include <EnergyPlus/DaylightingManager.hh>
82 : #include <EnergyPlus/DisplayRoutines.hh>
83 : #include <EnergyPlus/FileSystem.hh>
84 : #include <EnergyPlus/General.hh>
85 : #include <EnergyPlus/HeatBalanceManager.hh>
86 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
87 : #include <EnergyPlus/InternalHeatGains.hh>
88 : #include <EnergyPlus/OutputProcessor.hh>
89 : #include <EnergyPlus/OutputReportPredefined.hh>
90 : #include <EnergyPlus/PierceSurface.hh>
91 : #include <EnergyPlus/SQLiteProcedures.hh>
92 : #include <EnergyPlus/ScheduleManager.hh>
93 : #include <EnergyPlus/SolarReflectionManager.hh>
94 : #include <EnergyPlus/SolarShading.hh>
95 : #include <EnergyPlus/SurfaceOctree.hh>
96 : #include <EnergyPlus/UtilityRoutines.hh>
97 : #include <EnergyPlus/WindowComplexManager.hh>
98 :
99 : namespace EnergyPlus::DaylightingManager {
100 :
101 : // MODULE INFORMATION
102 : // AUTHOR Fred Winkelmann
103 : // DATE WRITTEN July 1997, December 1998
104 : // MODIFIED Oct 2004; LKL -- Efficiencies and code restructure
105 : // Aug 2012: BG -- Added availability schedule
106 : // RE-ENGINEERED na
107 :
108 : // PURPOSE OF THIS MODULE:
109 : // Manages the daylighting calculations for each thermal zone that has an associated
110 : // Daylighting:Controls object.
111 :
112 : // Includes calculation of interior daylight illuminance and glare
113 : // from each of the windows in a zone, control of window shading devices
114 : // to reduce glare, and control of overhead electric lighting in response
115 : // to interior daylight illuminance level at one or two user-specified
116 : // reference points at which sensors are located.
117 :
118 : // METHODOLOGY EMPLOYED:
119 : // REFERENCES:
120 : // "Daylighting Calculation in DOE-2," F.C.Winkelmann, LBL-11353, May 1983
121 : // "Daylighting Simulation in the DOE-2 Building Energy Analysis Program,"
122 : // F.C. Winkelmann and S. Selkowitz, Energy and Buildings 8(1985)271-286
123 :
124 : // OTHER NOTES:
125 : // This module was created from DOE-2.1E subroutines.
126 :
127 : // Correspondence between DOE-2.1E and EnergyPlus subroutine names:
128 :
129 : // DOE-2.1E EnergyPlus In Module Called from Module
130 : // DAVREF DayltgAveInteriorReflectance DaylightingManager DaylightingManager
131 : // DCOF CalcDayltgCoefficients DaylightingManager DaylightingManager
132 : // DCROSS DayltgCrossProduct DaylightingManager DaylightingManager
133 : // DEXTIL DayltgCurrentExtHorizIllum WeatherManager WeatherManager
134 : // DGLARE DayltgGlare DaylightingManager DaylightingManager
135 : // DHILL DayltgExtHorizIllum DaylightingManager DaylightingManager
136 : // DHITSH DayltgHitObstruction DaylightingManager DaylightingManager
137 : // DINTIL DayltgInteriorIllum DaylightingManager HeatBalanceSurfaceManager
138 : // DLTSYS DayltgElecLightingControl DaylightingManager HeatBalanceSurfaceManager
139 : // DNSOL not used
140 : // DPFAC DayltgPositionFactor DaylightingManager DaylightingManager
141 : // DPIERC PierceSurface PierceSurface DaylightingManager
142 : // DREFLT DayltgInterReflectedIllum DaylightingManager DaylightingManager
143 : // DSKYLU DayltgSkyLuminance DaylightingManager DaylightingManager
144 : // DTHLIM DayltgAzimuthLimits DaylightingManager DaylightingManager
145 : // DLUMEF DayltgLuminousEfficacy WeatherManager WeatherManager
146 :
147 : // Using/Aliasing
148 : using namespace DataHeatBalance;
149 : using namespace DataSurfaces;
150 :
151 284 : void DayltgAveInteriorReflectance(EnergyPlusData &state, int const enclNum) // Enclosure number
152 : {
153 :
154 : // SUBROUTINE INFORMATION:
155 : // AUTHOR Fred Winkelmann
156 : // DATE WRITTEN July 1997
157 : // MODIFIED Mar 2004, FCW: add calculation of following SurfaceWindow variables:
158 : // EnclAreaMinusThisSurf, EnclAreaReflProdMinusThisSurf, RhoCeilingWall,
159 : // RhoFloorWall, FractionUpgoing. Add calculation of ZoneDaylight%floorVisRefl.
160 :
161 : // PURPOSE OF THIS SUBROUTINE:
162 : // Called by CalcDayltgCoefficients for each daylit zone. Determines total
163 : // area and area-weighted average visible reflectance of
164 : // all inside faces of the surfaces of a zone. In addition, finds
165 : // area and average reflectance of interzone, underground and exterior
166 : // heat-transfer surfaces in the following categories: floor (tilt > 170 deg),
167 : // ceiling (tilt < 10 deg), and wall (10 < tilt < 170 deg).
168 : // The window reflectance values used here assume the windows have no shading
169 : // devices. This information is used in the calculation of the
170 : // internally-reflected daylighting component.
171 :
172 : // Finds total number of exterior windows in the space.
173 :
174 : // REFERENCES:
175 : // Based on DOE-2.1E subroutine DAVREF
176 :
177 : SurfaceClass IType; // Surface type/class
178 : Real64 AREA; // Inside surface area (m2)
179 : Real64 AInsTot; // Total inside surface area of an enclosure (m2)
180 : Real64 ARHTOT; // Sum over surfaces of AREA*(inside visible reflectance) (m2)
181 : int ITILT; // Surface tilt category (1 = floor, 2 = wall, 3 = ceiling)
182 : int IT; // Tilt index
183 : Real64 ATWL; // Opaque surface area (m2)
184 : Real64 ARHTWL; // ATWL times inside visible reflectance of surface (m2)
185 : Real64 ETA; // Ratio of floor-to-window-center height and average floor-to-ceiling height
186 :
187 : // Total inside surface area, including windows
188 284 : AInsTot = 0.0;
189 : // Sum of products of inside surface area * vis reflectance
190 284 : ARHTOT = 0.0;
191 : // Area sum and area * reflectance sum for different orientations
192 284 : state.dataDaylightingManager->AR = 0.0;
193 284 : state.dataDaylightingManager->ARH = 0.0;
194 : // Loop over surfaces in the zone's enclosure
195 :
196 284 : auto &thisEnclosure(state.dataViewFactor->EnclSolInfo(enclNum));
197 3414 : for (int ISurf : thisEnclosure.SurfacePtr) {
198 3130 : IType = state.dataSurface->Surface(ISurf).Class;
199 : // Error if window has multiplier > 1 since this causes incorrect illuminance calc
200 3130 : if (IType == SurfaceClass::Window && state.dataSurface->Surface(ISurf).Multiplier > 1.0) {
201 0 : if (thisEnclosure.TotalEnclosureDaylRefPoints > 0) {
202 0 : ShowSevereError(state,
203 0 : "DayltgAveInteriorReflectance: Multiplier > 1.0 for window " + state.dataSurface->Surface(ISurf).Name +
204 0 : " in Zone=" + state.dataSurface->Surface(ISurf).ZoneName);
205 0 : ShowContinueError(state, "...not allowed since it is in a zone or enclosure with daylighting.");
206 0 : ShowFatalError(state, "Program terminates due to preceding conditions.");
207 : } else {
208 0 : ShowSevereError(state,
209 0 : "DayltgAveInteriorReflectance: Multiplier > 1.0 for window " + state.dataSurface->Surface(ISurf).Name +
210 0 : " in Zone=" + state.dataSurface->Surface(ISurf).ZoneName);
211 0 : ShowContinueError(state, "...an adjacent Zone has daylighting. Simulation cannot proceed.");
212 0 : ShowFatalError(state, "Program terminates due to preceding conditions.");
213 : }
214 : }
215 3130 : if (IType == SurfaceClass::Wall || IType == SurfaceClass::Floor || IType == SurfaceClass::Roof || IType == SurfaceClass::Window ||
216 : IType == SurfaceClass::Door) {
217 2889 : AREA = state.dataSurface->Surface(ISurf).Area;
218 : // In following, FrameArea and DividerArea can be non-zero only for exterior windows
219 5778 : AInsTot += AREA + state.dataSurface->SurfWinFrameArea(ISurf) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(ISurf)) +
220 2889 : state.dataSurface->SurfWinDividerArea(ISurf) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(ISurf));
221 8667 : ARHTOT += AREA * state.dataConstruction->Construct(state.dataSurface->Surface(ISurf).Construction).ReflectVisDiffBack +
222 5778 : state.dataSurface->SurfWinFrameArea(ISurf) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(ISurf)) *
223 5778 : (1.0 - state.dataSurface->SurfWinFrameSolAbsorp(ISurf)) +
224 5778 : state.dataSurface->SurfWinDividerArea(ISurf) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(ISurf)) *
225 2889 : (1.0 - state.dataSurface->SurfWinDividerSolAbsorp(ISurf));
226 2889 : ITILT = 3; // Ceiling
227 2889 : if (state.dataSurface->Surface(ISurf).Tilt > 10.0 && state.dataSurface->Surface(ISurf).Tilt < 170.0) ITILT = 2; // Wall
228 2889 : if (state.dataSurface->Surface(ISurf).Tilt >= 170.0) ITILT = 1; // Floor
229 2889 : state.dataDaylightingManager->AR(ITILT) +=
230 5778 : AREA + state.dataSurface->SurfWinFrameArea(ISurf) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(ISurf)) +
231 2889 : state.dataSurface->SurfWinDividerArea(ISurf) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(ISurf));
232 2889 : state.dataDaylightingManager->ARH(ITILT) +=
233 5778 : AREA * state.dataConstruction->Construct(state.dataSurface->Surface(ISurf).Construction).ReflectVisDiffBack +
234 5778 : state.dataSurface->SurfWinFrameArea(ISurf) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(ISurf)) *
235 5778 : (1.0 - state.dataSurface->SurfWinFrameSolAbsorp(ISurf)) +
236 5778 : state.dataSurface->SurfWinDividerArea(ISurf) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(ISurf)) *
237 2889 : (1.0 - state.dataSurface->SurfWinDividerSolAbsorp(ISurf));
238 : }
239 : }
240 :
241 : // Average inside surface reflectance of enclosure
242 284 : if (AInsTot <= 0.0) {
243 0 : ShowSevereError(state, "DayltgAveInteriorReflectance: Total opaque surface area is <=0.0 in solar enclosure=" + thisEnclosure.Name);
244 0 : ShowFatalError(state, "Program terminates due to preceding conditions.");
245 : }
246 284 : state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect = ARHTOT / AInsTot;
247 : // Total inside surface area of enclosure
248 284 : state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea = AInsTot;
249 : // Average floor visible reflectance
250 284 : state.dataDaylightingData->enclDaylight(enclNum).floorVisRefl =
251 284 : state.dataDaylightingManager->ARH(3) / (state.dataDaylightingManager->AR(3) + 1.e-6);
252 :
253 3414 : for (int ISurf : thisEnclosure.SurfacePtr) {
254 3130 : IType = state.dataSurface->Surface(ISurf).Class;
255 3130 : if (IType == SurfaceClass::Wall || IType == SurfaceClass::Floor || IType == SurfaceClass::Roof) {
256 : // Remove this surface from the space inside surface area and area*reflectivity
257 : // The resulting areas are AP(ITILT). The resulting area*reflectivity is ARHP(ITILT).
258 : // Initialize gross area of surface (including subsurfaces)
259 1842 : ATWL = state.dataSurface->Surface(ISurf).Area; // This is the surface area less subsurfaces
260 : // Area * reflectance for this surface, excluding attached windows and doors
261 3684 : ARHTWL = state.dataSurface->Surface(ISurf).Area *
262 1842 : state.dataConstruction->Construct(state.dataSurface->Surface(ISurf).Construction).ReflectVisDiffBack;
263 : // Tilt index
264 1842 : if (state.dataSurface->Surface(ISurf).Tilt > 45.0 && state.dataSurface->Surface(ISurf).Tilt < 135.0) {
265 1232 : ITILT = 2; // Wall
266 610 : } else if (state.dataSurface->Surface(ISurf).Tilt >= 135.0) {
267 316 : ITILT = 1; // Floor
268 : } else {
269 294 : ITILT = 3; // Ceiling
270 : }
271 : // Loop over windows and doors on this wall
272 23547 : for (int IWinDr : thisEnclosure.SurfacePtr) {
273 58956 : if ((state.dataSurface->Surface(IWinDr).Class == SurfaceClass::Window ||
274 29330 : state.dataSurface->Surface(IWinDr).Class == SurfaceClass::Door) &&
275 7625 : state.dataSurface->Surface(IWinDr).BaseSurf == ISurf) {
276 3141 : ATWL += state.dataSurface->Surface(IWinDr).Area +
277 2094 : state.dataSurface->SurfWinFrameArea(IWinDr) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(IWinDr)) +
278 1047 : state.dataSurface->SurfWinDividerArea(IWinDr) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(IWinDr));
279 3141 : ARHTWL += state.dataSurface->Surface(IWinDr).Area *
280 2094 : state.dataConstruction->Construct(state.dataSurface->Surface(IWinDr).Construction).ReflectVisDiffBack +
281 2094 : state.dataSurface->SurfWinFrameArea(IWinDr) * (1.0 + 0.5 * state.dataSurface->SurfWinProjCorrFrIn(IWinDr)) *
282 2094 : (1.0 - state.dataSurface->SurfWinFrameSolAbsorp(IWinDr)) +
283 2094 : state.dataSurface->SurfWinDividerArea(IWinDr) * (1.0 + state.dataSurface->SurfWinProjCorrDivIn(IWinDr)) *
284 1047 : (1.0 - state.dataSurface->SurfWinDividerSolAbsorp(IWinDr));
285 : }
286 : }
287 : // Inside surface area of floor, walls and ceilings, minus surface ISurf and its subsurfaces
288 7368 : for (IT = 1; IT <= 3; ++IT) {
289 5526 : if (IT == ITILT) {
290 1842 : state.dataDaylightingManager->AP(IT) = state.dataDaylightingManager->AR(IT) - ATWL;
291 1842 : state.dataDaylightingManager->ARHP(IT) = state.dataDaylightingManager->ARH(IT) - ARHTWL;
292 : } else {
293 3684 : state.dataDaylightingManager->AP(IT) = state.dataDaylightingManager->AR(IT);
294 3684 : state.dataDaylightingManager->ARHP(IT) = state.dataDaylightingManager->ARH(IT);
295 : }
296 : }
297 1842 : state.dataSurface->SurfaceWindow(ISurf).EnclAreaMinusThisSurf = state.dataDaylightingManager->AP;
298 1842 : state.dataSurface->SurfaceWindow(ISurf).EnclAreaReflProdMinusThisSurf = state.dataDaylightingManager->ARHP;
299 : }
300 : } // End of loop over opaque surfaces in enclosure
301 :
302 3414 : for (int IWin : thisEnclosure.SurfacePtr) {
303 3130 : if (state.dataSurface->Surface(IWin).Class == SurfaceClass::Window) {
304 841 : int ISurf = state.dataSurface->Surface(IWin).BaseSurf;
305 841 : int zoneNum = state.dataSurface->Surface(IWin).Zone;
306 : // Ratio of floor-to-window-center height and average floor-to-ceiling height
307 841 : ETA = max(0.0,
308 : min(1.0,
309 1682 : (state.dataSurface->SurfaceWindow(IWin).WinCenter(3) - state.dataHeatBal->Zone(zoneNum).OriginZ) *
310 1682 : state.dataHeatBal->Zone(zoneNum).FloorArea / state.dataHeatBal->Zone(zoneNum).Volume));
311 841 : state.dataDaylightingManager->AP = state.dataSurface->SurfaceWindow(ISurf).EnclAreaMinusThisSurf;
312 841 : state.dataDaylightingManager->ARHP = state.dataSurface->SurfaceWindow(ISurf).EnclAreaReflProdMinusThisSurf;
313 : // Average reflectance seen by light moving up (RhoCeilingWall) and down (RhoFloorWall)
314 : // across horizontal plane through center of window
315 841 : state.dataSurface->SurfWinRhoCeilingWall(IWin) =
316 1682 : (state.dataDaylightingManager->ARHP(2) * (1.0 - ETA) + state.dataDaylightingManager->ARHP(3)) /
317 841 : (state.dataDaylightingManager->AP(2) * (1.0 - ETA) + state.dataDaylightingManager->AP(3) + 1.0e-5);
318 1682 : state.dataSurface->SurfWinRhoFloorWall(IWin) = (state.dataDaylightingManager->ARHP(2) * ETA + state.dataDaylightingManager->ARHP(1)) /
319 841 : (state.dataDaylightingManager->AP(2) * ETA + state.dataDaylightingManager->AP(1) + 1.e-9);
320 :
321 : // Angle factor for windows with diffusing shades. SurfaceWindow(IWin)%FractionUpgoing is
322 : // fraction of light from the shade that goes up toward ceiling and upper part of walls.
323 : // 1 - SurfaceWindow(IWin)%FractionUpgoing is fraction that goes down toward floor and lower part of walls.
324 841 : state.dataSurface->SurfWinFractionUpgoing(IWin) = state.dataSurface->Surface(IWin).Tilt / 180.0;
325 :
326 : // Daylighting shelf simplification: All light goes up to the ceiling regardless of orientation of shelf
327 841 : if (state.dataSurface->SurfDaylightingShelfInd(IWin) > 0) {
328 1 : if (state.dataDaylightingDevicesData->Shelf(state.dataSurface->SurfDaylightingShelfInd(IWin)).InSurf > 0)
329 1 : state.dataSurface->SurfWinFractionUpgoing(IWin) = 1.0;
330 : }
331 : }
332 : }
333 284 : }
334 :
335 14330 : void CalcDayltgCoefficients(EnergyPlusData &state)
336 : {
337 :
338 : // SUBROUTINE INFORMATION:
339 : // AUTHOR Fred Winkelmann
340 : // DATE WRITTEN July 1997
341 : // MODIFIED FW, Jan 2002: add variable slat angle blinds
342 : // FW, Mar 2002: add triangular windows
343 : // FW, Oct 2002: remove warning on window discretization relative to
344 : // reference point distance to window plane
345 : // FW, Jan 2003: add between-glass shades and blinds
346 : // FW, Apr 2003: initialize shading type to 'NOSHADE' in window loop
347 : // PE, May 2003: add light pipes (tubular daylighting devices)
348 : // FW, Jul 2003: account for possible non-zero transmittance of
349 : // shading surfaces (previously all shading surfaces were
350 : // assumed to be opaque)
351 : // PE, Aug 2003: add daylighting shelves
352 : // FW, Sep 2003: write the bare-window overcast sky daylight factors to the eio file
353 : // FW, Nov 2003: add exterior beam and sky solar diffuse reflection from obstructions;
354 : // add beam solar and sky solar reflection from ground with obstructions.
355 : // FW, Nov 2003: change expression for NDIVX, NDIVY (no. of window elements in X,Y) to
356 : // round up to nearest integer rather than down
357 : // FW, Nov 2003: add specular reflection of beam solar from obstructions
358 : // RJH, Jan 2004: add alternative daylighting analysis using DElight
359 : // All modifications demarked with RJH (Rob Hitchcock)
360 : // FW, Feb 2004: add daylighting through interior windows
361 : // FW, Apr 2004: add light well efficiency that multiplies glazing transmittance
362 : // FW, Apr 2004: add diffusing glazing
363 : // RJH, Jul 2004: add error handling for warnings/errors returned from DElight
364 : // LKL, Oct 2004: Separate "map" and "ref" point calculations -- move some input routines to
365 : // separate routines.
366 : // RE-ENGINEERED na
367 :
368 : // PURPOSE OF THIS SUBROUTINE:
369 : // Calculates daylighting factors for later use in the time-step loop.
370 :
371 : // METHODOLOGY EMPLOYED:
372 :
373 : // For each combination of exterior window and reference point in a zone,
374 : // calculates daylighting factors (interior illuminance / exterior illuminance)
375 : // and glare factors for clear and overcast skies and for windows with and
376 : // without shading devices. These factors are calculated for each hourly
377 : // sun position for design days and for selected days throughout the year.
378 :
379 : // If a target zone has one or more interior windows, also calculates daylighting
380 : // factors for the target zone that are associated with exterior windows in adjacent
381 : // zones that share interior windows with the target zone.
382 :
383 : // The daylight illuminance at a reference point from a window is determined
384 : // by dividing the window into rectangular elements and calculating the illuminance
385 : // reaching the reference point directly from each element. The illumination
386 : // from an element can come from the sky or ground if the window is unshaded, or from
387 : // a shading device illuminated by solar radiation. Also considered are the
388 : // illuminance contribution from interreflection among the zone's interior surfaces
389 : // and sunlight striking the reference point.
390 :
391 : // In calculating sky-related interior illuminance and luminance quantities,
392 : // the sky luminance for the different sky types are determined from distributions
393 : // in which the zenith luminance is normalized to 1.0 cd/m2. Similarly, sun-related
394 : // illuminance and luminance quantities are based on beam normal solar illuminance
395 : // normalized to 1.0 lux.
396 : // The daylight and glare factors calculated in this subroutine are used in DayltgInteriorIllum
397 : // to get the daylight illuminance and glare at each time step.
398 : // Based on this information and user-input lighting setpoint and type of lighting
399 : // control system, DayltgElecLightingControl then determines how much the overhead electric lighting
400 : // can be reduced.
401 :
402 : // REFERENCES:
403 : // Based on DOE-2.1E subroutine DCOF.
404 :
405 : // int IHR; // Hour of day counter
406 : // int IWin; // Window counter
407 : // int loop; // DO loop indices
408 : Real64 DaylFac; // sky daylight factor at ref pt i
409 :
410 : // added for output all daylight factors
411 : Real64 DFClrSky;
412 : Real64 DFClrTbSky;
413 : Real64 DFIntSky;
414 : Real64 DFOcSky;
415 :
416 : Real64 SlatAngle;
417 : int ISA;
418 : int ISlatAngle;
419 :
420 14330 : if (state.dataDaylightingManager->CalcDayltghCoefficients_firstTime) {
421 771 : GetDaylightingParametersInput(state);
422 771 : CheckTDDsAndLightShelvesInDaylitZones(state);
423 771 : AssociateWindowShadingControlWithDaylighting(state);
424 771 : state.dataDaylightingManager->CalcDayltghCoefficients_firstTime = false;
425 : } // End of check if firstTime
426 :
427 : // Find the total number of exterior windows associated with all Daylighting:Detailed enclosures.
428 : // An exterior window is associated with such a enclosure if (1) it is an exterior window in the enclosure, or
429 : // (2) it is an exterior window in an adjacent enclosure that shares an interior window with the enclosure.
430 : // Note that exterior windows in category (2) may be counted more than once if an adjacent enclosure
431 : // is adjacent to more than one daylit enclosure with which the adjacent enclosure shares interior windows.
432 : // If there are no interior windows in a building, than TotWindowsWithDayl is just the total number of
433 : // exterior windows in Daylighting:Detailed enclosures. Note that it is possible for a
434 : // Daylighting:Detailed enclosure to have zero exterior windows of its own, but it may have an interior
435 : // through which daylight passes from adjacent enclosures with exterior windows.
436 28658 : if ((int)state.dataDaylightingData->DaylRefPt.size() == 0) return;
437 507 : if (state.dataGlobal->BeginSimFlag) {
438 62 : state.dataDaylightingManager->TotWindowsWithDayl = 0;
439 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
440 708 : state.dataDaylightingManager->TotWindowsWithDayl += state.dataDaylightingData->enclDaylight(enclNum).NumOfDayltgExtWins;
441 : }
442 : }
443 :
444 507 : if (state.dataDaylightingManager->TotWindowsWithDayl == 0) return;
445 :
446 : //-----------------------------------------!
447 : // Detailed daylighting factor calculation !
448 : //-----------------------------------------!
449 507 : if (!state.dataSysVars->DetailedSolarTimestepIntegration && !state.dataGlobal->KickOffSizing && !state.dataGlobal->KickOffSimulation) {
450 200 : if (state.dataGlobal->WarmupFlag) {
451 200 : DisplayString(state, "Calculating Detailed Daylighting Factors, Start Date=" + state.dataEnvrn->CurMnDy);
452 : } else {
453 0 : DisplayString(state, "Updating Detailed Daylighting Factors, Start Date=" + state.dataEnvrn->CurMnDy);
454 : }
455 : }
456 :
457 507 : if (state.dataGlobal->BeginSimFlag) {
458 :
459 : // Find minimum solid angle subtended by an interior window in Daylighting:Detailed zones.
460 : // Used in calculating daylighting through interior windows.
461 62 : CalcMinIntWinSolidAngs(state);
462 :
463 : // Warning if detailed daylighting has been requested for a zone with no associated exterior windows.
464 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
465 708 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
466 708 : if (thisEnclDaylight.NumOfDayltgExtWins == 0 && thisEnclDaylight.TotalExtWindows == 0) {
467 244 : for (int daylightCtrlNum : thisEnclDaylight.daylightControlIndexes) {
468 0 : if (state.dataDaylightingData->daylightControl(daylightCtrlNum).TotalDaylRefPoints > 0) {
469 0 : ShowWarningError(state,
470 0 : "Detailed daylighting will not be done for Daylighting:Controls=" +
471 0 : state.dataDaylightingData->daylightControl(daylightCtrlNum).Name);
472 0 : ShowContinueError(state, "because it has no associated exterior windows.");
473 : }
474 : }
475 : }
476 :
477 : // Find area and reflectance quantities used in calculating inter-reflected illuminance.
478 : // TH 9/10/2009. Need to calculate for zones without daylighting controls (TotalDaylRefPoints = 0)
479 : // but with adjacent zones having daylighting controls.
480 708 : if ((thisEnclDaylight.NumOfDayltgExtWins > 0) || thisEnclDaylight.adjEnclHasDayltgCtrl) {
481 284 : DayltgAveInteriorReflectance(state, enclNum);
482 : }
483 : }
484 : }
485 :
486 : // Zero daylighting factor arrays
487 507 : if ((int)state.dataDaylightingDevicesData->TDDPipe.size() > 0) {
488 5 : if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
489 5 : state.dataDaylightingManager->TDDTransVisBeam = 0.0;
490 5 : state.dataDaylightingManager->TDDFluxInc = 0.0;
491 5 : state.dataDaylightingManager->TDDFluxTrans = 0.0;
492 : } else {
493 0 : state.dataDaylightingManager->TDDTransVisBeam(state.dataGlobal->HourOfDay, {1, (int)state.dataDaylightingDevicesData->TDDPipe.size()}) =
494 0 : 0.0;
495 0 : state.dataDaylightingManager->TDDFluxInc(
496 0 : state.dataGlobal->HourOfDay, {1, 4}, {1, (int)state.dataDaylightingDevicesData->TDDPipe.size()}) = 0.0;
497 0 : state.dataDaylightingManager->TDDFluxTrans(
498 0 : state.dataGlobal->HourOfDay, {1, 4}, {1, (int)state.dataDaylightingDevicesData->TDDPipe.size()}) = 0.0;
499 : }
500 : }
501 :
502 507 : if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
503 507 : if (state.dataGlobal->BeginDayFlag) {
504 : // Calculate hourly sun angles, clear sky zenith luminance, and exterior horizontal illuminance
505 507 : state.dataDaylightingManager->PHSUN = 0.0;
506 507 : state.dataDaylightingManager->SPHSUN = 0.0;
507 507 : state.dataDaylightingManager->CPHSUN = 0.0;
508 507 : state.dataDaylightingManager->THSUN = 0.0;
509 :
510 507 : state.dataDaylightingManager->PHSUNHR = 0.0;
511 507 : state.dataDaylightingManager->SPHSUNHR = 0.0;
512 507 : state.dataDaylightingManager->CPHSUNHR = 0.0;
513 507 : state.dataDaylightingManager->THSUNHR = 0.0;
514 507 : state.dataDaylightingManager->GILSK = 0.0;
515 507 : state.dataDaylightingManager->GILSU = 0.0;
516 12675 : for (int IHR = 1; IHR <= 24; ++IHR) {
517 12168 : if (state.dataSurface->SurfSunCosHourly(IHR)(3) < DataEnvironment::SunIsUpValue)
518 7830 : continue; // Skip if sun is below horizon //Autodesk SurfSunCosHourly was uninitialized here
519 4338 : state.dataDaylightingManager->PHSUN = DataGlobalConstants::PiOvr2 - std::acos(state.dataSurface->SurfSunCosHourly(IHR)(3));
520 4338 : state.dataDaylightingManager->PHSUNHR(IHR) = state.dataDaylightingManager->PHSUN;
521 4338 : state.dataDaylightingManager->SPHSUNHR(IHR) = std::sin(state.dataDaylightingManager->PHSUN);
522 4338 : state.dataDaylightingManager->CPHSUNHR(IHR) = std::cos(state.dataDaylightingManager->PHSUN);
523 4338 : state.dataDaylightingManager->THSUNHR(IHR) =
524 4338 : std::atan2(state.dataSurface->SurfSunCosHourly(IHR)(2), state.dataSurface->SurfSunCosHourly(IHR)(1));
525 : // Get exterior horizontal illuminance from sky and sun
526 4338 : state.dataDaylightingManager->THSUN = state.dataDaylightingManager->THSUNHR(IHR);
527 4338 : state.dataDaylightingManager->SPHSUN = state.dataDaylightingManager->SPHSUNHR(IHR);
528 4338 : state.dataDaylightingManager->CPHSUN = state.dataDaylightingManager->CPHSUNHR(IHR);
529 4338 : DayltgExtHorizIllum(state, state.dataDaylightingManager->GILSK(IHR, 1), state.dataDaylightingManager->GILSU(IHR));
530 : }
531 : }
532 : } else { // timestep integrated calculations
533 0 : state.dataDaylightingManager->PHSUN = 0.0;
534 0 : state.dataDaylightingManager->SPHSUN = 0.0;
535 0 : state.dataDaylightingManager->CPHSUN = 0.0;
536 0 : state.dataDaylightingManager->THSUN = 0.0;
537 :
538 0 : state.dataDaylightingManager->PHSUNHR(state.dataGlobal->HourOfDay) = 0.0;
539 0 : state.dataDaylightingManager->SPHSUNHR(state.dataGlobal->HourOfDay) = 0.0;
540 0 : state.dataDaylightingManager->CPHSUNHR(state.dataGlobal->HourOfDay) = 0.0;
541 0 : state.dataDaylightingManager->THSUNHR(state.dataGlobal->HourOfDay) = 0.0;
542 0 : state.dataDaylightingManager->GILSK(state.dataGlobal->HourOfDay, {1, 4}) = 0.0;
543 0 : state.dataDaylightingManager->GILSU(state.dataGlobal->HourOfDay) = 0.0;
544 0 : if (!(state.dataSurface->SurfSunCosHourly(state.dataGlobal->HourOfDay)(3) < DataEnvironment::SunIsUpValue)) { // Skip if sun is below horizon
545 0 : state.dataDaylightingManager->PHSUN =
546 0 : DataGlobalConstants::PiOvr2 - std::acos(state.dataSurface->SurfSunCosHourly(state.dataGlobal->HourOfDay)(3));
547 0 : state.dataDaylightingManager->PHSUNHR(state.dataGlobal->HourOfDay) = state.dataDaylightingManager->PHSUN;
548 0 : state.dataDaylightingManager->SPHSUNHR(state.dataGlobal->HourOfDay) = std::sin(state.dataDaylightingManager->PHSUN);
549 0 : state.dataDaylightingManager->CPHSUNHR(state.dataGlobal->HourOfDay) = std::cos(state.dataDaylightingManager->PHSUN);
550 0 : state.dataDaylightingManager->THSUNHR(state.dataGlobal->HourOfDay) =
551 0 : std::atan2(state.dataSurface->SurfSunCosHourly(state.dataGlobal->HourOfDay)(2),
552 0 : state.dataSurface->SurfSunCosHourly(state.dataGlobal->HourOfDay)(1));
553 : // Get exterior horizontal illuminance from sky and sun
554 0 : state.dataDaylightingManager->THSUN = state.dataDaylightingManager->THSUNHR(state.dataGlobal->HourOfDay);
555 0 : state.dataDaylightingManager->SPHSUN = state.dataDaylightingManager->SPHSUNHR(state.dataGlobal->HourOfDay);
556 0 : state.dataDaylightingManager->CPHSUN = state.dataDaylightingManager->CPHSUNHR(state.dataGlobal->HourOfDay);
557 0 : DayltgExtHorizIllum(state,
558 0 : state.dataDaylightingManager->GILSK(state.dataGlobal->HourOfDay, 1),
559 0 : state.dataDaylightingManager->GILSU(state.dataGlobal->HourOfDay));
560 : }
561 : }
562 :
563 507 : CalcDayltgCoeffsRefMapPoints(state);
564 :
565 507 : if (state.dataDaylightingManager->doSkyReporting) {
566 239 : if (!state.dataGlobal->KickOffSizing && !state.dataGlobal->KickOffSimulation) {
567 62 : if (state.dataDaylightingManager->FirstTimeDaylFacCalc && state.dataDaylightingManager->TotWindowsWithDayl > 0) {
568 : // Write the bare-window four sky daylight factors at noon time to the eio file; this is done only
569 : // for first time that daylight factors are calculated and so is insensitive to possible variation
570 : // due to change in ground reflectance from month to month, or change in storm window status.
571 : static constexpr std::string_view Format_700(
572 : "! <Sky Daylight Factors>, Sky Type, MonthAndDay, Daylighting Control Name, Enclosure Name, "
573 : "Window Name, Reference Point, Daylight Factor\n");
574 62 : print(state.files.eio, Format_700);
575 349 : for (int controlNum = 1; controlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++controlNum) {
576 287 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(controlNum);
577 287 : int enclNum = thisDaylightControl.enclIndex;
578 287 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
579 :
580 287 : if (thisEnclDaylight.NumOfDayltgExtWins == 0 || !thisEnclDaylight.hasSplitFluxDaylighting) continue;
581 1126 : for (int windowCounter = 1; windowCounter <= thisEnclDaylight.NumOfDayltgExtWins; ++windowCounter) {
582 842 : int windowSurfNum = thisEnclDaylight.DayltgExtWinSurfNums(windowCounter);
583 : // For this report, do not include ext wins in zone adjacent to ZoneNum since the inter-reflected
584 : // component will not be calculated for these windows until the time-step loop.
585 842 : if (state.dataSurface->Surface(windowSurfNum).SolarEnclIndex == enclNum) {
586 : // Output for each reference point, for each sky. Group by sky type first
587 6728 : for (const DataDaylighting::SkyType &skyType : {DataDaylighting::SkyType::Clear,
588 : DataDaylighting::SkyType::ClearTurbid,
589 : DataDaylighting::SkyType::Intermediate,
590 841 : DataDaylighting::SkyType::Overcast}) {
591 6728 : std::string skyTypeString;
592 3364 : if (skyType == DataDaylighting::SkyType::Clear) {
593 841 : skyTypeString = "Clear Sky";
594 2523 : } else if (skyType == DataDaylighting::SkyType::ClearTurbid) {
595 841 : skyTypeString = "Clear Turbid Sky";
596 1682 : } else if (skyType == DataDaylighting::SkyType::Intermediate) {
597 841 : skyTypeString = "Intermediate Sky";
598 841 : } else if (skyType == DataDaylighting::SkyType::Overcast) {
599 841 : skyTypeString = "Overcast Sky";
600 : //} else {
601 : // // Should never happen
602 : // skyTypeString = "ERROR_SKY_TYPE_NOT_HANDLED";
603 : }
604 :
605 9292 : for (int refPtNum = 1; refPtNum <= thisDaylightControl.TotalDaylRefPoints; ++refPtNum) {
606 5928 : DaylFac = thisDaylightControl.DaylIllFacSky(12, 1, static_cast<int>(skyType), refPtNum, windowCounter);
607 29640 : print(state.files.eio,
608 : " Sky Daylight Factors,{},{},{},{},{},{},{:.4R}\n",
609 : skyTypeString,
610 5928 : state.dataEnvrn->CurMnDy,
611 : thisDaylightControl.Name,
612 5928 : state.dataViewFactor->EnclSolInfo(thisDaylightControl.enclIndex).Name,
613 5928 : state.dataSurface->Surface(windowSurfNum).Name,
614 5928 : state.dataDaylightingData->DaylRefPt(thisDaylightControl.DaylRefPtNum(refPtNum)).Name,
615 5928 : DaylFac);
616 : }
617 : }
618 : }
619 : }
620 : }
621 62 : state.dataDaylightingManager->FirstTimeDaylFacCalc = false;
622 62 : state.dataDaylightingManager->doSkyReporting = false;
623 : }
624 : }
625 : }
626 :
627 : // Skip if no daylight windows
628 507 : if (state.dataDaylightingManager->TotWindowsWithDayl == 0) return;
629 :
630 : // Skip if no request of reporting
631 507 : if ((!state.dataDaylightingData->DFSReportSizingDays) && (!state.dataDaylightingData->DFSReportAllShadowCalculationDays)) return;
632 :
633 : // Skip duplicate calls
634 9 : if (state.dataGlobal->KickOffSizing) return;
635 7 : if (state.dataGlobal->DoingSizing) return;
636 5 : if (state.dataGlobal->KickOffSimulation) return;
637 :
638 2 : if (state.dataDaylightingData->DFSReportSizingDays) {
639 2 : if (state.dataGlobal->DoWeathSim && state.dataGlobal->DoDesDaySim) {
640 0 : if (state.dataGlobal->KindOfSim == DataGlobalConstants::KindOfSim::RunPeriodWeather) return;
641 : }
642 : }
643 :
644 2 : if (state.dataDaylightingData->DFSReportAllShadowCalculationDays) {
645 0 : if (state.dataGlobal->KindOfSim != DataGlobalConstants::KindOfSim::RunPeriodWeather) return;
646 : }
647 :
648 : // open a new file eplusout.dfs for saving the daylight factors
649 2 : if (state.dataDaylightingManager->CreateDFSReportFile) {
650 1 : InputOutputFile &dfs = state.files.dfs.ensure_open(state, "CalcDayltgCoefficients", state.files.outputControl.dfs);
651 1 : print(dfs, "{}\n", "This file contains daylight factors for all exterior windows of daylight enclosures.");
652 1 : print(dfs, "{}\n", "MonthAndDay,Enclosure Name,Zone Name,Window Name,Window State");
653 1 : print(dfs,
654 : "{}\n",
655 : "Hour,Reference Point,Daylight Factor for Clear Sky,Daylight Factor for Clear Turbid Sky,"
656 1 : "Daylight Factor for Intermediate Sky,Daylight Factor for Overcast Sky");
657 1 : state.dataDaylightingManager->CreateDFSReportFile = false;
658 : }
659 :
660 26 : for (int controlNum = 1; controlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++controlNum) {
661 24 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(controlNum);
662 24 : int enclNum = thisDaylightControl.enclIndex;
663 24 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
664 24 : if (thisEnclDaylight.NumOfDayltgExtWins == 0) continue;
665 :
666 48 : for (int windowCounter = 1; windowCounter <= thisEnclDaylight.NumOfDayltgExtWins; ++windowCounter) {
667 24 : int windowSurfNum = thisEnclDaylight.DayltgExtWinSurfNums(windowCounter);
668 :
669 : // For this report, do not include ext wins in zone/enclosure adjacent to ZoneNum since the inter-reflected
670 : // component will not be calculated for these windows until the time-step loop.
671 24 : if (state.dataSurface->Surface(windowSurfNum).SolarEnclIndex == enclNum) {
672 :
673 24 : if (state.dataSurface->SurfWinMovableSlats(windowSurfNum)) {
674 : // variable slat angle - MaxSlatangle sets
675 0 : ISA = MaxSlatAngs + 1;
676 24 : } else if (state.dataSurface->Surface(windowSurfNum).HasShadeControl) {
677 : // window shade or blind with fixed slat angle
678 0 : ISA = 2;
679 : } else {
680 : // base window
681 24 : ISA = 1;
682 : }
683 :
684 : // loop over each slat angle
685 48 : for (ISlatAngle = 1; ISlatAngle <= ISA; ++ISlatAngle) {
686 24 : if (ISlatAngle == 1) {
687 : // base window without shades, screens, or blinds
688 120 : print(state.files.dfs,
689 : "{},{},{},{},Base Window\n",
690 24 : state.dataEnvrn->CurMnDy,
691 24 : state.dataViewFactor->EnclSolInfo(enclNum).Name,
692 24 : state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).Name,
693 48 : state.dataSurface->Surface(windowSurfNum).Name);
694 0 : } else if (ISlatAngle == 2 && ISA == 2) {
695 : // window shade or blind with fixed slat angle
696 0 : print(state.files.dfs,
697 : "{},{},{},{},Blind or Slat Applied\n",
698 0 : state.dataEnvrn->CurMnDy,
699 0 : state.dataViewFactor->EnclSolInfo(enclNum).Name,
700 0 : state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).Name,
701 0 : state.dataSurface->Surface(windowSurfNum).Name);
702 : } else {
703 : // blind with variable slat angle
704 0 : SlatAngle = 180.0 / double(MaxSlatAngs - 1) * double(ISlatAngle - 2);
705 0 : print(state.files.dfs,
706 : "{},{},{},{},{:.1R}\n",
707 0 : state.dataEnvrn->CurMnDy,
708 0 : state.dataViewFactor->EnclSolInfo(enclNum).Name,
709 0 : state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).Name,
710 0 : state.dataSurface->Surface(windowSurfNum).Name,
711 0 : SlatAngle);
712 : }
713 :
714 600 : for (int IHR = 1; IHR <= 24; ++IHR) {
715 : // For each Daylight Reference Point
716 1152 : for (int refPtNum = 1; refPtNum <= thisDaylightControl.TotalDaylRefPoints; ++refPtNum) {
717 576 : DFClrSky = thisDaylightControl.DaylIllFacSky(
718 576 : IHR, ISlatAngle, static_cast<int>(DataDaylighting::SkyType::Clear), refPtNum, windowCounter);
719 576 : DFClrTbSky = thisDaylightControl.DaylIllFacSky(
720 576 : IHR, ISlatAngle, static_cast<int>(DataDaylighting::SkyType::ClearTurbid), refPtNum, windowCounter);
721 576 : DFIntSky = thisDaylightControl.DaylIllFacSky(
722 576 : IHR, ISlatAngle, static_cast<int>(DataDaylighting::SkyType::Intermediate), refPtNum, windowCounter);
723 576 : DFOcSky = thisDaylightControl.DaylIllFacSky(
724 576 : IHR, ISlatAngle, static_cast<int>(DataDaylighting::SkyType::Overcast), refPtNum, windowCounter);
725 :
726 : // write daylight factors - 4 sky types for each daylight ref point
727 1152 : print(state.files.dfs,
728 : "{},{},{:.5R},{:.5R},{:.5R},{:.5R}\n",
729 : IHR,
730 576 : state.dataDaylightingData->DaylRefPt(thisDaylightControl.DaylRefPtNum(refPtNum)).Name,
731 : DFClrSky,
732 : DFClrTbSky,
733 : DFIntSky,
734 576 : DFOcSky);
735 : } // for (refPtNum) Reference Point
736 : } // for (IHR) hour
737 : } // for (ISlatAngle) slat angle
738 : } // if (SolarEnclIndex == enclNum)
739 : } // for (windowCounter) exterior windows in enclosure
740 : } // for (controlNum) daylighting control
741 : }
742 :
743 507 : void CalcDayltgCoeffsRefMapPoints(EnergyPlusData &state)
744 : {
745 :
746 : // SUBROUTINE INFORMATION:
747 : // AUTHOR Linda Lawrie
748 : // DATE WRITTEN October 2004
749 : // MODIFIED May 2006 (RR): added exterior window screens
750 : // April 2012 (LKL); change to allow multiple maps per zone
751 :
752 : // PURPOSE OF THIS SUBROUTINE:
753 : // This subroutine does the daylighting coefficient calculation for the
754 : // daylighting and illuminance map reference points.
755 :
756 : bool ErrorsFound;
757 :
758 507 : if (state.dataDaylightingManager->VeryFirstTime) {
759 : // make sure all necessary surfaces match to pipes
760 62 : ErrorsFound = false;
761 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
762 1547 : for (int loopwin = 1; loopwin <= state.dataDaylightingData->enclDaylight(enclNum).NumOfDayltgExtWins; ++loopwin) {
763 839 : int IWin = state.dataDaylightingData->enclDaylight(enclNum).DayltgExtWinSurfNums(loopwin);
764 839 : if (state.dataSurface->SurfWinOriginalClass(IWin) != SurfaceClass::TDD_Diffuser) continue;
765 : // Look up the TDD:DOME object
766 2 : int PipeNum = state.dataSurface->SurfWinTDDPipeNum(IWin);
767 2 : if (PipeNum == 0) {
768 0 : ShowSevereError(state,
769 0 : "GetTDDInput: Surface=" + state.dataSurface->Surface(IWin).Name +
770 : ", TDD:Dome object does not reference a valid Diffuser object.");
771 0 : ShowContinueError(state, "...needs DaylightingDevice:Tubular of same name as Surface.");
772 0 : ErrorsFound = true;
773 : }
774 : }
775 : }
776 :
777 62 : if (ErrorsFound) {
778 0 : ShowFatalError(state, "Not all TubularDaylightDome objects have corresponding DaylightingDevice:Tubular objects. Program terminates.");
779 : }
780 62 : state.dataDaylightingManager->VeryFirstTime = false;
781 : }
782 :
783 : // Calc for daylighting reference points for daylighting controls that use SplitFlux method
784 3251 : for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
785 2744 : if (state.dataDaylightingData->daylightControl(daylightCtrlNum).DaylightMethod != DataDaylighting::DaylightingMethod::SplitFlux) continue;
786 : // Skip enclosures with no exterior windows or in adjacent enclosure(s) with which an interior window is shared
787 2729 : if (state.dataDaylightingData->enclDaylight(state.dataDaylightingData->daylightControl(daylightCtrlNum).enclIndex).NumOfDayltgExtWins == 0)
788 0 : continue;
789 2729 : CalcDayltgCoeffsRefPoints(state, daylightCtrlNum);
790 : }
791 507 : if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation) {
792 : // Calc for illuminance maps
793 134 : if ((int)state.dataDaylightingData->IllumMap.size() > 0) {
794 44 : for (int MapNum = 1; MapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++MapNum) {
795 24 : int mapZoneNum = state.dataDaylightingData->IllumMapCalc(MapNum).zoneIndex;
796 24 : if (state.dataGlobal->WarmupFlag) {
797 24 : DisplayString(state, "Calculating Daylighting Coefficients (Map Points), Zone=" + state.dataHeatBal->Zone(mapZoneNum).Name);
798 : } else {
799 0 : DisplayString(state, "Updating Daylighting Coefficients (Map Points), Zone=" + state.dataHeatBal->Zone(mapZoneNum).Name);
800 : }
801 24 : CalcDayltgCoeffsMapPoints(state, MapNum);
802 : }
803 : }
804 : }
805 507 : }
806 :
807 2729 : void CalcDayltgCoeffsRefPoints(EnergyPlusData &state, int const daylightCtrlNum)
808 : {
809 :
810 : // SUBROUTINE INFORMATION:
811 : // AUTHOR Linda Lawrie
812 : // DATE WRITTEN April 2012
813 : // MODIFIED November 2012 (B. Griffith), refactor for detailed timestep integration and remove duplicate code
814 : // RE-ENGINEERED na
815 :
816 : // PURPOSE OF THIS SUBROUTINE:
817 : // Provides calculations for Daylighting Coefficients for daylighting reference points
818 :
819 : int IHR; // Hour of day counter
820 : int NRF; // Number of daylighting reference points in a zone
821 : int IL; // Reference point counter
822 : Real64 AZVIEW; // Azimuth of view vector in absolute coord system for
823 : // glare calculation (radians)
824 : int IConst; // Construction counter
825 : int ICtrl; // Window control counter
826 : int IWin; // Window counter
827 : int IWin2; // Secondary window counter (for TDD:DOME object, if exists)
828 : int InShelfSurf; // Inside daylighting shelf surface number
829 : WinShadingType ShType; // Window shading type
830 : int BlNum; // Window Blind Number
831 : int LSHCAL; // Interior shade calculation flag: 0=not yet
832 : // calculated, 1=already calculated
833 : int NWX; // Number of window elements in x direction for dayltg calc
834 : int NWY; // Number of window elements in y direction for dayltg calc
835 : int NWYlim; // For triangle, largest NWY for a given IX
836 : int IX; // Counter for window elements in the x direction
837 : int IY; // Counter for window elements in the y direction
838 : Real64 COSB; // Cosine of angle between window outward normal and ray from
839 : // reference point to window element
840 : Real64 PHRAY; // Altitude of ray from reference point to window element (radians)
841 : Real64 THRAY; // Azimuth of ray from reference point to window element (radians)
842 : Real64 DOMEGA; // Solid angle subtended by window element wrt reference point (steradians)
843 : Real64 TVISB; // Visible transmittance of window for COSB angle of incidence (times light well
844 : // efficiency, if appropriate)
845 : int ISunPos; // Sun position counter; used to avoid calculating various
846 : // quantities that do not depend on sun position.
847 : Real64 ObTrans; // Product of solar transmittances of exterior obstructions hit by ray
848 : // from reference point through a window element
849 : int loopwin; // loop index for exterior windows associated with a daylit zone
850 : bool is_Rectangle; // True if window is rectangular
851 : bool is_Triangle; // True if window is triangular
852 : Real64 DWX; // Horizontal dimension of window element (m)
853 : Real64 DWY; // Vertical dimension of window element (m)
854 : Real64 DAXY; // Area of window element
855 : Real64 SkyObstructionMult; // Ratio of obstructed to unobstructed sky diffuse at a ground point
856 : DataDaylighting::ExtWinType ExtWinType; // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
857 : int BRef;
858 : int ILB;
859 : bool hitIntObs; // True iff interior obstruction hit
860 : bool hitExtObs; // True iff ray from ref pt to ext win hits an exterior obstruction
861 : Real64 TVISIntWin; // Visible transmittance of int win at COSBIntWin for light from ext win
862 : Real64 TVISIntWinDisk; // Visible transmittance of int win at COSBIntWin for sun
863 :
864 2729 : auto &W2 = state.dataDaylightingManager->W2;
865 2729 : auto &W3 = state.dataDaylightingManager->W3;
866 2729 : auto &W21 = state.dataDaylightingManager->W21;
867 2729 : auto &W23 = state.dataDaylightingManager->W23;
868 2729 : auto &RREF = state.dataDaylightingManager->RREF;
869 2729 : auto &RREF2 = state.dataDaylightingManager->RREF2;
870 2729 : auto &RWIN = state.dataDaylightingManager->RWIN;
871 2729 : auto &RWIN2 = state.dataDaylightingManager->RWIN2;
872 2729 : auto &Ray = state.dataDaylightingManager->Ray;
873 2729 : auto &WNORM2 = state.dataDaylightingManager->WNORM2;
874 2729 : auto &VIEWVC = state.dataDaylightingManager->VIEWVC;
875 2729 : auto &U2 = state.dataDaylightingManager->U2;
876 2729 : auto &U21 = state.dataDaylightingManager->U21;
877 2729 : auto &U23 = state.dataDaylightingManager->U23;
878 2729 : auto &VIEWVC2 = state.dataDaylightingManager->VIEWVC2;
879 :
880 : int WinEl; // Current window element
881 :
882 2729 : if (state.dataDaylightingManager->refFirstTime && (state.dataDaylightingData->maxRefPointsPerControl > 0)) {
883 62 : state.dataDaylightingManager->RefErrIndex.allocate(state.dataDaylightingData->maxRefPointsPerControl, state.dataSurface->TotSurfaces);
884 62 : state.dataDaylightingManager->RefErrIndex = 0;
885 62 : state.dataDaylightingManager->refFirstTime = false;
886 : }
887 :
888 2729 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
889 2729 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(thisDaylightControl.enclIndex);
890 2729 : int zoneNum = thisDaylightControl.zoneIndex;
891 : // Azimuth of view vector in absolute coord sys
892 5458 : AZVIEW = (thisDaylightControl.ViewAzimuthForGlare + state.dataHeatBal->Zone(zoneNum).RelNorth + state.dataHeatBal->BuildingAzimuth +
893 2729 : state.dataHeatBal->BuildingRotationAppendixG) *
894 : DataGlobalConstants::DegToRadians;
895 : // View vector components in absolute coord sys
896 2729 : VIEWVC(1) = std::sin(AZVIEW);
897 2729 : VIEWVC(2) = std::cos(AZVIEW);
898 2729 : VIEWVC(3) = 0.0;
899 :
900 2729 : thisDaylightControl.DaylIllumAtRefPt = 0.0; // Daylight illuminance at reference points (lux)
901 2729 : thisDaylightControl.GlareIndexAtRefPt = 0.0; // Glare index at reference points
902 2729 : thisDaylightControl.SolidAngAtRefPt = 0.0;
903 2729 : thisDaylightControl.SolidAngAtRefPtWtd = 0.0;
904 2729 : thisDaylightControl.IllumFromWinAtRefPt = 0.0;
905 2729 : thisDaylightControl.BackLumFromWinAtRefPt = 0.0;
906 2729 : thisDaylightControl.SourceLumFromWinAtRefPt = 0.0;
907 :
908 2729 : if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
909 :
910 2729 : thisDaylightControl.DaylIllFacSky = 0.0;
911 2729 : thisDaylightControl.DaylSourceFacSky = 0.0;
912 2729 : thisDaylightControl.DaylBackFacSky = 0.0;
913 2729 : thisDaylightControl.DaylIllFacSun = 0.0;
914 2729 : thisDaylightControl.DaylIllFacSunDisk = 0.0;
915 2729 : thisDaylightControl.DaylSourceFacSun = 0.0;
916 2729 : thisDaylightControl.DaylSourceFacSunDisk = 0.0;
917 2729 : thisDaylightControl.DaylBackFacSun = 0.0;
918 2729 : thisDaylightControl.DaylBackFacSunDisk = 0.0;
919 : } else {
920 0 : int numRefPts = thisDaylightControl.TotalDaylRefPoints;
921 0 : thisDaylightControl.DaylIllFacSky(state.dataGlobal->HourOfDay,
922 0 : {1, state.dataSurface->actualMaxSlatAngs + 1},
923 : {1, 4},
924 : {1, numRefPts},
925 0 : {1, thisEnclDaylight.NumOfDayltgExtWins}) = 0.0;
926 0 : thisDaylightControl.DaylSourceFacSky(state.dataGlobal->HourOfDay,
927 0 : {1, state.dataSurface->actualMaxSlatAngs + 1},
928 : {1, 4},
929 : {1, numRefPts},
930 0 : {1, thisEnclDaylight.NumOfDayltgExtWins}) = 0.0;
931 0 : thisDaylightControl.DaylBackFacSky(state.dataGlobal->HourOfDay,
932 0 : {1, state.dataSurface->actualMaxSlatAngs + 1},
933 : {1, 4},
934 : {1, numRefPts},
935 0 : {1, thisEnclDaylight.NumOfDayltgExtWins}) = 0.0;
936 0 : thisDaylightControl.DaylIllFacSun(
937 0 : state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
938 0 : 0.0;
939 0 : thisDaylightControl.DaylIllFacSunDisk(
940 0 : state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
941 0 : 0.0;
942 0 : thisDaylightControl.DaylSourceFacSun(
943 0 : state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
944 0 : 0.0;
945 0 : thisDaylightControl.DaylSourceFacSunDisk(
946 0 : state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
947 0 : 0.0;
948 0 : thisDaylightControl.DaylBackFacSun(
949 0 : state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
950 0 : 0.0;
951 0 : thisDaylightControl.DaylBackFacSunDisk(
952 0 : state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
953 0 : 0.0;
954 : }
955 :
956 2729 : NRF = thisDaylightControl.TotalDaylRefPoints;
957 2729 : BRef = 0;
958 :
959 7286 : for (IL = 1; IL <= NRF; ++IL) {
960 : // Reference point in absolute coordinate system
961 4557 : RREF = thisDaylightControl.DaylRefPtAbsCoord({1, 3}, IL); // ( x, y, z )
962 :
963 : // -------------
964 : // ---------- WINDOW LOOP ----------
965 : // -------------
966 19587 : for (loopwin = 1; loopwin <= thisEnclDaylight.NumOfDayltgExtWins; ++loopwin) {
967 :
968 15030 : FigureDayltgCoeffsAtPointsSetupForWindow(state,
969 : daylightCtrlNum,
970 : IL,
971 : loopwin,
972 : DataDaylighting::CalledFor::RefPoint,
973 : RREF,
974 : VIEWVC,
975 : IWin,
976 : IWin2,
977 : NWX,
978 : NWY,
979 : W2,
980 : W3,
981 : W21,
982 : W23,
983 : LSHCAL,
984 : InShelfSurf,
985 : ICtrl,
986 : ShType,
987 : BlNum,
988 : WNORM2,
989 : ExtWinType,
990 : IConst,
991 : RREF2,
992 : DWX,
993 : DWY,
994 : DAXY,
995 : U2,
996 : U23,
997 : U21,
998 : VIEWVC2,
999 : is_Rectangle,
1000 : is_Triangle);
1001 : // ---------------------
1002 : // ---------- WINDOW ELEMENT LOOP ----------
1003 : // ---------------------
1004 :
1005 15030 : WinEl = 0;
1006 :
1007 205236 : for (IX = 1; IX <= NWX; ++IX) {
1008 190206 : if (is_Rectangle) {
1009 190206 : NWYlim = NWY;
1010 0 : } else if (is_Triangle) {
1011 0 : NWYlim = NWY - IX + 1;
1012 : }
1013 :
1014 768910 : for (IY = 1; IY <= NWYlim; ++IY) {
1015 :
1016 578704 : ++WinEl;
1017 :
1018 578704 : FigureDayltgCoeffsAtPointsForWindowElements(state,
1019 : daylightCtrlNum,
1020 : IL,
1021 : loopwin,
1022 : DataDaylighting::CalledFor::RefPoint,
1023 : WinEl,
1024 : IWin,
1025 : IWin2,
1026 : IX,
1027 : IY,
1028 : SkyObstructionMult,
1029 : W2,
1030 : W21,
1031 : W23,
1032 : RREF,
1033 : NWYlim,
1034 : VIEWVC2,
1035 : DWX,
1036 : DWY,
1037 : DAXY,
1038 : U2,
1039 : U23,
1040 : U21,
1041 : RWIN,
1042 : RWIN2,
1043 : Ray,
1044 : PHRAY,
1045 : LSHCAL,
1046 : COSB,
1047 : ObTrans,
1048 : TVISB,
1049 : DOMEGA,
1050 : THRAY,
1051 : hitIntObs,
1052 : hitExtObs,
1053 : WNORM2,
1054 : ExtWinType,
1055 : IConst,
1056 : RREF2,
1057 : is_Triangle,
1058 : TVISIntWin,
1059 : TVISIntWinDisk);
1060 :
1061 : // -------------------
1062 : // ---------- SUN POSITION LOOP ----------
1063 : // -------------------
1064 :
1065 : // Sun position counter. Used to avoid calculating various quantities
1066 : // that do not depend on sun position.
1067 :
1068 578704 : if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
1069 578704 : ISunPos = 0;
1070 14467600 : for (IHR = 1; IHR <= 24; ++IHR) {
1071 :
1072 13888896 : FigureDayltgCoeffsAtPointsForSunPosition(state,
1073 : daylightCtrlNum,
1074 : IL,
1075 : IX,
1076 : NWX,
1077 : IY,
1078 : NWYlim,
1079 : WinEl,
1080 : IWin,
1081 : IWin2,
1082 : IHR,
1083 : ISunPos,
1084 : SkyObstructionMult,
1085 : RWIN2,
1086 : Ray,
1087 : PHRAY,
1088 : LSHCAL,
1089 : InShelfSurf,
1090 : COSB,
1091 : ObTrans,
1092 : TVISB,
1093 : DOMEGA,
1094 : ICtrl,
1095 : ShType,
1096 : BlNum,
1097 : THRAY,
1098 : WNORM2,
1099 : ExtWinType,
1100 : IConst,
1101 : AZVIEW,
1102 : RREF2,
1103 : hitIntObs,
1104 : hitExtObs,
1105 : DataDaylighting::CalledFor::RefPoint,
1106 : TVISIntWin,
1107 : TVISIntWinDisk);
1108 :
1109 : } // End of hourly sun position loop, IHR
1110 : } else { // timestep integrated
1111 0 : if (state.dataEnvrn->SunIsUp && !state.dataDaylightingManager->MySunIsUpFlag) {
1112 0 : ISunPos = 0;
1113 0 : state.dataDaylightingManager->MySunIsUpFlag = true;
1114 0 : } else if (state.dataEnvrn->SunIsUp && state.dataDaylightingManager->MySunIsUpFlag) {
1115 0 : ISunPos = 1;
1116 0 : } else if (!state.dataEnvrn->SunIsUp && state.dataDaylightingManager->MySunIsUpFlag) {
1117 0 : state.dataDaylightingManager->MySunIsUpFlag = false;
1118 0 : ISunPos = -1;
1119 0 : } else if (!state.dataEnvrn->SunIsUp && !state.dataDaylightingManager->MySunIsUpFlag) {
1120 0 : ISunPos = -1;
1121 : }
1122 :
1123 0 : FigureDayltgCoeffsAtPointsForSunPosition(state,
1124 : daylightCtrlNum,
1125 : IL,
1126 : IX,
1127 : NWX,
1128 : IY,
1129 : NWYlim,
1130 : WinEl,
1131 : IWin,
1132 : IWin2,
1133 0 : state.dataGlobal->HourOfDay,
1134 : ISunPos,
1135 : SkyObstructionMult,
1136 : RWIN2,
1137 : Ray,
1138 : PHRAY,
1139 : LSHCAL,
1140 : InShelfSurf,
1141 : COSB,
1142 : ObTrans,
1143 : TVISB,
1144 : DOMEGA,
1145 : ICtrl,
1146 : ShType,
1147 : BlNum,
1148 : THRAY,
1149 : WNORM2,
1150 : ExtWinType,
1151 : IConst,
1152 : AZVIEW,
1153 : RREF2,
1154 : hitIntObs,
1155 : hitExtObs,
1156 : DataDaylighting::CalledFor::RefPoint,
1157 : TVISIntWin,
1158 : TVISIntWinDisk);
1159 : }
1160 :
1161 : } // End of window Y-element loop, IY
1162 : } // End of window X-element loop, IX
1163 :
1164 : // Loop again over hourly sun positions and calculate daylight factors by adding
1165 : // direct and inter-reflected illum components, then dividing by exterior horiz illum.
1166 : // Also calculate corresponding glare factors.
1167 :
1168 15030 : ILB = BRef + IL;
1169 :
1170 15030 : if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
1171 15030 : ISunPos = 0;
1172 375750 : for (IHR = 1; IHR <= 24; ++IHR) {
1173 360720 : FigureRefPointDayltgFactorsToAddIllums(state, daylightCtrlNum, ILB, IHR, ISunPos, IWin, loopwin, NWX, NWY, ICtrl);
1174 :
1175 : } // End of sun position loop, IHR
1176 : } else {
1177 0 : if (state.dataEnvrn->SunIsUp && !state.dataDaylightingManager->MySunIsUpFlag) {
1178 0 : ISunPos = 0;
1179 0 : state.dataDaylightingManager->MySunIsUpFlag = true;
1180 0 : } else if (state.dataEnvrn->SunIsUp && state.dataDaylightingManager->MySunIsUpFlag) {
1181 0 : ISunPos = 1;
1182 0 : } else if (!state.dataEnvrn->SunIsUp && state.dataDaylightingManager->MySunIsUpFlag) {
1183 0 : state.dataDaylightingManager->MySunIsUpFlag = false;
1184 0 : ISunPos = -1;
1185 0 : } else if (!state.dataEnvrn->SunIsUp && !state.dataDaylightingManager->MySunIsUpFlag) {
1186 0 : ISunPos = -1;
1187 : }
1188 0 : FigureRefPointDayltgFactorsToAddIllums(
1189 0 : state, daylightCtrlNum, ILB, state.dataGlobal->HourOfDay, ISunPos, IWin, loopwin, NWX, NWY, ICtrl);
1190 : }
1191 : } // End of window loop, loopwin - IWin
1192 :
1193 : } // End of reference point loop, IL
1194 2729 : }
1195 :
1196 24 : void CalcDayltgCoeffsMapPoints(EnergyPlusData &state, int const mapNum)
1197 : {
1198 :
1199 : // SUBROUTINE INFORMATION:
1200 : // AUTHOR Linda Lawrie
1201 : // DATE WRITTEN April 2012
1202 : // MODIFIED November 2012 (B. Griffith), refactor for detailed timestep integration and remove duplicate code
1203 : // RE-ENGINEERED na
1204 :
1205 : // PURPOSE OF THIS SUBROUTINE:
1206 : // Provides calculations for Daylighting Coefficients for map illuminance points
1207 :
1208 : // METHODOLOGY EMPLOYED:
1209 : // Was previously part of CalcDayltgCoeffsRefMapPoints -- broken out to all multiple
1210 : // maps per zone
1211 :
1212 : // In the following four variables, I=1 for clear sky, 2 for overcast.
1213 : int IHR; // Hour of day counter
1214 : int numRefPts; // Number of daylighting reference points in a zone
1215 : int IL; // Reference point counter
1216 : Real64 AZVIEW; // Azimuth of view vector in absolute coord system for
1217 : // glare calculation (radians)
1218 : int IConst; // Construction counter
1219 : int ICtrl; // Window control counter
1220 : int IWin; // Window counter
1221 : int IWin2; // Secondary window counter (for TDD:DOME object, if exists)
1222 : int InShelfSurf; // Inside daylighting shelf surface number
1223 : WinShadingType ShType; // Window shading type
1224 : int BlNum; // Window Blind Number
1225 : int LSHCAL; // Interior shade calculation flag: 0=not yet
1226 : // calculated, 1=already calculated
1227 : int NWX; // Number of window elements in x direction for dayltg calc
1228 : int NWY; // Number of window elements in y direction for dayltg calc
1229 : int NWYlim; // For triangle, largest NWY for a given IX
1230 : Real64 DWX; // Horizontal dimension of window element (m)
1231 : Real64 DWY; // Vertical dimension of window element (m)
1232 : int IX; // Counter for window elements in the x direction
1233 : int IY; // Counter for window elements in the y direction
1234 : Real64 COSB; // Cosine of angle between window outward normal and ray from
1235 : // reference point to window element
1236 : Real64 PHRAY; // Altitude of ray from reference point to window element (radians)
1237 : Real64 THRAY; // Azimuth of ray from reference point to window element (radians)
1238 : Real64 DOMEGA; // Solid angle subtended by window element wrt reference point (steradians)
1239 : Real64 TVISB; // Visible transmittance of window for COSB angle of incidence (times light well
1240 : // efficiency, if appropriate)
1241 : int ISunPos; // Sun position counter; used to avoid calculating various
1242 : // quantities that do not depend on sun position.
1243 : Real64 ObTrans; // Product of solar transmittances of exterior obstructions hit by ray
1244 : // from reference point through a window element
1245 : int loopwin; // loop index for exterior windows associated with a daylit zone
1246 : bool is_Rectangle; // True if window is rectangular
1247 : bool is_Triangle; // True if window is triangular
1248 : Real64 DAXY; // Area of window element
1249 : Real64 SkyObstructionMult; // Ratio of obstructed to unobstructed sky diffuse at a ground point
1250 : DataDaylighting::ExtWinType ExtWinType; // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
1251 : int ILB;
1252 : bool hitIntObs; // True iff interior obstruction hit
1253 : bool hitExtObs; // True iff ray from ref pt to ext win hits an exterior obstruction
1254 : Real64 TVISIntWin; // Visible transmittance of int win at COSBIntWin for light from ext win
1255 : Real64 TVISIntWinDisk; // Visible transmittance of int win at COSBIntWin for sun
1256 24 : auto &MySunIsUpFlag(state.dataDaylightingManager->CalcDayltgCoeffsMapPointsMySunIsUpFlag);
1257 : int WinEl; // window elements counter
1258 :
1259 24 : auto &W2 = state.dataDaylightingManager->W2;
1260 24 : auto &W3 = state.dataDaylightingManager->W3;
1261 24 : auto &W21 = state.dataDaylightingManager->W21;
1262 24 : auto &W23 = state.dataDaylightingManager->W23;
1263 24 : auto &RREF = state.dataDaylightingManager->RREF;
1264 24 : auto &RREF2 = state.dataDaylightingManager->RREF2;
1265 24 : auto &RWIN = state.dataDaylightingManager->RWIN;
1266 24 : auto &RWIN2 = state.dataDaylightingManager->RWIN2;
1267 24 : auto &Ray = state.dataDaylightingManager->Ray;
1268 24 : auto &WNORM2 = state.dataDaylightingManager->WNORM2;
1269 24 : auto &VIEWVC = state.dataDaylightingManager->VIEWVC;
1270 24 : auto &U2 = state.dataDaylightingManager->U2;
1271 24 : auto &U21 = state.dataDaylightingManager->U21;
1272 24 : auto &U23 = state.dataDaylightingManager->U23;
1273 24 : auto &VIEWVC2 = state.dataDaylightingManager->VIEWVC2;
1274 :
1275 24 : if (state.dataDaylightingManager->mapFirstTime && (int)state.dataDaylightingData->IllumMap.size() > 0) {
1276 5 : IL = -999;
1277 12 : for (int MapNum = 1; MapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++MapNum) {
1278 7 : IL = max(IL, state.dataDaylightingData->IllumMapCalc(MapNum).TotalMapRefPoints);
1279 : }
1280 5 : state.dataDaylightingManager->MapErrIndex.dimension(IL, state.dataSurface->TotSurfaces, 0);
1281 5 : state.dataDaylightingManager->mapFirstTime = false;
1282 : }
1283 :
1284 24 : int enclNum = state.dataDaylightingData->IllumMapCalc(mapNum).enclIndex;
1285 24 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
1286 :
1287 : // Azimuth of view vector in absolute coord sys - set to zero here, because glare isn't calculated for map points
1288 : // but these are arguments to some of the functions that are shared with regular reference points, so initalize here.
1289 24 : AZVIEW = 0.0;
1290 : // View vector components in absolute coord sys
1291 24 : VIEWVC(1) = 0.0;
1292 24 : VIEWVC(2) = 0.0;
1293 24 : VIEWVC(3) = 0.0;
1294 :
1295 24 : numRefPts = state.dataDaylightingData->IllumMapCalc(mapNum).TotalMapRefPoints;
1296 :
1297 24 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPt = 0.0; // Daylight illuminance at reference points (lux)
1298 24 : state.dataDaylightingData->IllumMapCalc(mapNum).IllumFromWinAtMapPt = 0.0;
1299 24 : if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
1300 24 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSky = 0.0;
1301 24 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSun = 0.0;
1302 24 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSunDisk = 0.0;
1303 : } else {
1304 0 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSky(state.dataGlobal->HourOfDay,
1305 0 : {1, state.dataSurface->actualMaxSlatAngs + 1},
1306 : {1, 4},
1307 : {1, numRefPts},
1308 0 : {1, thisEnclDaylight.NumOfDayltgExtWins}) = 0.0;
1309 0 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSun(
1310 0 : state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
1311 0 : 0.0;
1312 0 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSunDisk(
1313 0 : state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, numRefPts}, {1, thisEnclDaylight.NumOfDayltgExtWins}) =
1314 0 : 0.0;
1315 : }
1316 :
1317 2124 : for (IL = 1; IL <= numRefPts; ++IL) {
1318 :
1319 2100 : RREF = state.dataDaylightingData->IllumMapCalc(mapNum).MapRefPtAbsCoord({1, 3}, IL); // (x, y, z)
1320 :
1321 : // -------------
1322 : // ---------- WINDOW LOOP ----------
1323 : // -------------
1324 :
1325 15500 : for (loopwin = 1; loopwin <= thisEnclDaylight.NumOfDayltgExtWins; ++loopwin) {
1326 :
1327 : // daylightingCtrlNum parameter is unused for map points
1328 13400 : FigureDayltgCoeffsAtPointsSetupForWindow(state,
1329 : 0,
1330 : IL,
1331 : loopwin,
1332 : DataDaylighting::CalledFor::MapPoint,
1333 : RREF,
1334 : VIEWVC,
1335 : IWin,
1336 : IWin2,
1337 : NWX,
1338 : NWY,
1339 : W2,
1340 : W3,
1341 : W21,
1342 : W23,
1343 : LSHCAL,
1344 : InShelfSurf,
1345 : ICtrl,
1346 : ShType,
1347 : BlNum,
1348 : WNORM2,
1349 : ExtWinType,
1350 : IConst,
1351 : RREF2,
1352 : DWX,
1353 : DWY,
1354 : DAXY,
1355 : U2,
1356 : U23,
1357 : U21,
1358 : VIEWVC2,
1359 : is_Rectangle,
1360 : is_Triangle,
1361 : mapNum);
1362 : // ---------------------
1363 : // ---------- WINDOW ELEMENT LOOP ----------
1364 : // ---------------------
1365 13400 : WinEl = 0;
1366 :
1367 84320 : for (IX = 1; IX <= NWX; ++IX) {
1368 70920 : if (is_Rectangle) {
1369 70920 : NWYlim = NWY;
1370 0 : } else if (is_Triangle) {
1371 0 : NWYlim = NWY - IX + 1;
1372 : }
1373 :
1374 2230160 : for (IY = 1; IY <= NWYlim; ++IY) {
1375 :
1376 2159240 : ++WinEl;
1377 :
1378 : // daylightingCtrlNum parameter is unused for map points
1379 2159240 : FigureDayltgCoeffsAtPointsForWindowElements(state,
1380 : 0,
1381 : IL,
1382 : loopwin,
1383 : DataDaylighting::CalledFor::MapPoint,
1384 : WinEl,
1385 : IWin,
1386 : IWin2,
1387 : IX,
1388 : IY,
1389 : SkyObstructionMult,
1390 : W2,
1391 : W21,
1392 : W23,
1393 : RREF,
1394 : NWYlim,
1395 : VIEWVC2,
1396 : DWX,
1397 : DWY,
1398 : DAXY,
1399 : U2,
1400 : U23,
1401 : U21,
1402 : RWIN,
1403 : RWIN2,
1404 : Ray,
1405 : PHRAY,
1406 : LSHCAL,
1407 : COSB,
1408 : ObTrans,
1409 : TVISB,
1410 : DOMEGA,
1411 : THRAY,
1412 : hitIntObs,
1413 : hitExtObs,
1414 : WNORM2,
1415 : ExtWinType,
1416 : IConst,
1417 : RREF2,
1418 : is_Triangle,
1419 : TVISIntWin,
1420 : TVISIntWinDisk,
1421 : mapNum);
1422 : // -------------------
1423 : // ---------- SUN POSITION LOOP ----------
1424 : // -------------------
1425 :
1426 : // Sun position counter. Used to avoid calculating various quantities
1427 : // that do not depend on sun position.
1428 2159240 : if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
1429 2159240 : ISunPos = 0;
1430 53981000 : for (IHR = 1; IHR <= 24; ++IHR) {
1431 : // daylightingCtrlNum parameter is unused for map points
1432 51821760 : FigureDayltgCoeffsAtPointsForSunPosition(state,
1433 : 0,
1434 : IL,
1435 : IX,
1436 : NWX,
1437 : IY,
1438 : NWYlim,
1439 : WinEl,
1440 : IWin,
1441 : IWin2,
1442 : IHR,
1443 : ISunPos,
1444 : SkyObstructionMult,
1445 : RWIN2,
1446 : Ray,
1447 : PHRAY,
1448 : LSHCAL,
1449 : InShelfSurf,
1450 : COSB,
1451 : ObTrans,
1452 : TVISB,
1453 : DOMEGA,
1454 : ICtrl,
1455 : ShType,
1456 : BlNum,
1457 : THRAY,
1458 : WNORM2,
1459 : ExtWinType,
1460 : IConst,
1461 : AZVIEW,
1462 : RREF2,
1463 : hitIntObs,
1464 : hitExtObs,
1465 : DataDaylighting::CalledFor::MapPoint,
1466 : TVISIntWin,
1467 : TVISIntWinDisk,
1468 : mapNum);
1469 : } // End of hourly sun position loop, IHR
1470 : } else {
1471 0 : if (state.dataEnvrn->SunIsUp && !MySunIsUpFlag) {
1472 0 : ISunPos = 0;
1473 0 : MySunIsUpFlag = true;
1474 0 : } else if (state.dataEnvrn->SunIsUp && MySunIsUpFlag) {
1475 0 : ISunPos = 1;
1476 0 : } else if (!state.dataEnvrn->SunIsUp && MySunIsUpFlag) {
1477 0 : MySunIsUpFlag = false;
1478 0 : ISunPos = -1;
1479 0 : } else if (!state.dataEnvrn->SunIsUp && !MySunIsUpFlag) {
1480 0 : ISunPos = -1;
1481 : }
1482 : // daylightingCtrlNum parameter is unused for map points
1483 0 : FigureDayltgCoeffsAtPointsForSunPosition(state,
1484 : 0,
1485 : IL,
1486 : IX,
1487 : NWX,
1488 : IY,
1489 : NWYlim,
1490 : WinEl,
1491 : IWin,
1492 : IWin2,
1493 0 : state.dataGlobal->HourOfDay,
1494 : ISunPos,
1495 : SkyObstructionMult,
1496 : RWIN2,
1497 : Ray,
1498 : PHRAY,
1499 : LSHCAL,
1500 : InShelfSurf,
1501 : COSB,
1502 : ObTrans,
1503 : TVISB,
1504 : DOMEGA,
1505 : ICtrl,
1506 : ShType,
1507 : BlNum,
1508 : THRAY,
1509 : WNORM2,
1510 : ExtWinType,
1511 : IConst,
1512 : AZVIEW,
1513 : RREF2,
1514 : hitIntObs,
1515 : hitExtObs,
1516 : DataDaylighting::CalledFor::MapPoint,
1517 : TVISIntWin,
1518 : TVISIntWinDisk,
1519 : mapNum);
1520 : }
1521 : } // End of window Y-element loop, IY
1522 : } // End of window X-element loop, IX
1523 :
1524 13400 : if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
1525 : // Loop again over hourly sun positions and calculate daylight factors by adding
1526 : // direct and inter-reflected illum components, then dividing by exterior horiz illum.
1527 : // Also calculate corresponding glare factors.
1528 13400 : ILB = IL;
1529 335000 : for (IHR = 1; IHR <= 24; ++IHR) {
1530 321600 : FigureMapPointDayltgFactorsToAddIllums(state, mapNum, ILB, IHR, IWin, loopwin, ICtrl);
1531 : } // End of sun position loop, IHR
1532 : } else {
1533 0 : ILB = IL;
1534 0 : FigureMapPointDayltgFactorsToAddIllums(state, mapNum, ILB, state.dataGlobal->HourOfDay, IWin, loopwin, ICtrl);
1535 : }
1536 :
1537 : } // End of window loop, loopwin - IWin
1538 :
1539 : } // End of reference point loop, IL
1540 24 : }
1541 :
1542 28430 : void FigureDayltgCoeffsAtPointsSetupForWindow(
1543 : EnergyPlusData &state,
1544 : int const daylightCtrlNum, // zero if called for map points
1545 : int const iRefPoint,
1546 : int const loopwin,
1547 : DataDaylighting::CalledFor const CalledFrom, // indicate which type of routine called this routine
1548 : Vector3<Real64> const &RREF, // Location of a reference point in absolute coordinate system
1549 : Vector3<Real64> const &VIEWVC, // View vector in absolute coordinate system
1550 : int &IWin,
1551 : int &IWin2,
1552 : int &NWX,
1553 : int &NWY,
1554 : Vector3<Real64> &W2, // Second vertex of window
1555 : Vector3<Real64> &W3, // Third vertex of window
1556 : Vector3<Real64> &W21, // Vector from window vertex 2 to window vertex 1
1557 : Vector3<Real64> &W23, // Vector from window vertex 2 to window vertex 3
1558 : int &LSHCAL, // Interior shade calculation flag: 0=not yet calculated, 1=already calculated
1559 : int &InShelfSurf, // Inside daylighting shelf surface number
1560 : int &ICtrl, // Window control counter
1561 : WinShadingType &ShType, // Window shading type
1562 : int &BlNum, // Window blind number
1563 : Vector3<Real64> &WNORM2, // Unit vector normal to window
1564 : DataDaylighting::ExtWinType &ExtWinType, // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
1565 : int &IConst, // Construction counter
1566 : Vector3<Real64> &RREF2, // Location of virtual reference point in absolute coordinate system
1567 : Real64 &DWX, // Horizontal dimension of window element (m)
1568 : Real64 &DWY, // Vertical dimension of window element (m)
1569 : Real64 &DAXY, // Area of window element
1570 : Vector3<Real64> &U2, // Second vertex of window for TDD:DOME (if exists)
1571 : Vector3<Real64> &U23, // Vector from window vertex 2 to window vertex 3 for TDD:DOME (if exists)
1572 : Vector3<Real64> &U21, // Vector from window vertex 2 to window vertex 1 for TDD:DOME (if exists)
1573 : Vector3<Real64> &VIEWVC2, // Virtual view vector in absolute coordinate system
1574 : bool &is_Rectangle, // True if window is rectangular
1575 : bool &is_Triangle, // True if window is triangular
1576 : int const MapNum)
1577 : {
1578 : // SUBROUTINE INFORMATION:
1579 : // AUTHOR B. Griffith
1580 : // DATE WRITTEN November 2012, refactor from legacy code by Fred Winklemann
1581 :
1582 : // PURPOSE OF THIS SUBROUTINE:
1583 : // collect code to setup calculations for each window for daylighting coefficients
1584 :
1585 : // METHODOLOGY EMPLOYED:
1586 : // switch as need to serve both reference points and map points based on calledFrom
1587 :
1588 : int ShelfNum; // Daylighting shelf object number
1589 : int IConstShaded; // Shaded construction counter
1590 : Real64 WW; // Window width (m)
1591 : Real64 HW; // Window height (m)
1592 :
1593 : int NDIVX; // Number of window x divisions for daylighting calc
1594 : int NDIVY; // Number of window y divisions for daylighting calc
1595 : Real64 ALF; // Distance from reference point to window plane (m)
1596 : Real64 D1a; // Projection of vector from window origin to reference
1597 : // on window X axis (m)
1598 : Real64 D1b; // Projection of vector from window origin to reference
1599 : // on window Y axis (m)
1600 : Real64 SolidAngExtWin; // Approx. solid angle subtended by an ext. window wrt ref pt
1601 : Real64 SolidAngMinIntWin; // Approx. smallest solid angle subtended by an int. window wrt ref pt
1602 : Real64 SolidAngRatio; // Ratio of SolidAngExtWin and SolidAngMinIntWin
1603 : int PipeNum; // TDD pipe object number
1604 : Real64 SinCornerAng; // For triangle, sine of corner angle of window element
1605 :
1606 28430 : int zoneNum = 0; // zone number
1607 28430 : int enclNum = 0; // enclosure number
1608 :
1609 28430 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
1610 15030 : state.dataDaylightingData->daylightControl(daylightCtrlNum).SolidAngAtRefPt(loopwin, iRefPoint) = 0.0;
1611 15030 : state.dataDaylightingData->daylightControl(daylightCtrlNum).SolidAngAtRefPtWtd(loopwin, iRefPoint) = 0.0;
1612 15030 : zoneNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).zoneIndex;
1613 15030 : enclNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).enclIndex;
1614 13400 : } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
1615 13400 : assert(MapNum > 0);
1616 13400 : zoneNum = state.dataDaylightingData->IllumMapCalc(MapNum).zoneIndex;
1617 13400 : enclNum = state.dataDaylightingData->IllumMapCalc(MapNum).enclIndex;
1618 : }
1619 28430 : IWin = state.dataDaylightingData->enclDaylight(enclNum).DayltgExtWinSurfNums(loopwin);
1620 :
1621 28430 : if (state.dataSurface->Surface(state.dataSurface->Surface(IWin).BaseSurf).SolarEnclIndex == enclNum) {
1622 28226 : ExtWinType = DataDaylighting::ExtWinType::InZoneExtWin;
1623 : } else {
1624 204 : ExtWinType = DataDaylighting::ExtWinType::AdjZoneExtWin;
1625 : }
1626 :
1627 28430 : IConst = state.dataSurface->SurfActiveConstruction(IWin);
1628 :
1629 : // For thermochromic windows, the daylight and glare factors are calculated for a base window cosntruction
1630 : // at base TC layer temperature. During each time step calculations at DayltgInteriorIllum,
1631 : // DayltgInteriorMapIllum, and DayltgGlare, the daylight and glare factors are adjusted by the visible
1632 : // transmittance ratio = VT of actual TC window based on last hour TC layer temperature / VT of the base TC window
1633 28430 : if (state.dataConstruction->Construct(IConst).TCFlag == 1) {
1634 : // For thermochromic windows, use the base window construction at base temperature of the TC layer
1635 0 : IConst = state.dataConstruction->Construct(IConst).TCMasterConst;
1636 : }
1637 :
1638 28430 : ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
1639 28430 : ShType = WinShadingType::NoShade; // 'NOSHADE'
1640 28430 : BlNum = 0;
1641 : // ScNum = 0; //Unused Set but never used
1642 28430 : if (state.dataSurface->Surface(IWin).HasShadeControl) ShType = state.dataSurface->WindowShadingControl(ICtrl).ShadingType;
1643 28430 : BlNum = state.dataSurface->SurfWinBlindNumber(IWin);
1644 : // ScNum = SurfaceWindow( IWin ).ScreenNumber; //Unused Set but never used
1645 :
1646 28430 : ShelfNum = state.dataSurface->SurfDaylightingShelfInd(IWin);
1647 28430 : if (ShelfNum > 0) {
1648 420 : InShelfSurf = state.dataDaylightingDevicesData->Shelf(state.dataSurface->SurfDaylightingShelfInd(IWin))
1649 210 : .InSurf; // Inside daylighting shelf present if > 0
1650 : } else {
1651 28220 : InShelfSurf = 0;
1652 : }
1653 :
1654 28430 : is_Rectangle = false;
1655 28430 : is_Triangle = false;
1656 28430 : if (state.dataSurface->Surface(IWin).Sides == 3) is_Triangle = true;
1657 28430 : if (state.dataSurface->Surface(IWin).Sides == 4) is_Rectangle = true;
1658 :
1659 28430 : if (is_Rectangle) {
1660 : // Vertices of window (numbered counter-clockwise starting at upper left as viewed
1661 : // from inside of room). Assumes original vertices are numbered counter-clockwise from
1662 : // upper left as viewed from outside.
1663 28430 : W3 = state.dataSurface->Surface(IWin).Vertex(2);
1664 28430 : W2 = state.dataSurface->Surface(IWin).Vertex(3);
1665 28430 : state.dataDaylightingManager->W1 = state.dataSurface->Surface(IWin).Vertex(4);
1666 0 : } else if (is_Triangle) {
1667 0 : W3 = state.dataSurface->Surface(IWin).Vertex(2);
1668 0 : W2 = state.dataSurface->Surface(IWin).Vertex(3);
1669 0 : state.dataDaylightingManager->W1 = state.dataSurface->Surface(IWin).Vertex(1);
1670 : }
1671 :
1672 : // Shade/blind calculation flag
1673 28430 : LSHCAL = 0;
1674 :
1675 : // Visible transmittance at normal incidence
1676 28430 : state.dataSurface->SurfWinVisTransSelected(IWin) =
1677 28430 : General::POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef) * state.dataSurface->SurfWinGlazedFrac(IWin);
1678 : // For windows with switchable glazing, ratio of visible transmittance at normal
1679 : // incidence for fully switched (dark) state to that of unswitched state
1680 28430 : state.dataSurface->SurfWinVisTransRatio(IWin) = 1.0;
1681 28430 : if (ICtrl > 0) {
1682 12594 : if (ShType == WinShadingType::SwitchableGlazing) {
1683 12562 : IConstShaded = state.dataSurface->Surface(IWin).activeShadedConstruction;
1684 12562 : state.dataSurface->SurfWinVisTransRatio(IWin) =
1685 12562 : General::SafeDivide(General::POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef),
1686 12562 : General::POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef));
1687 : }
1688 : }
1689 :
1690 : // Unit vectors from window vertex 2 to 1 and 2 to 3,
1691 : // center point of window, and vector from ref pt to center of window
1692 28430 : W21 = state.dataDaylightingManager->W1 - W2;
1693 28430 : W23 = W3 - W2;
1694 28430 : HW = W21.magnitude();
1695 28430 : WW = W23.magnitude();
1696 28430 : if (is_Rectangle) {
1697 28430 : state.dataDaylightingManager->WC = W2 + (W23 + W21) / 2.0;
1698 0 : } else if (is_Triangle) {
1699 0 : state.dataDaylightingManager->WC = W2 + (W23 + W21) / 3.0;
1700 : }
1701 28430 : state.dataSurface->SurfaceWindow(IWin).WinCenter = state.dataDaylightingManager->WC;
1702 28430 : state.dataDaylightingManager->REFWC = state.dataDaylightingManager->WC - RREF;
1703 : // Unit vectors
1704 28430 : W21 /= HW;
1705 28430 : W23 /= WW;
1706 :
1707 : // Unit vector normal to window (pointing away from room)
1708 28430 : state.dataDaylightingManager->WNORM = state.dataSurface->Surface(IWin).lcsz;
1709 :
1710 : // Initialize number of window elements
1711 28430 : NDIVX = 40;
1712 28430 : NDIVY = 40;
1713 :
1714 : // Distance from ref point to window plane
1715 28430 : ALF = std::abs(dot(state.dataDaylightingManager->WNORM, state.dataDaylightingManager->REFWC));
1716 28430 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
1717 : // Check if ref point to close to window due to input error (0.1524 m below is 0.5 ft)
1718 15030 : if (ALF < 0.1524 && ExtWinType == DataDaylighting::ExtWinType::InZoneExtWin) {
1719 : // Ref pt is close to window plane. Get vector from window
1720 : // origin to projection of ref pt on window plane.
1721 0 : state.dataDaylightingManager->W2REF = RREF + ALF * state.dataDaylightingManager->WNORM - W2;
1722 :
1723 0 : D1a = dot(state.dataDaylightingManager->W2REF, W23);
1724 0 : D1b = dot(state.dataDaylightingManager->W2REF, W21);
1725 :
1726 : // ! Error message if ref pt is too close to window.
1727 0 : if (D1a > 0.0 && D1b > 0.0 && D1b <= HW && D1a <= WW) {
1728 0 : ShowSevereError(
1729 : state,
1730 0 : format("CalcDaylightCoeffRefPoints: Daylighting calculation cannot be done for Daylighting:Controls={} because reference point "
1731 : "#{} is less than 0.15m (6\") from window plane {}",
1732 0 : state.dataDaylightingData->daylightControl(daylightCtrlNum).Name,
1733 : iRefPoint,
1734 0 : state.dataSurface->Surface(IWin).Name));
1735 0 : ShowContinueError(state, format("Distance=[{:.5R}]. This is too close; check position of reference point.", ALF));
1736 0 : ShowFatalError(state, "Program terminates due to preceding condition.");
1737 : }
1738 15030 : } else if (ALF < 0.1524 && ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) {
1739 0 : if (state.dataDaylightingManager->RefErrIndex(iRefPoint, IWin) == 0) { // only show error message once
1740 0 : ShowWarningError(state,
1741 0 : "CalcDaylightCoeffRefPoints: For Daylghting:Controls=\"" +
1742 0 : state.dataDaylightingData->daylightControl(daylightCtrlNum).Name + "\" External Window=\"" +
1743 0 : state.dataSurface->Surface(IWin).Name + "\"in Zone=\"" +
1744 0 : state.dataHeatBal->Zone(state.dataSurface->Surface(IWin).Zone).Name +
1745 : "\" reference point is less than 0.15m (6\") from window plane ");
1746 0 : ShowContinueError(state,
1747 0 : format("Distance=[{:.1R} m] to ref point=[{:.1R},{:.1R},{:.1R}], Inaccuracy in Daylighting Calcs may result.",
1748 : ALF,
1749 0 : RREF(1),
1750 0 : RREF(2),
1751 0 : RREF(3)));
1752 0 : state.dataDaylightingManager->RefErrIndex(iRefPoint, IWin) = 1;
1753 : }
1754 : }
1755 13400 : } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
1756 13400 : if (ALF < 0.1524 && ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) {
1757 0 : if (state.dataDaylightingManager->MapErrIndex(iRefPoint, IWin) == 0) { // only show error message once
1758 0 : ShowWarningError(state,
1759 0 : "CalcDaylightCoeffMapPoints: For Zone=\"" + state.dataHeatBal->Zone(zoneNum).Name + "\" External Window=\"" +
1760 0 : state.dataSurface->Surface(IWin).Name + "\"in Zone=\"" +
1761 0 : state.dataHeatBal->Zone(state.dataSurface->Surface(IWin).Zone).Name +
1762 : "\" map point is less than 0.15m (6\") from window plane ");
1763 0 : ShowContinueError(
1764 : state,
1765 0 : format(
1766 0 : "Distance=[{:.1R} m] map point=[{:.1R},{:.1R},{:.1R}], Inaccuracy in Map Calcs may result.", ALF, RREF(1), RREF(2), RREF(3)));
1767 0 : state.dataDaylightingManager->MapErrIndex(iRefPoint, IWin) = 1;
1768 : }
1769 : }
1770 : }
1771 : // Number of window elements in X and Y for daylighting calculation
1772 28430 : if (ALF > 0.1524) {
1773 27150 : NDIVX = 1 + int(4.0 * WW / ALF);
1774 27150 : NDIVY = 1 + int(4.0 * HW / ALF);
1775 : }
1776 :
1777 28430 : if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) {
1778 : // Adjust number of exterior window elements to give acceptable number of rays through
1779 : // interior windows in the zone (for accuracy of interior window daylighting calculation)
1780 408 : SolidAngExtWin = General::SafeDivide(
1781 204 : ((state.dataSurface->Surface(IWin).Area + state.dataSurface->SurfWinDividerArea(IWin)) / state.dataSurface->Surface(IWin).Multiplier),
1782 : pow_2(ALF));
1783 204 : SolidAngMinIntWin = state.dataDaylightingData->enclDaylight(enclNum).MinIntWinSolidAng;
1784 204 : SolidAngRatio = max(1.0, SolidAngExtWin / SolidAngMinIntWin);
1785 204 : NDIVX *= std::sqrt(SolidAngRatio);
1786 204 : NDIVY *= std::sqrt(SolidAngRatio);
1787 : }
1788 :
1789 28430 : NWX = min(40, NDIVX);
1790 28430 : NWY = min(40, NDIVY);
1791 :
1792 : // Discretization of triangle is simpler if NWX = NWY
1793 28430 : if (is_Triangle) {
1794 0 : NWX = max(NWX, NWY);
1795 0 : NWY = NWX;
1796 : }
1797 :
1798 : // Edge lengths of window elements
1799 28430 : DWX = WW / NWX;
1800 28430 : DWY = HW / NWY;
1801 :
1802 : // Azimuth and altitude of window normal
1803 28430 : state.dataSurface->SurfWinPhi(IWin) = std::asin(state.dataDaylightingManager->WNORM(3));
1804 28430 : if (std::abs(state.dataDaylightingManager->WNORM(1)) > 1.0e-5 || std::abs(state.dataDaylightingManager->WNORM(2)) > 1.0e-5) {
1805 22486 : state.dataSurface->SurfWinTheta(IWin) = std::atan2(state.dataDaylightingManager->WNORM(2), state.dataDaylightingManager->WNORM(1));
1806 : } else {
1807 5944 : state.dataSurface->SurfWinTheta(IWin) = 0.0;
1808 : }
1809 :
1810 : // Recalculation of values for TDD:DOME
1811 28430 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Diffuser) {
1812 :
1813 : // Look up the TDD:DOME object
1814 420 : PipeNum = state.dataSurface->SurfWinTDDPipeNum(IWin);
1815 420 : IWin2 = state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome;
1816 :
1817 : // Calculate reference point coords relative to the diffuser coordinate system
1818 : // W21, W23, and WNORM are the unit vectors
1819 420 : state.dataDaylightingManager->REFD(1) = dot(state.dataDaylightingManager->REFWC, W21);
1820 420 : state.dataDaylightingManager->REFD(2) = dot(state.dataDaylightingManager->REFWC, W23);
1821 420 : state.dataDaylightingManager->REFD(3) = dot(state.dataDaylightingManager->REFWC, state.dataDaylightingManager->WNORM);
1822 :
1823 : // Calculate view vector coords relative to the diffuser coordinate system
1824 420 : state.dataDaylightingManager->VIEWVD(1) = dot(VIEWVC, W21);
1825 420 : state.dataDaylightingManager->VIEWVD(2) = dot(VIEWVC, W23);
1826 420 : state.dataDaylightingManager->VIEWVD(3) = dot(VIEWVC, state.dataDaylightingManager->WNORM);
1827 :
1828 420 : state.dataDaylightingManager->U3 = state.dataSurface->Surface(IWin2).Vertex(2);
1829 420 : U2 = state.dataSurface->Surface(IWin2).Vertex(3);
1830 :
1831 420 : if (state.dataSurface->Surface(IWin2).Sides == 4) {
1832 : // Vertices of window (numbered counter-clockwise starting
1833 : // at upper left as viewed from inside of room)
1834 : // Assumes original vertices are numbered counter-clockwise from
1835 : // upper left as viewed from outside.
1836 420 : state.dataDaylightingManager->U3 = state.dataSurface->Surface(IWin2).Vertex(2);
1837 420 : U2 = state.dataSurface->Surface(IWin2).Vertex(3);
1838 420 : state.dataDaylightingManager->U1 = state.dataSurface->Surface(IWin2).Vertex(4);
1839 0 : } else if (state.dataSurface->Surface(IWin2).Sides == 3) {
1840 0 : state.dataDaylightingManager->U3 = state.dataSurface->Surface(IWin2).Vertex(2);
1841 0 : U2 = state.dataSurface->Surface(IWin2).Vertex(3);
1842 0 : state.dataDaylightingManager->U1 = state.dataSurface->Surface(IWin2).Vertex(1);
1843 : }
1844 :
1845 : // Unit vectors from window vertex 2 to 1 and 2 to 3,
1846 : // center point of window, and vector from ref pt to center of window
1847 420 : U21 = state.dataDaylightingManager->U1 - U2;
1848 420 : U23 = state.dataDaylightingManager->U3 - U2;
1849 420 : HW = U21.magnitude();
1850 420 : WW = U23.magnitude();
1851 420 : if (state.dataSurface->Surface(IWin2).Sides == 4) {
1852 420 : state.dataDaylightingManager->WC = U2 + (U23 + U21) / 2.0;
1853 0 : } else if (state.dataSurface->Surface(IWin2).Sides == 3) {
1854 0 : state.dataDaylightingManager->WC = U2 + (U23 + U21) / 3.0;
1855 : }
1856 420 : state.dataSurface->SurfaceWindow(IWin2).WinCenter = state.dataDaylightingManager->WC;
1857 : // Unit vectors
1858 420 : U21 /= HW;
1859 420 : U23 /= WW;
1860 :
1861 : // Unit vector normal to dome (pointing away from TDD)
1862 : // These are specific to the exterior.
1863 : // NOTE: Preserve WNORM for later in the code.
1864 420 : WNORM2 = cross(U21, U23).normalize();
1865 :
1866 : // Azimuth and altitude of dome normal
1867 : // These are specific to the exterior.
1868 420 : state.dataSurface->SurfWinPhi(IWin2) = std::asin(WNORM2(3));
1869 420 : if (std::abs(WNORM2(1)) > 1.0e-5 || std::abs(WNORM2(2)) > 1.0e-5) {
1870 420 : state.dataSurface->SurfWinTheta(IWin2) = std::atan2(WNORM2(2), WNORM2(1));
1871 : } else {
1872 0 : state.dataSurface->SurfWinTheta(IWin2) = 0.0;
1873 : }
1874 :
1875 : // Calculate new virtual reference point coords relative to dome coord system
1876 : // W21, W23, and WNORM2 are now the unit vectors for the dome coord system
1877 840 : state.dataDaylightingManager->REFWC = state.dataDaylightingManager->REFD(1) * U21 + state.dataDaylightingManager->REFD(2) * U23 +
1878 1260 : state.dataDaylightingManager->REFD(3) * WNORM2;
1879 420 : RREF2 = state.dataDaylightingManager->WC - state.dataDaylightingManager->REFWC;
1880 :
1881 : // Calculate new virtual view vector coords relative to dome coord system
1882 420 : VIEWVC2 = state.dataDaylightingManager->VIEWVD(1) * U21 + state.dataDaylightingManager->VIEWVD(2) * U23 +
1883 840 : state.dataDaylightingManager->VIEWVD(3) * WNORM2;
1884 :
1885 : // Copy several values from the diffuser so that DayltgInterReflectedIllum works correctly
1886 : // These are specific to the interior.
1887 420 : state.dataSurface->SurfWinRhoCeilingWall(IWin2) = state.dataSurface->SurfWinRhoCeilingWall(IWin);
1888 420 : state.dataSurface->SurfWinRhoFloorWall(IWin2) = state.dataSurface->SurfWinRhoFloorWall(IWin);
1889 420 : state.dataSurface->SurfWinFractionUpgoing(IWin2) = state.dataSurface->SurfWinFractionUpgoing(IWin);
1890 420 : state.dataSurface->SurfWinGlazedFrac(IWin2) = state.dataSurface->SurfWinGlazedFrac(IWin);
1891 :
1892 : } else {
1893 : // This is not a TDD:DIFFUSER. Make sure nothing is messed up for a regular window.
1894 28010 : IWin2 = IWin;
1895 28010 : WNORM2 = state.dataDaylightingManager->WNORM;
1896 28010 : RREF2 = RREF;
1897 28010 : VIEWVC2 = VIEWVC;
1898 :
1899 28010 : U2 = W2;
1900 28010 : U21 = W21;
1901 28010 : U23 = W23;
1902 : }
1903 :
1904 : // Initialize bsdf daylighting coefficients here. Only one time initialization
1905 28430 : if (state.dataSurface->SurfWinWindowModelType(IWin) == WindowModel::BSDF) {
1906 18 : if (!state.dataBSDFWindow->ComplexWind(IWin).DaylightingInitialized) {
1907 18 : int NRefPts = 0;
1908 18 : if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
1909 0 : NRefPts = state.dataDaylightingData->IllumMapCalc(MapNum).TotalMapRefPoints;
1910 18 : } else if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
1911 18 : NRefPts = state.dataDaylightingData->daylightControl(daylightCtrlNum).TotalDaylRefPoints;
1912 : }
1913 18 : InitializeCFSDaylighting(state, daylightCtrlNum, IWin, NWX, NWY, RREF, NRefPts, iRefPoint, CalledFrom, MapNum);
1914 : // if ((WinEl == (NWX * NWY)).and.(CalledFrom == CalledForMapPoint).and.(NRefPts == iRefPoint)) then
1915 18 : if ((CalledFrom == DataDaylighting::CalledFor::MapPoint) && (NRefPts == iRefPoint)) {
1916 0 : state.dataBSDFWindow->ComplexWind(IWin).DaylightingInitialized = true;
1917 : }
1918 : }
1919 : }
1920 :
1921 28430 : if (!state.dataSysVars->DetailedSolarTimestepIntegration) {
1922 : // Initialize sky and sun components of direct illuminance (arrays EDIRSK, EDIRSU, EDIRSUdisk)
1923 : // and average window luminance (arrays AVWLSK, AVWLSU, AVWLSUdisk), at ref pt.
1924 28430 : state.dataDaylightingManager->EDIRSK = 0.0;
1925 28430 : state.dataDaylightingManager->EDIRSU = 0.0;
1926 28430 : state.dataDaylightingManager->EDIRSUdisk = 0.0;
1927 28430 : state.dataDaylightingManager->AVWLSK = 0.0;
1928 28430 : state.dataDaylightingManager->AVWLSU = 0.0;
1929 28430 : state.dataDaylightingManager->AVWLSUdisk = 0.0;
1930 : } else {
1931 0 : state.dataDaylightingManager->EDIRSK(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, 4}) = 0.0;
1932 0 : state.dataDaylightingManager->EDIRSU(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}) = 0.0;
1933 0 : state.dataDaylightingManager->EDIRSUdisk(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}) = 0.0;
1934 0 : state.dataDaylightingManager->AVWLSK(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}, {1, 4}) = 0.0;
1935 0 : state.dataDaylightingManager->AVWLSU(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}) = 0.0;
1936 0 : state.dataDaylightingManager->AVWLSUdisk(state.dataGlobal->HourOfDay, {1, state.dataSurface->actualMaxSlatAngs + 1}) = 0.0;
1937 : }
1938 28430 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
1939 : // Initialize solid angle subtended by window wrt ref pt
1940 : // and solid angle weighted by glare position factor
1941 15030 : state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPt(iRefPoint) = 0.0;
1942 15030 : state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint) = 0.0;
1943 : }
1944 : // Area of window element
1945 28430 : if (is_Rectangle) {
1946 28430 : DAXY = DWX * DWY;
1947 0 : } else if (is_Triangle) {
1948 0 : SinCornerAng = std::sqrt(1.0 - pow_2(dot(W21, W23)));
1949 0 : DAXY = DWX * DWY * SinCornerAng;
1950 : }
1951 28430 : }
1952 :
1953 2737944 : void FigureDayltgCoeffsAtPointsForWindowElements(
1954 : EnergyPlusData &state,
1955 : int const daylightCtrlNum, // Current daylighting control number (only used when called from RefPoint)
1956 : int const iRefPoint,
1957 : int const loopwin,
1958 : DataDaylighting::CalledFor const CalledFrom, // indicate which type of routine called this routine
1959 : int const WinEl, // Current window element number
1960 : int const IWin,
1961 : int const IWin2,
1962 : int const iXelement,
1963 : int const iYelement,
1964 : Real64 &SkyObstructionMult,
1965 : Vector3<Real64> const &W2, // Second vertex of window
1966 : Vector3<Real64> const &W21, // Vector from window vertex 2 to window vertex 1
1967 : Vector3<Real64> const &W23, // Vector from window vertex 2 to window vertex 3
1968 : Vector3<Real64> const &RREF, // Location of a reference point in absolute coordinate system
1969 : int const NWYlim, // For triangle, largest NWY for a given IX
1970 : Vector3<Real64> const &VIEWVC2, // Virtual view vector in absolute coordinate system
1971 : Real64 const DWX, // Horizontal dimension of window element (m)
1972 : Real64 const DWY, // Vertical dimension of window element (m)
1973 : Real64 const DAXY, // Area of window element
1974 : Vector3<Real64> const &U2, // Second vertex of window for TDD:DOME (if exists)
1975 : Vector3<Real64> const &U23, // Vector from window vertex 2 to window vertex 3 for TDD:DOME (if exists)
1976 : Vector3<Real64> const &U21, // Vector from window vertex 2 to window vertex 1 for TDD:DOME (if exists)
1977 : Vector3<Real64> &RWIN, // Center of a window element for TDD:DOME (if exists) in abs coord sys
1978 : Vector3<Real64> &RWIN2, // Center of a window element for TDD:DOME (if exists) in abs coord sys
1979 : Vector3<Real64> &Ray, // Unit vector along ray from reference point to window element
1980 : Real64 &PHRAY, // Altitude of ray from reference point to window element (radians)
1981 : int &LSHCAL, // Interior shade calculation flag: 0=not yet calculated, 1=already calculated
1982 : Real64 &COSB, // Cosine of angle between window outward normal and ray from reference point to window element
1983 : Real64 &ObTrans, // Product of solar transmittances of exterior obstructions hit by ray
1984 : Real64 &TVISB, // Visible transmittance of window for COSB angle of incidence (times light well
1985 : Real64 &DOMEGA, // Solid angle subtended by window element wrt reference point (steradians)
1986 : Real64 &THRAY, // Azimuth of ray from reference point to window element (radians)
1987 : bool &hitIntObs, // True iff interior obstruction hit
1988 : bool &hitExtObs, // True iff ray from ref pt to ext win hits an exterior obstruction
1989 : Vector3<Real64> const &WNORM2, // Unit vector normal to window
1990 : DataDaylighting::ExtWinType const ExtWinType, // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
1991 : int const IConst, // Construction counter
1992 : Vector3<Real64> const &RREF2, // Location of virtual reference point in absolute coordinate system
1993 : bool const is_Triangle,
1994 : Real64 &TVISIntWin, // Visible transmittance of int win at COSBIntWin for light from ext win
1995 : Real64 &TVISIntWinDisk, // Visible transmittance of int win at COSBIntWin for sun
1996 : int const MapNum)
1997 : {
1998 :
1999 : // SUBROUTINE INFORMATION:
2000 : // AUTHOR B. Griffith
2001 : // DATE WRITTEN November 2012, refactor from legacy code by Fred Winklemann
2002 :
2003 : // PURPOSE OF THIS SUBROUTINE:
2004 : // collect code to do calculations for each window element for daylighting coefficients
2005 :
2006 : // REFERENCES:
2007 : // switch as need to serve both reference points and map points based on calledFrom
2008 :
2009 : Real64 DIS; // Distance between reference point and center of window element (m)
2010 : Real64 DAXY1; // For triangle, area of window element at end of column
2011 : Real64 POSFAC; // Position factor for a window element / ref point / view vector combination
2012 : Real64 RR; // Distance from ref point to intersection of view vector
2013 : // and plane normal to view vector and window element (m)
2014 : Real64 ASQ; // Square of distance from above intersection to window element (m2)
2015 : Real64 YD; // Vertical displacement of window element wrt ref point
2016 : Real64 XR; // Horizontal displacement ratio
2017 : Real64 YR; // Vertical displacement ratio
2018 :
2019 : int IntWinHitNum; // Surface number of interior window that is intersected
2020 : bool hitIntWin; // Ray from ref pt passes through interior window
2021 : int PipeNum; // TDD pipe object number
2022 : Real64 COSBIntWin; // Cos of angle between int win outward normal and ray betw ref pt and
2023 : // exterior window element or between ref pt and sun
2024 :
2025 : Real64 Alfa; // Intermediate variable
2026 : Real64 Beta; // Intermediate variable
2027 : Real64 HorDis; // Distance between ground hit point and proj'n of center
2028 : // of window element onto ground (m)
2029 :
2030 : // Local complex fenestration variables
2031 : int CplxFenState; // Current complex fenestration state
2032 2737944 : int NReflSurf = 0; // Number of blocked beams for complex fenestration
2033 : int ICplxFen; // Complex fenestration counter
2034 : int RayIndex;
2035 : Real64 TransBeam; // Obstructions transmittance for incoming BSDF rays (temporary variable)
2036 :
2037 2737944 : ++LSHCAL;
2038 2737944 : SkyObstructionMult = 1.0;
2039 :
2040 : // Center of win element in absolute coord sys
2041 2737944 : RWIN = W2 + (double(iXelement) - 0.5) * W23 * DWX + (double(iYelement) - 0.5) * W21 * DWY;
2042 :
2043 : // Center of win element on TDD:DOME in absolute coord sys
2044 : // If no TDD, RWIN2 = RWIN
2045 2737944 : RWIN2 = U2 + (double(iXelement) - 0.5) * U23 * DWX + (double(iYelement) - 0.5) * U21 * DWY;
2046 :
2047 : // Distance between ref pt and window element
2048 2737944 : DIS = distance(RWIN, RREF);
2049 :
2050 : // Unit vector along ray from ref pt to element
2051 2737944 : Ray = (RWIN - RREF) / DIS;
2052 :
2053 : // Cosine of angle between ray and window outward normal
2054 2737944 : COSB = dot(WNORM2, Ray);
2055 :
2056 : // If COSB > 0, direct light from window can reach ref pt. Otherwise go to loop
2057 : // over sun position and calculate inter-reflected component of illuminance
2058 2737944 : if (COSB > 0.0) {
2059 : // Azimuth (-pi to pi) and altitude (-pi/2 to pi/2) of ray. Azimuth = 0 is along east.
2060 2737944 : PHRAY = std::asin(Ray(3));
2061 2737944 : if (std::abs(Ray(1)) > 1.0e-5 || std::abs(Ray(2)) > 1.0e-5) {
2062 2737939 : THRAY = std::atan2(Ray(2), Ray(1));
2063 : } else {
2064 5 : THRAY = 0.0;
2065 : }
2066 :
2067 : // Solid angle subtended by element wrt ref pt.
2068 2737944 : DAXY1 = DAXY;
2069 : // For triangle, at end of Y column only one half of parallelopiped's area contributes
2070 2737944 : if (is_Triangle && iYelement == NWYlim) DAXY1 = 0.5 * DAXY;
2071 2737944 : DOMEGA = DAXY1 * COSB / (DIS * DIS);
2072 :
2073 : // Calculate position factor (used in glare calculation) for this
2074 : // win element / ref pt / view-vector combination
2075 2737944 : POSFAC = 0.0;
2076 :
2077 : // Distance from ref pt to intersection of view vector and plane
2078 : // normal to view vector containing the window element
2079 :
2080 2737944 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
2081 578704 : RR = DIS * dot(Ray, VIEWVC2);
2082 578704 : if (RR > 0.0) {
2083 : // Square of distance from above intersection point to win element
2084 527227 : ASQ = DIS * DIS - RR * RR;
2085 : // Vertical displacement of win element wrt ref pt
2086 527227 : YD = RWIN2(3) - RREF2(3);
2087 : // Horizontal and vertical displacement ratio and position factor
2088 527227 : XR = std::sqrt(std::abs(ASQ - YD * YD)) / RR;
2089 527227 : YR = std::abs(YD / RR);
2090 527227 : POSFAC = DayltgGlarePositionFactor(XR, YR);
2091 : }
2092 : }
2093 :
2094 2737944 : hitIntObs = false;
2095 2737944 : IntWinHitNum = 0;
2096 2737944 : hitIntWin = false;
2097 2737944 : TVISIntWinDisk = 0.0; // Init Value
2098 2737944 : TVISIntWin = 0.0;
2099 :
2100 2737944 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Diffuser) {
2101 : // Look up the TDD:DOME object
2102 420 : PipeNum = state.dataSurface->SurfWinTDDPipeNum(IWin);
2103 : // Unshaded visible transmittance of TDD for a single ray from sky/ground element
2104 840 : TVISB = DaylightingDevices::TransTDD(state, PipeNum, COSB, DataDaylightingDevices::RadType::VisibleBeam) *
2105 420 : state.dataSurface->SurfWinGlazedFrac(IWin);
2106 :
2107 : } else { // Regular window
2108 2737524 : if (state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF) {
2109 : // Vis trans of glass for COSB incidence angle
2110 8212140 : TVISB = General::POLYF(COSB, state.dataConstruction->Construct(IConst).TransVisBeamCoef) *
2111 5474760 : state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
2112 : } else {
2113 : // Complex fenestration needs to use different equation for visible transmittance. That will be calculated later
2114 : // in the code since it depends on different incoming directions. For now, just put zero to differentiate from
2115 : // regular windows
2116 144 : TVISB = 0.0;
2117 : }
2118 2737524 : if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) {
2119 23680 : int zoneNum = 0;
2120 23680 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
2121 40 : zoneNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).zoneIndex;
2122 23640 : } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
2123 23640 : assert(MapNum > 0);
2124 23640 : zoneNum = state.dataDaylightingData->IllumMapCalc(MapNum).zoneIndex;
2125 : }
2126 : // Does ray pass through an interior window in zone (ZoneNum) containing the ref point?
2127 47360 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
2128 23680 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
2129 26948 : for (int IntWin = thisSpace.WindowSurfaceFirst; IntWin <= thisSpace.WindowSurfaceLast; ++IntWin) {
2130 23680 : if (state.dataSurface->Surface(IntWin).ExtBoundCond >=
2131 : 1) { // in develop this was Surface(IntWin).Class == SurfaceClass::Window && Surface(IntWin).ExtBoundCond >= 1
2132 47360 : if (state.dataSurface->Surface(state.dataSurface->Surface(IntWin).ExtBoundCond).Zone ==
2133 23680 : state.dataSurface->Surface(IWin).Zone) {
2134 23680 : PierceSurface(state, IntWin, RREF, Ray, state.dataDaylightingManager->HitPtIntWin, hitIntWin);
2135 23680 : if (hitIntWin) {
2136 20412 : IntWinHitNum = IntWin;
2137 20412 : COSBIntWin = dot(state.dataSurface->Surface(IntWin).OutNormVec, Ray);
2138 20412 : if (COSBIntWin <= 0.0) {
2139 0 : hitIntWin = false;
2140 0 : IntWinHitNum = 0;
2141 0 : continue;
2142 : }
2143 20412 : TVISIntWin = General::POLYF(
2144 : COSBIntWin,
2145 20412 : state.dataConstruction->Construct(state.dataSurface->Surface(IntWin).Construction).TransVisBeamCoef);
2146 20412 : TVISB *= TVISIntWin;
2147 20412 : break; // Ray passes thru interior window; exit from DO loop
2148 : }
2149 : }
2150 : }
2151 : }
2152 : } // End of loop over surfaces in zone ZoneNum
2153 :
2154 23680 : if (!hitIntWin) {
2155 : // Ray does not pass through an int win in ZoneNum. Therefore, it hits the opaque part
2156 : // of a surface between ref point in ZoneNum and ext win element in adjacent zone.
2157 3268 : hitIntObs = true;
2158 : }
2159 : } // End of check if this is an ext win in an adjacent zone
2160 : } // End of check if TDD:Diffuser or regular exterior window or complex fenestration
2161 :
2162 : // Check for interior obstructions
2163 2737944 : if (ExtWinType == DataDaylighting::ExtWinType::InZoneExtWin && !hitIntObs) {
2164 : // Check for obstruction between reference point and window element
2165 : // Returns hitIntObs = true iff obstruction is hit
2166 : // (Example of interior obstruction is a wall in an L-shaped room that lies
2167 : // between reference point and window.)
2168 2714264 : DayltgHitInteriorObstruction(state, IWin, RREF, RWIN, hitIntObs);
2169 : }
2170 :
2171 2737944 : if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin && IntWinHitNum > 0 && !hitIntObs) {
2172 : // Check for obstruction between ref point and interior window through which ray passes
2173 20412 : DayltgHitInteriorObstruction(state, IntWinHitNum, RREF, state.dataDaylightingManager->HitPtIntWin, hitIntObs);
2174 20412 : if (!hitIntObs) {
2175 : // Check for obstruction between intersection point on int window and ext win element
2176 20412 : DayltgHitBetWinObstruction(state, IntWinHitNum, IWin, state.dataDaylightingManager->HitPtIntWin, RWIN, hitIntObs);
2177 : }
2178 : }
2179 2737944 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
2180 : // Glare calculations only done for regular reference points, not for maps
2181 578704 : if (!hitIntObs) {
2182 578634 : if (ExtWinType == DataDaylighting::ExtWinType::InZoneExtWin ||
2183 40 : (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin && hitIntWin)) {
2184 : // Increment solid angle subtended by portion of window above ref pt
2185 578634 : state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPt(iRefPoint) += DOMEGA;
2186 578634 : state.dataDaylightingData->daylightControl(daylightCtrlNum).SolidAngAtRefPt(loopwin, iRefPoint) += DOMEGA;
2187 : // Increment position-factor-modified solid angle
2188 578634 : state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint) += DOMEGA * POSFAC;
2189 578634 : state.dataDaylightingData->daylightControl(daylightCtrlNum).SolidAngAtRefPtWtd(loopwin, iRefPoint) += DOMEGA * POSFAC;
2190 : }
2191 : }
2192 : }
2193 2737944 : if (hitIntObs) ObTrans = 0.0;
2194 :
2195 2737944 : hitExtObs = false;
2196 2737944 : if (!hitIntObs) {
2197 : // No interior obstruction was hit.
2198 : // Check for exterior obstructions between window element and sky/ground.
2199 : // Get product of transmittances of obstructions hit by ray.
2200 : // ObTrans = 1.0 will be returned if no exterior obstructions are hit.
2201 :
2202 2703358 : if (state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF) {
2203 : // the IHR (now HourOfDay) here is/was not correct, this is outside of hour loop
2204 : // the hour is used to query schedule for transmission , not sure what to do
2205 : // it will work for detailed and never did work correctly before.
2206 2703214 : DayltgHitObstruction(state, state.dataGlobal->HourOfDay, IWin2, RWIN2, Ray, ObTrans);
2207 2703214 : if (ObTrans < 1.0) hitExtObs = true;
2208 : } else {
2209 : // Transmittance from exterior obstruction surfaces is calculated here. This needs to be done for each timestep
2210 : // in order to account for changes in exterior surface transmittances
2211 144 : CplxFenState = state.dataSurface->SurfaceWindow(IWin).ComplexFen.CurrentState;
2212 144 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
2213 144 : NReflSurf = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CplxFenState).RefPoint(iRefPoint).NReflSurf(WinEl);
2214 0 : } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
2215 0 : NReflSurf = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CplxFenState).IlluminanceMap(iRefPoint, MapNum).NReflSurf(WinEl);
2216 : }
2217 144 : for (ICplxFen = 1; ICplxFen <= NReflSurf; ++ICplxFen) {
2218 0 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
2219 0 : RayIndex =
2220 0 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CplxFenState).RefPoint(iRefPoint).RefSurfIndex(ICplxFen, WinEl);
2221 0 : } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
2222 0 : RayIndex = state.dataBSDFWindow->ComplexWind(IWin)
2223 0 : .DaylghtGeom(CplxFenState)
2224 0 : .IlluminanceMap(iRefPoint, MapNum)
2225 0 : .RefSurfIndex(ICplxFen, WinEl);
2226 : }
2227 0 : state.dataDaylightingManager->RayVector = state.dataBSDFWindow->ComplexWind(IWin).Geom(CplxFenState).sInc(RayIndex);
2228 : // It will get product of all transmittances
2229 0 : DayltgHitObstruction(state, state.dataGlobal->HourOfDay, IWin, RWIN, state.dataDaylightingManager->RayVector, TransBeam);
2230 : // IF (TransBeam > 0.0d0) ObTrans = TransBeam
2231 0 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
2232 0 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CplxFenState).RefPoint(iRefPoint).TransOutSurf(ICplxFen, WinEl) =
2233 : TransBeam;
2234 0 : } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
2235 0 : state.dataBSDFWindow->ComplexWind(IWin)
2236 0 : .DaylghtGeom(CplxFenState)
2237 0 : .IlluminanceMap(iRefPoint, MapNum)
2238 0 : .TransOutSurf(ICplxFen, WinEl) = TransBeam;
2239 : }
2240 : }
2241 : // This will avoid obstruction multiplier calculations for non-CFS window
2242 144 : ObTrans = 0.0;
2243 : }
2244 : }
2245 :
2246 2737944 : if (state.dataSurface->CalcSolRefl && PHRAY < 0.0 && ObTrans > 1.0e-6) {
2247 : // Calculate effect of obstructions on shading of sky diffuse reaching the ground point hit
2248 : // by the ray. This effect is given by the ratio SkyObstructionMult =
2249 : // (obstructed sky diffuse at ground point)/(unobstructed sky diffuse at ground point).
2250 : // This ratio is calculated for an isotropic sky.
2251 : // Ground point hit by the ray:
2252 50 : Alfa = std::acos(-Ray(3));
2253 50 : Beta = std::atan2(Ray(2), Ray(1));
2254 50 : HorDis = (RWIN2(3) - state.dataSurface->GroundLevelZ) * std::tan(Alfa);
2255 50 : state.dataDaylightingManager->GroundHitPt(3) = state.dataSurface->GroundLevelZ;
2256 50 : state.dataDaylightingManager->GroundHitPt(1) = RWIN2(1) + HorDis * std::cos(Beta);
2257 50 : state.dataDaylightingManager->GroundHitPt(2) = RWIN2(2) + HorDis * std::sin(Beta);
2258 :
2259 50 : SkyObstructionMult =
2260 50 : CalcObstrMultiplier(state, state.dataDaylightingManager->GroundHitPt, AltAngStepsForSolReflCalc, AzimAngStepsForSolReflCalc);
2261 : } // End of check if solar reflection calculation is in effect
2262 :
2263 : } // End of check if COSB > 0
2264 2737944 : }
2265 :
2266 18 : void InitializeCFSDaylighting(EnergyPlusData &state,
2267 : int const daylightCtrlNum, // Current daylighting control number
2268 : int const IWin, // Complex fenestration number
2269 : int const NWX, // Number of horizontal divisions
2270 : int const NWY, // Number of vertical divisions
2271 : Vector3<Real64> const &RefPoint, // reference point coordinates
2272 : int const NRefPts, // Number of reference points
2273 : int const iRefPoint, // Reference points counter
2274 : DataDaylighting::CalledFor const CalledFrom,
2275 : int const MapNum)
2276 : {
2277 : // SUBROUTINE INFORMATION:
2278 : // AUTHOR Simon Vidanovic
2279 : // DATE WRITTEN April 2013
2280 : // MODIFIED na
2281 : // RE-ENGINEERED na
2282 :
2283 : // PURPOSE OF THIS SUBROUTINE:
2284 : // For incoming BSDF window direction calculates whether bin is coming from sky, ground or reflected surface.
2285 : // Routine also calculates intersection points with ground and exterior reflection surfaces.
2286 :
2287 : int NumOfWinEl; // Number of window elements
2288 : int CurFenState; // Current fenestration state
2289 :
2290 : Real64 DWX; // Window element width
2291 : Real64 DWY; // Window element height
2292 : Real64 WinElArea; // Window element area
2293 :
2294 18 : auto &W1 = state.dataDaylightingManager->W1;
2295 18 : auto &W2 = state.dataDaylightingManager->W2;
2296 18 : auto &W3 = state.dataDaylightingManager->W3;
2297 18 : auto &W21 = state.dataDaylightingManager->W21;
2298 18 : auto &W23 = state.dataDaylightingManager->W23;
2299 18 : auto &WNorm = state.dataDaylightingManager->WNorm; // unit vector from window (point towards outside)
2300 :
2301 : int NBasis; // number of incident basis directions for current state
2302 : int NTrnBasis; // number of outgoing basis directions for current state
2303 :
2304 : // reference point variables
2305 :
2306 : // Position factor variables
2307 : Real64 AZVIEW; // Azimuth of view vector
2308 :
2309 : // Object Data
2310 18 : DataBSDFWindow::BSDFDaylghtPosition elPos; // altitude and azimuth of intersection element
2311 36 : Vector Vec; // temporary vector variable
2312 :
2313 18 : NumOfWinEl = NWX * NWY;
2314 :
2315 18 : DWX = state.dataSurface->Surface(IWin).Width / NWX;
2316 18 : DWY = state.dataSurface->Surface(IWin).Height / NWY;
2317 :
2318 18 : int zoneNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).zoneIndex;
2319 54 : AZVIEW = (state.dataDaylightingData->daylightControl(daylightCtrlNum).ViewAzimuthForGlare + state.dataHeatBal->Zone(zoneNum).RelNorth +
2320 36 : state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) *
2321 : DataGlobalConstants::DegToRadians;
2322 :
2323 : // Perform necessary calculations for window coordinates and vectors. This will be used to calculate centroids for
2324 : // each window element
2325 18 : W1 = 0.0;
2326 18 : W2 = 0.0;
2327 18 : W3 = 0.0;
2328 :
2329 18 : if (state.dataSurface->Surface(IWin).Sides == 4) {
2330 18 : W3 = state.dataSurface->Surface(IWin).Vertex(2);
2331 18 : W2 = state.dataSurface->Surface(IWin).Vertex(3);
2332 18 : W1 = state.dataSurface->Surface(IWin).Vertex(4);
2333 0 : } else if (state.dataSurface->Surface(IWin).Sides == 3) {
2334 0 : W3 = state.dataSurface->Surface(IWin).Vertex(2);
2335 0 : W2 = state.dataSurface->Surface(IWin).Vertex(3);
2336 0 : W1 = state.dataSurface->Surface(IWin).Vertex(1);
2337 : }
2338 :
2339 18 : W21 = W1 - W2;
2340 18 : W23 = W3 - W2;
2341 :
2342 18 : W21 /= state.dataSurface->Surface(IWin).Height;
2343 18 : W23 /= state.dataSurface->Surface(IWin).Width;
2344 :
2345 18 : WNorm = state.dataSurface->Surface(IWin).lcsz;
2346 :
2347 18 : WinElArea = DWX * DWY;
2348 18 : if (state.dataSurface->Surface(IWin).Sides == 3) {
2349 0 : WinElArea *= std::sqrt(1.0 - pow_2(dot(W21, W23)));
2350 : }
2351 :
2352 18 : if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
2353 :
2354 0 : if (!allocated(state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap)) {
2355 0 : state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap.allocate(NRefPts, (int)state.dataDaylightingData->IllumMap.size());
2356 : }
2357 :
2358 0 : AllocateForCFSRefPointsGeometry(state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap(iRefPoint, MapNum), NumOfWinEl);
2359 :
2360 18 : } else if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
2361 18 : if (!allocated(state.dataBSDFWindow->ComplexWind(IWin).RefPoint)) {
2362 2 : state.dataBSDFWindow->ComplexWind(IWin).RefPoint.allocate(NRefPts);
2363 : }
2364 :
2365 18 : AllocateForCFSRefPointsGeometry(state.dataBSDFWindow->ComplexWind(IWin).RefPoint(iRefPoint), NumOfWinEl);
2366 : }
2367 :
2368 : //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2369 : //! Allocation for each complex fenestration state reference points
2370 : //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2371 18 : if (!allocated(state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom)) {
2372 2 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom.allocate(state.dataBSDFWindow->ComplexWind(IWin).NumStates);
2373 : }
2374 :
2375 : // Calculation needs to be performed for each state
2376 36 : for (CurFenState = 1; CurFenState <= state.dataBSDFWindow->ComplexWind(IWin).NumStates; ++CurFenState) {
2377 18 : NBasis = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurFenState).Inc.NBasis;
2378 18 : NTrnBasis = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurFenState).Trn.NBasis;
2379 :
2380 18 : if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
2381 0 : if ((int)state.dataDaylightingData->IllumMap.size() > 0) {
2382 : // illuminance map for each state
2383 0 : if (!allocated(state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).IlluminanceMap)) {
2384 0 : state.dataBSDFWindow->ComplexWind(IWin)
2385 0 : .DaylghtGeom(CurFenState)
2386 0 : .IlluminanceMap.allocate(NRefPts, (int)state.dataDaylightingData->IllumMap.size());
2387 : }
2388 :
2389 0 : AllocateForCFSRefPointsState(state,
2390 0 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).IlluminanceMap(iRefPoint, MapNum),
2391 : NumOfWinEl,
2392 : NBasis,
2393 : NTrnBasis);
2394 :
2395 0 : InitializeCFSStateData(state,
2396 0 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).IlluminanceMap(iRefPoint, MapNum),
2397 0 : state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap(iRefPoint, MapNum),
2398 : daylightCtrlNum,
2399 : IWin,
2400 : RefPoint,
2401 : CurFenState,
2402 : NBasis,
2403 : NTrnBasis,
2404 : AZVIEW,
2405 : NWX,
2406 : NWY,
2407 : W2,
2408 : W21,
2409 : W23,
2410 : DWX,
2411 : DWY,
2412 : WNorm,
2413 : WinElArea);
2414 : }
2415 :
2416 18 : } else if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
2417 18 : if (!allocated(state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).RefPoint)) {
2418 2 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).RefPoint.allocate(NRefPts);
2419 : }
2420 :
2421 18 : AllocateForCFSRefPointsState(
2422 18 : state, state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).RefPoint(iRefPoint), NumOfWinEl, NBasis, NTrnBasis);
2423 :
2424 36 : InitializeCFSStateData(state,
2425 18 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurFenState).RefPoint(iRefPoint),
2426 18 : state.dataBSDFWindow->ComplexWind(IWin).RefPoint(iRefPoint),
2427 : daylightCtrlNum,
2428 : IWin,
2429 : RefPoint,
2430 : CurFenState,
2431 : NBasis,
2432 : NTrnBasis,
2433 : AZVIEW,
2434 : NWX,
2435 : NWY,
2436 : W2,
2437 : W21,
2438 : W23,
2439 : DWX,
2440 : DWY,
2441 : WNorm,
2442 : WinElArea);
2443 : }
2444 : }
2445 18 : }
2446 :
2447 18 : void InitializeCFSStateData(EnergyPlusData &state,
2448 : DataBSDFWindow::BSDFRefPoints &StateRefPoint,
2449 : DataBSDFWindow::BSDFRefPointsGeomDescr &DaylghtGeomDescr,
2450 : [[maybe_unused]] int const daylightCtrlNum, // Current daylighting control number
2451 : int const iWin,
2452 : Vector3<Real64> const &RefPoint, // reference point
2453 : int const CurFenState,
2454 : int const NBasis,
2455 : int const NTrnBasis,
2456 : Real64 const AZVIEW,
2457 : int const NWX,
2458 : int const NWY,
2459 : Vector3<Real64> const &W2,
2460 : Vector3<Real64> const &W21,
2461 : Vector3<Real64> const &W23,
2462 : Real64 const DWX,
2463 : Real64 const DWY,
2464 : Vector3<Real64> const &WNorm, // unit vector from window (point towards outside)
2465 : Real64 const WinElArea)
2466 : {
2467 : // SUBROUTINE INFORMATION:
2468 : // AUTHOR Simon Vidanovic
2469 : // DATE WRITTEN June 2013
2470 : // MODIFIED na
2471 : // RE-ENGINEERED na
2472 :
2473 : // PURPOSE OF THIS SUBROUTINE:
2474 : // Initialize daylight state data for current
2475 :
2476 : // SUBROUTINE LOCAL VARIABLES
2477 : int curWinEl;
2478 : int IRay;
2479 : bool hit;
2480 : int TotHits;
2481 : int JSurf;
2482 : Real64 DotProd; // Temporary variable for manipulating dot product .dot.
2483 : int NSky;
2484 : int NGnd;
2485 : int NReflSurf;
2486 : int MaxTotHits;
2487 : int IX;
2488 : int IY;
2489 : Real64 LeastHitDsq; // dist^2 from window element center to hit point
2490 : Real64 HitDsq;
2491 : Real64 TransRSurf;
2492 : int I;
2493 : int J;
2494 :
2495 18 : auto &RWin = state.dataDaylightingManager->RWin;
2496 18 : auto &V = state.dataDaylightingManager->V;
2497 18 : auto &GroundHitPt = state.dataDaylightingManager->GroundHitPt;
2498 :
2499 : // temporary arrays for surfaces
2500 : // Each complex fenestration state can have different number of basis elements
2501 : // This is the reason for making these temporary arrays local
2502 36 : Array1D_int TmpSkyInd(NBasis, 0); // Temporary sky index list
2503 36 : Array1D_int TmpGndInd(NBasis, 0); // Temporary gnd index list
2504 36 : Array1D<Real64> TmpGndMultiplier(NBasis, 0.0); // Temporary ground obstruction multiplier
2505 36 : Array1D_int TmpRfSfInd(NBasis, 0); // Temporary RefSurfIndex
2506 36 : Array1D_int TmpRfRyNH(NBasis, 0); // Temporary RefRayNHits
2507 36 : Array2D_int TmpHSurfNo(state.dataSurface->TotSurfaces, NBasis, 0); // Temporary HitSurfNo
2508 36 : Array2D<Real64> TmpHSurfDSq(state.dataSurface->TotSurfaces, NBasis, 0.0); // Temporary HitSurfDSq
2509 :
2510 : // Object Data
2511 36 : Vector Centroid; // current window element centroid
2512 36 : Vector HitPt; // surface hit point
2513 36 : Array1D<Vector> TmpGndPt(NBasis, Vector(0.0, 0.0, 0.0)); // Temporary ground intersection list
2514 36 : Array2D<Vector> TmpHitPt(state.dataSurface->TotSurfaces, NBasis, Vector(0.0, 0.0, 0.0)); // Temporary HitPt
2515 :
2516 18 : CFSRefPointPosFactor(state, RefPoint, StateRefPoint, iWin, CurFenState, NTrnBasis, AZVIEW);
2517 :
2518 18 : curWinEl = 0;
2519 : // loop through window elements. This will calculate sky, ground and reflection bins for each window element
2520 54 : for (IX = 1; IX <= NWX; ++IX) {
2521 180 : for (IY = 1; IY <= NWY; ++IY) {
2522 :
2523 144 : ++curWinEl;
2524 :
2525 : // centroid coordinates for current window element
2526 144 : Centroid = W2 + (double(IX) - 0.5) * W23 * DWX + (double(IY) - 0.5) * W21 * DWY;
2527 144 : RWin = Centroid;
2528 :
2529 144 : CFSRefPointSolidAngle(state, RefPoint, RWin, WNorm, StateRefPoint, DaylghtGeomDescr, iWin, CurFenState, NTrnBasis, curWinEl, WinElArea);
2530 :
2531 144 : NSky = 0;
2532 144 : NGnd = 0;
2533 144 : NReflSurf = 0;
2534 144 : MaxTotHits = 0;
2535 : // Calculation of potential surface obstruction for each incoming direction
2536 21024 : for (IRay = 1; IRay <= NBasis; ++IRay) {
2537 :
2538 20880 : hit = false;
2539 20880 : TotHits = 0;
2540 187920 : for (JSurf = 1; JSurf <= state.dataSurface->TotSurfaces; ++JSurf) {
2541 : // the following test will cycle on anything except exterior surfaces and shading surfaces
2542 167040 : if (state.dataSurface->Surface(JSurf).HeatTransSurf && state.dataSurface->Surface(JSurf).ExtBoundCond != ExternalEnvironment)
2543 125280 : continue;
2544 : // skip the base surface containing the window and any other subsurfaces of that surface
2545 62640 : if (JSurf == state.dataSurface->Surface(iWin).BaseSurf ||
2546 20880 : state.dataSurface->Surface(JSurf).BaseSurf == state.dataSurface->Surface(iWin).BaseSurf)
2547 41760 : continue;
2548 : // skip surfaces that face away from the window
2549 0 : DotProd = dot(state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay),
2550 0 : state.dataSurface->Surface(JSurf).NewellSurfaceNormalVector);
2551 0 : if (DotProd >= 0) continue;
2552 0 : PierceSurface(state, JSurf, Centroid, state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay), HitPt, hit);
2553 0 : if (!hit) continue; // Miss: Try next surface
2554 0 : if (TotHits == 0) {
2555 : // First hit for this ray
2556 0 : TotHits = 1;
2557 0 : ++NReflSurf;
2558 0 : TmpRfSfInd(NReflSurf) = IRay;
2559 0 : TmpRfRyNH(NReflSurf) = 1;
2560 0 : TmpHSurfNo(1, NReflSurf) = JSurf;
2561 0 : TmpHitPt(1, NReflSurf) = HitPt;
2562 0 : V = HitPt - Centroid; // vector array from window ctr to hit pt
2563 0 : LeastHitDsq = V.magnitude_squared(); // dist^2 window ctr to hit pt
2564 0 : TmpHSurfDSq(1, NReflSurf) = LeastHitDsq;
2565 0 : if (!state.dataSurface->Surface(JSurf).HeatTransSurf && state.dataSurface->Surface(JSurf).SchedShadowSurfIndex != 0) {
2566 0 : TransRSurf = 1.0; // If a shadowing surface may have a scheduled transmittance, treat it here as completely transparent
2567 : } else {
2568 0 : TransRSurf = 0.0;
2569 : }
2570 : } else {
2571 0 : V = HitPt - Centroid;
2572 0 : HitDsq = V.magnitude_squared();
2573 0 : if (HitDsq >= LeastHitDsq) {
2574 0 : if (TransRSurf > 0.0) { // forget the new hit if the closer hit is opaque
2575 0 : J = TotHits + 1;
2576 0 : if (TotHits > 1) {
2577 0 : for (I = 2; I <= TotHits; ++I) {
2578 0 : if (HitDsq < TmpHSurfDSq(I, NReflSurf)) {
2579 0 : J = I;
2580 0 : break;
2581 : }
2582 : }
2583 0 : if (!state.dataSurface->Surface(JSurf).HeatTransSurf &&
2584 0 : state.dataSurface->Surface(JSurf).SchedShadowSurfIndex == 0) {
2585 : // The new hit is opaque, so we can drop all the hits further away
2586 0 : TmpHSurfNo(J, NReflSurf) = JSurf;
2587 0 : TmpHitPt(J, NReflSurf) = HitPt;
2588 0 : TmpHSurfDSq(J, NReflSurf) = HitDsq;
2589 0 : TotHits = J;
2590 : } else {
2591 : // The new hit is scheduled (presumed transparent), so keep the more distant hits
2592 : // Note that all the hists in the list will be transparent except the last,
2593 : // which may be either transparent or opaque
2594 0 : if (TotHits >= J) {
2595 0 : for (I = TotHits; I >= J; --I) {
2596 0 : TmpHSurfNo(I + 1, NReflSurf) = TmpHSurfNo(I, NReflSurf);
2597 0 : TmpHitPt(I + 1, NReflSurf) = TmpHitPt(I, NReflSurf);
2598 0 : TmpHSurfDSq(I + 1, NReflSurf) = TmpHSurfDSq(I, NReflSurf);
2599 : }
2600 0 : TmpHSurfNo(J, NReflSurf) = JSurf;
2601 0 : TmpHitPt(J, NReflSurf) = HitPt;
2602 0 : TmpHSurfDSq(J, NReflSurf) = HitDsq;
2603 0 : ++TotHits;
2604 : }
2605 : } // if (.NOT.Surface(JSurf)%HeatTransSurf .AND. Surface(JSurf)%SchedShadowSurfIndex == 0) then
2606 : } // if (TotHits > 1) then
2607 : } // if (TransRSurf > 0.0d0) then
2608 : } else { // if (HitDsq >= LeastHitDsq) then
2609 : // A new closest hit. If it is opaque, drop the current hit list,
2610 : // otherwise add it at the front
2611 0 : LeastHitDsq = HitDsq;
2612 0 : if (!state.dataSurface->Surface(JSurf).HeatTransSurf && state.dataSurface->Surface(JSurf).SchedShadowSurfIndex != 0) {
2613 0 : TransRSurf = 1.0; // New closest hit is transparent, keep the existing hit list
2614 0 : for (I = TotHits; I >= 1; --I) {
2615 0 : TmpHSurfNo(I + 1, NReflSurf) = TmpHSurfNo(I, NReflSurf);
2616 0 : TmpHitPt(I + 1, NReflSurf) = TmpHitPt(I, NReflSurf);
2617 0 : TmpHSurfDSq(I + 1, NReflSurf) = TmpHSurfDSq(I, NReflSurf);
2618 0 : ++TotHits;
2619 : }
2620 : } else {
2621 0 : TransRSurf = 0.0; // New closest hit is opaque, drop the existing hit list
2622 0 : TotHits = 1;
2623 : }
2624 0 : TmpHSurfNo(1, NReflSurf) = JSurf; // In either case the new hit is put in position 1
2625 0 : TmpHitPt(1, NReflSurf) = HitPt;
2626 0 : TmpHSurfDSq(1, NReflSurf) = LeastHitDsq;
2627 : }
2628 : }
2629 : } // do JSurf = 1, TotSurfaces
2630 20880 : if (TotHits <= 0) {
2631 : // This ray reached the sky or ground unobstructed
2632 20880 : if (state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay).z < 0.0) {
2633 : // A ground ray
2634 9216 : ++NGnd;
2635 9216 : TmpGndInd(NGnd) = IRay;
2636 27648 : TmpGndPt(NGnd).x = Centroid.x - (state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay).x /
2637 18432 : state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay).z) *
2638 9216 : Centroid.z;
2639 27648 : TmpGndPt(NGnd).y = Centroid.y - (state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay).y /
2640 18432 : state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sInc(IRay).z) *
2641 9216 : Centroid.z;
2642 9216 : TmpGndPt(NGnd).z = 0.0;
2643 :
2644 : // for solar reflectance calculations, need to precalculate obstruction multipliers
2645 9216 : if (state.dataSurface->CalcSolRefl) {
2646 9216 : GroundHitPt = TmpGndPt(NGnd);
2647 9216 : TmpGndMultiplier(NGnd) = CalcObstrMultiplier(state, GroundHitPt, AltAngStepsForSolReflCalc, AzimAngStepsForSolReflCalc);
2648 : }
2649 : } else {
2650 : // A sky ray
2651 11664 : ++NSky;
2652 11664 : TmpSkyInd(NSky) = IRay;
2653 : }
2654 : } else {
2655 : // Save the number of hits for this ray
2656 0 : TmpRfRyNH(NReflSurf) = TotHits;
2657 : }
2658 20880 : MaxTotHits = max(MaxTotHits, TotHits);
2659 : } // do IRay = 1, ComplexWind(IWin)%Geom(CurFenState)%Inc%NBasis
2660 :
2661 : // Fill up state data for current window element data
2662 144 : StateRefPoint.NSky(curWinEl) = NSky;
2663 144 : StateRefPoint.SkyIndex({1, NSky}, curWinEl) = TmpSkyInd({1, NSky});
2664 :
2665 144 : StateRefPoint.NGnd(curWinEl) = NGnd;
2666 144 : StateRefPoint.GndIndex({1, NGnd}, curWinEl) = TmpGndInd({1, NGnd});
2667 144 : StateRefPoint.GndPt({1, NGnd}, curWinEl) = TmpGndPt({1, NGnd});
2668 144 : StateRefPoint.GndObstrMultiplier({1, NGnd}, curWinEl) = TmpGndMultiplier({1, NGnd});
2669 :
2670 144 : StateRefPoint.NReflSurf(curWinEl) = NReflSurf;
2671 144 : StateRefPoint.RefSurfIndex({1, NReflSurf}, curWinEl) = TmpRfSfInd({1, NReflSurf});
2672 144 : StateRefPoint.RefRayNHits({1, NReflSurf}, curWinEl) = TmpRfRyNH({1, NReflSurf});
2673 144 : StateRefPoint.HitSurfNo({1, MaxTotHits}, {1, NReflSurf}, curWinEl) = TmpHSurfNo({1, MaxTotHits}, {1, NReflSurf});
2674 144 : StateRefPoint.HitSurfDSq({1, MaxTotHits}, {1, NReflSurf}, curWinEl) = TmpHSurfDSq({1, MaxTotHits}, {1, NReflSurf});
2675 144 : StateRefPoint.HitPt({1, MaxTotHits}, {1, NReflSurf}, curWinEl) = TmpHitPt({1, MaxTotHits}, {1, NReflSurf});
2676 : } // do IY = 1, NWY
2677 : } // do IX = 1, NWX
2678 18 : }
2679 :
2680 18 : void AllocateForCFSRefPointsState(
2681 : EnergyPlusData &state, DataBSDFWindow::BSDFRefPoints &StateRefPoint, int const NumOfWinEl, int const NBasis, int const NTrnBasis)
2682 : {
2683 : // SUBROUTINE INFORMATION:
2684 : // AUTHOR Simon Vidanovic
2685 : // DATE WRITTEN June 2013
2686 : // MODIFIED na
2687 : // RE-ENGINEERED na
2688 :
2689 : // PURPOSE OF THIS SUBROUTINE:
2690 : // Memory allocation for complex fenestration systems reference points geometry
2691 :
2692 18 : if (!allocated(StateRefPoint.NSky)) {
2693 2 : StateRefPoint.NSky.allocate(NumOfWinEl);
2694 2 : StateRefPoint.NSky = 0;
2695 : }
2696 :
2697 18 : if (!allocated(StateRefPoint.SkyIndex)) {
2698 2 : StateRefPoint.SkyIndex.allocate(NBasis, NumOfWinEl);
2699 2 : StateRefPoint.SkyIndex = 0;
2700 : }
2701 :
2702 18 : if (!allocated(StateRefPoint.NGnd)) {
2703 2 : StateRefPoint.NGnd.allocate(NumOfWinEl);
2704 2 : StateRefPoint.NGnd = 0;
2705 : }
2706 :
2707 18 : if (!allocated(StateRefPoint.GndIndex)) {
2708 2 : StateRefPoint.GndIndex.allocate(NBasis, NumOfWinEl);
2709 2 : StateRefPoint.GndIndex = 0;
2710 : }
2711 :
2712 18 : if (!allocated(StateRefPoint.GndPt)) {
2713 2 : StateRefPoint.GndPt.allocate(NBasis, NumOfWinEl);
2714 2 : StateRefPoint.GndPt = Vector(0.0, 0.0, 0.0);
2715 : }
2716 :
2717 18 : if (!allocated(StateRefPoint.GndObstrMultiplier)) {
2718 2 : StateRefPoint.GndObstrMultiplier.allocate(NBasis, NumOfWinEl);
2719 2 : StateRefPoint.GndObstrMultiplier = 0.0;
2720 : }
2721 :
2722 18 : if (!allocated(StateRefPoint.NReflSurf)) {
2723 2 : StateRefPoint.NReflSurf.allocate(NumOfWinEl);
2724 2 : StateRefPoint.NReflSurf = 0;
2725 : }
2726 :
2727 18 : if (!allocated(StateRefPoint.RefSurfIndex)) {
2728 2 : StateRefPoint.RefSurfIndex.allocate(NBasis, NumOfWinEl);
2729 2 : StateRefPoint.RefSurfIndex = 0;
2730 : }
2731 :
2732 18 : if (!allocated(StateRefPoint.TransOutSurf)) {
2733 2 : StateRefPoint.TransOutSurf.allocate(NBasis, NumOfWinEl);
2734 2 : StateRefPoint.TransOutSurf = 1.0;
2735 : }
2736 :
2737 18 : if (!allocated(StateRefPoint.RefRayNHits)) {
2738 2 : StateRefPoint.RefRayNHits.allocate(NBasis, NumOfWinEl);
2739 2 : StateRefPoint.RefRayNHits = 0;
2740 : }
2741 :
2742 18 : if (!allocated(StateRefPoint.HitSurfNo)) {
2743 2 : StateRefPoint.HitSurfNo.allocate(state.dataSurface->TotSurfaces, NBasis, NumOfWinEl);
2744 2 : StateRefPoint.HitSurfNo = 0;
2745 : }
2746 :
2747 18 : if (!allocated(StateRefPoint.HitSurfDSq)) {
2748 2 : StateRefPoint.HitSurfDSq.allocate(state.dataSurface->TotSurfaces, NBasis, NumOfWinEl);
2749 2 : StateRefPoint.HitSurfDSq = 0.0;
2750 : }
2751 :
2752 18 : if (!allocated(StateRefPoint.HitPt)) {
2753 2 : StateRefPoint.HitPt.allocate(state.dataSurface->TotSurfaces, NBasis, NumOfWinEl);
2754 2 : StateRefPoint.HitPt = Vector(0.0, 0.0, 0.0);
2755 : }
2756 :
2757 18 : if (!allocated(StateRefPoint.RefPointIndex)) {
2758 2 : StateRefPoint.RefPointIndex.allocate(NumOfWinEl);
2759 2 : StateRefPoint.RefPointIndex = 0;
2760 : }
2761 :
2762 18 : if (!allocated(StateRefPoint.RefPointIntersection)) {
2763 2 : StateRefPoint.RefPointIntersection.allocate(NTrnBasis);
2764 2 : StateRefPoint.RefPointIntersection = false;
2765 : }
2766 :
2767 18 : if (!allocated(StateRefPoint.RefPtIntPosFac)) {
2768 2 : StateRefPoint.RefPtIntPosFac.allocate(NTrnBasis);
2769 2 : StateRefPoint.RefPtIntPosFac = 0.0;
2770 : }
2771 18 : }
2772 :
2773 18 : void AllocateForCFSRefPointsGeometry(DataBSDFWindow::BSDFRefPointsGeomDescr &RefPointsGeomDescr, int const NumOfWinEl)
2774 : {
2775 : // SUBROUTINE INFORMATION:
2776 : // AUTHOR Simon Vidanovic
2777 : // DATE WRITTEN June 2013
2778 : // MODIFIED na
2779 : // RE-ENGINEERED na
2780 :
2781 : // PURPOSE OF THIS SUBROUTINE:
2782 : // Memory allocation for complex fenestration systems reference points geometry
2783 :
2784 : // METHODOLOGY EMPLOYED:
2785 : // <description>
2786 :
2787 : // REFERENCES:
2788 : // na
2789 :
2790 : // Using/Aliasing
2791 :
2792 : // Locals
2793 : // SUBROUTINE ARGUMENT DEFINITIONS:
2794 : // integer, intent(in) :: NRefPts
2795 :
2796 : // SUBROUTINE LOCAL VARIABLES
2797 :
2798 18 : if (!allocated(RefPointsGeomDescr.SolidAngle)) {
2799 2 : RefPointsGeomDescr.SolidAngle.allocate(NumOfWinEl);
2800 2 : RefPointsGeomDescr.SolidAngle = 0.0;
2801 : }
2802 :
2803 18 : if (!allocated(RefPointsGeomDescr.SolidAngleVec)) {
2804 2 : RefPointsGeomDescr.SolidAngleVec.allocate(NumOfWinEl);
2805 2 : RefPointsGeomDescr.SolidAngleVec = Vector(0.0, 0.0, 0.0);
2806 : }
2807 18 : }
2808 :
2809 144 : void CFSRefPointSolidAngle(EnergyPlusData &state,
2810 : Vector3<Real64> const &RefPoint,
2811 : Vector3<Real64> const &RWin,
2812 : Vector3<Real64> const &WNorm,
2813 : DataBSDFWindow::BSDFRefPoints &RefPointMap,
2814 : DataBSDFWindow::BSDFRefPointsGeomDescr &RefPointGeomMap,
2815 : int const iWin,
2816 : int const CurFenState,
2817 : int const NTrnBasis,
2818 : int const curWinEl,
2819 : Real64 const WinElArea)
2820 : {
2821 : // SUBROUTINE INFORMATION:
2822 : // AUTHOR Simon Vidanovic
2823 : // DATE WRITTEN June 2013
2824 : // MODIFIED na
2825 : // RE-ENGINEERED na
2826 :
2827 : // PURPOSE OF THIS SUBROUTINE:
2828 : // Calculate position factor for given reference point.
2829 :
2830 : // SUBROUTINE LOCAL VARIABLES
2831 144 : auto &Ray = state.dataDaylightingManager->Ray;
2832 144 : auto &RayNorm = state.dataDaylightingManager->RayNorm;
2833 144 : auto &V = state.dataDaylightingManager->V;
2834 : Real64 BestMatch;
2835 : int iTrnRay;
2836 : Real64 temp;
2837 : Real64 Dist;
2838 : Real64 CosB;
2839 :
2840 : // calculate vector from center of window element to the current reference point
2841 144 : Ray = RefPoint - RWin;
2842 :
2843 : // figure out outgoing beam direction from current reference point
2844 144 : BestMatch = 0.0;
2845 21024 : for (iTrnRay = 1; iTrnRay <= NTrnBasis; ++iTrnRay) {
2846 20880 : V = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sTrn(iTrnRay);
2847 20880 : temp = dot(Ray, V);
2848 20880 : if (temp > BestMatch) {
2849 702 : BestMatch = temp;
2850 702 : RefPointMap.RefPointIndex(curWinEl) = iTrnRay;
2851 : }
2852 : }
2853 :
2854 : // calculate solid view angle
2855 144 : Dist = Ray.magnitude();
2856 144 : RayNorm = Ray / (-Dist);
2857 144 : RefPointGeomMap.SolidAngleVec(curWinEl) = RayNorm;
2858 144 : CosB = dot(WNorm, RayNorm);
2859 144 : RefPointGeomMap.SolidAngle(curWinEl) = WinElArea * CosB / (Dist * Dist);
2860 144 : }
2861 :
2862 18 : void CFSRefPointPosFactor(EnergyPlusData &state,
2863 : Vector3<Real64> const &RefPoint,
2864 : DataBSDFWindow::BSDFRefPoints &RefPointMap,
2865 : int const iWin,
2866 : int const CurFenState,
2867 : int const NTrnBasis,
2868 : Real64 const AZVIEW)
2869 : {
2870 : // SUBROUTINE INFORMATION:
2871 : // AUTHOR Simon Vidanovic
2872 : // DATE WRITTEN June 2013
2873 : // MODIFIED na
2874 : // RE-ENGINEERED na
2875 :
2876 : // PURPOSE OF THIS SUBROUTINE:
2877 : // Calculate position factor for given reference point.
2878 :
2879 : // Using/Aliasing
2880 : using WindowComplexManager::DaylghtAltAndAzimuth;
2881 :
2882 : // SUBROUTINE LOCAL VARIABLES
2883 : int iTrnRay;
2884 : Real64 XR;
2885 : Real64 YR;
2886 18 : auto &V = state.dataDaylightingManager->V;
2887 18 : auto &InterPoint = state.dataDaylightingManager->InterPoint;
2888 : bool hit;
2889 :
2890 : // Object Data
2891 18 : DataBSDFWindow::BSDFDaylghtPosition elPos; // altitude and azimuth of intersection element
2892 :
2893 18 : auto const &sTrn(state.dataBSDFWindow->ComplexWind(iWin).Geom(CurFenState).sTrn);
2894 2628 : for (iTrnRay = 1; iTrnRay <= NTrnBasis; ++iTrnRay) {
2895 2610 : V = sTrn(iTrnRay);
2896 2610 : V.negate();
2897 : PierceSurface(state, iWin, RefPoint, V, InterPoint, hit);
2898 2610 : if (hit) {
2899 234 : RefPointMap.RefPointIntersection(iTrnRay) = true;
2900 :
2901 234 : elPos = DaylghtAltAndAzimuth(V);
2902 :
2903 234 : XR = std::tan(std::abs(DataGlobalConstants::PiOvr2 - AZVIEW - elPos.Azimuth) + 0.001);
2904 234 : YR = std::tan(elPos.Altitude + 0.001);
2905 234 : RefPointMap.RefPtIntPosFac(iTrnRay) = DayltgGlarePositionFactor(XR, YR);
2906 : }
2907 : }
2908 18 : }
2909 :
2910 9906 : Real64 CalcObstrMultiplier(EnergyPlusData &state,
2911 : Vector3<Real64> const &GroundHitPt, // Coordinates of point that ray hits ground (m)
2912 : int const AltSteps, // Number of steps in altitude angle for solar reflection calc
2913 : int const AzimSteps // Number of steps in azimuth angle of solar reflection calc
2914 : )
2915 : {
2916 :
2917 : // SUBROUTINE INFORMATION:
2918 : // AUTHOR Simon Vidanovic
2919 : // DATE WRITTEN April 2013, refactor from legacy code by Fred Winklemann
2920 : // MODIFIED na
2921 : // RE-ENGINEERED na
2922 :
2923 : // PURPOSE OF THIS SUBROUTINE:
2924 : // collect code to do obstruction multiplier from ground point
2925 :
2926 : // METHODOLOGY EMPLOYED:
2927 : // Send rays upward from hit point and see which ones are unobstructed and so go to sky.
2928 : // Divide hemisphere centered at ground hit point into elements of altitude Phi and
2929 : // azimuth Theta and create upward-going ground ray unit vector at each Phi,Theta pair.
2930 : // Phi = 0 at the horizon; Phi = Pi/2 at the zenith.
2931 :
2932 : // USE STATEMENTS:
2933 : using DataSurfaces::AzimAngStepsForSolReflCalc;
2934 :
2935 : // Return value
2936 : Real64 ObstrMultiplier;
2937 :
2938 : // Locals
2939 : Real64 DPhi; // Phi increment (radians)
2940 : Real64 DTheta; // Theta increment (radians)
2941 : Real64 SkyGndUnObs; // Unobstructed sky irradiance at a ground point
2942 : Real64 SkyGndObs; // Obstructed sky irradiance at a ground point
2943 :
2944 : Real64 Phi; // Altitude angle of ray from a ground point (radians)
2945 : Real64 SPhi; // Sin of Phi
2946 : Real64 CPhi; // cos of Phi
2947 : Real64 Theta; // Azimuth angle of ray from a ground point (radians)
2948 :
2949 : Real64 CosIncAngURay; // Cosine of incidence angle of URay on ground plane
2950 : Real64 dOmegaGnd; // Solid angle element of ray from ground point (steradians)
2951 : Real64 IncAngSolidAngFac; // CosIncAngURay*dOmegaGnd/Pi
2952 : bool hitObs; // True iff obstruction is hit
2953 9906 : auto &URay = state.dataDaylightingManager->URay; // Unit vector in (Phi,Theta) direction
2954 9906 : auto &ObsHitPt = state.dataDaylightingManager->ObsHitPt; // Unit vector in (Phi,Theta) direction
2955 9906 : auto &AltSteps_last = state.dataDaylightingManager->AltSteps_last; // Unit vector in (Phi,Theta) direction
2956 9906 : auto &cos_Phi = state.dataDaylightingManager->cos_Phi; // Unit vector in (Phi,Theta) direction
2957 9906 : auto &sin_Phi = state.dataDaylightingManager->sin_Phi; // Unit vector in (Phi,Theta) direction
2958 9906 : auto &cos_Theta = state.dataDaylightingManager->cos_Theta; // Unit vector in (Phi,Theta) direction
2959 9906 : auto &sin_Theta = state.dataDaylightingManager->sin_Theta; // Unit vector in (Phi,Theta) direction
2960 9906 : auto &AzimSteps_last = state.dataDaylightingManager->AzimSteps_last;
2961 :
2962 9906 : assert(AzimSteps <= AzimAngStepsForSolReflCalc);
2963 :
2964 9906 : DPhi = DataGlobalConstants::PiOvr2 / (AltSteps / 2.0);
2965 9906 : DTheta = DataGlobalConstants::Pi / AzimSteps;
2966 9906 : SkyGndObs = 0.0;
2967 9906 : SkyGndUnObs = 0.0;
2968 :
2969 : // Tuned Precompute Phi trig table
2970 9906 : if (AltSteps != AltSteps_last) {
2971 18 : for (int IPhi = 1, IPhi_end = (AltSteps / 2); IPhi <= IPhi_end; ++IPhi) {
2972 15 : Phi = (IPhi - 0.5) * DPhi;
2973 15 : cos_Phi(IPhi) = std::cos(Phi);
2974 15 : sin_Phi(IPhi) = std::sin(Phi);
2975 : }
2976 3 : AltSteps_last = AltSteps;
2977 : }
2978 : // Tuned Precompute Theta trig table
2979 9906 : if (AzimSteps != AzimSteps_last) {
2980 57 : for (int ITheta = 1; ITheta <= 2 * AzimSteps; ++ITheta) {
2981 54 : Theta = (ITheta - 0.5) * DTheta;
2982 54 : cos_Theta(ITheta) = std::cos(Theta);
2983 54 : sin_Theta(ITheta) = std::sin(Theta);
2984 : }
2985 3 : AzimSteps_last = AzimSteps;
2986 : }
2987 :
2988 : // Altitude loop
2989 59436 : for (int IPhi = 1, IPhi_end = (AltSteps / 2); IPhi <= IPhi_end; ++IPhi) {
2990 49530 : SPhi = sin_Phi(IPhi);
2991 49530 : CPhi = cos_Phi(IPhi);
2992 :
2993 : // Third component of ground ray unit vector in (Theta,Phi) direction
2994 49530 : URay(3) = SPhi;
2995 49530 : dOmegaGnd = CPhi * DTheta * DPhi;
2996 : // Cosine of angle of incidence of ground ray on ground plane
2997 49530 : CosIncAngURay = SPhi;
2998 49530 : IncAngSolidAngFac = CosIncAngURay * dOmegaGnd / DataGlobalConstants::Pi;
2999 : // Azimuth loop
3000 941070 : for (int ITheta = 1; ITheta <= 2 * AzimSteps; ++ITheta) {
3001 891540 : URay(1) = CPhi * cos_Theta(ITheta);
3002 891540 : URay(2) = CPhi * sin_Theta(ITheta);
3003 891540 : SkyGndUnObs += IncAngSolidAngFac;
3004 : // Does this ground ray hit an obstruction?
3005 891540 : hitObs = false;
3006 891540 : if (state.dataSurface->TotSurfaces < octreeCrossover) { // Linear search through surfaces
3007 :
3008 1770233 : for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
3009 : PierceSurface(state, ObsSurfNum, GroundHitPt, URay, ObsHitPt, hitObs); // Check if ray pierces surface
3010 1054441 : if (hitObs) break;
3011 : }
3012 :
3013 : } else { // Surface octree search
3014 :
3015 : // Lambda function for the octree to test for surface hit
3016 0 : auto surfaceHit = [&GroundHitPt, &hitObs, &URay, &ObsHitPt](SurfaceData const &surface) -> bool {
3017 0 : if (surface.IsShadowPossibleObstruction) {
3018 : PierceSurface(surface, GroundHitPt, URay, ObsHitPt, hitObs); // Check if ray pierces surface
3019 0 : return hitObs; // Ray pierces surface
3020 : } else {
3021 0 : return false;
3022 : }
3023 0 : };
3024 :
3025 : // Check octree surface candidates until a hit is found, if any
3026 0 : Vector3<Real64> const URay_inv(SurfaceOctreeCube::safe_inverse(URay));
3027 0 : state.dataHeatBalMgr->surfaceOctree.hasSurfaceRayIntersectsCube(GroundHitPt, URay, URay_inv, surfaceHit);
3028 : }
3029 :
3030 891540 : if (hitObs) continue; // Obstruction hit
3031 : // Sky is hit
3032 715792 : SkyGndObs += IncAngSolidAngFac;
3033 : } // End of azimuth loop
3034 : } // End of altitude loop
3035 :
3036 : // in case ground point is surrounded by obstructions (SkyGndUnObs == 0), then multiplier will be equal to zero
3037 : // This should not happen anyway because in that case ray would not be able to reach ground point
3038 9906 : ObstrMultiplier = 0.0;
3039 :
3040 9906 : if (SkyGndUnObs != 0.0) {
3041 9906 : ObstrMultiplier = SkyGndObs / SkyGndUnObs;
3042 : }
3043 :
3044 9906 : return ObstrMultiplier;
3045 : }
3046 :
3047 65710656 : void FigureDayltgCoeffsAtPointsForSunPosition(
3048 : EnergyPlusData &state,
3049 : int const daylightCtrlNum, // Daylighting control index
3050 : int const iRefPoint,
3051 : int const iXelement,
3052 : int const NWX, // Number of window elements in x direction for dayltg calc
3053 : int const iYelement,
3054 : int const NWY, // Number of window elements in y direction for dayltg calc
3055 : int const WinEl, // Current window element counter
3056 : int const IWin,
3057 : int const IWin2,
3058 : int const iHour,
3059 : int &ISunPos,
3060 : Real64 const SkyObstructionMult,
3061 : Vector3<Real64> const &RWIN2, // Center of a window element for TDD:DOME (if exists) in abs coord sys
3062 : Vector3<Real64> const &Ray, // Unit vector along ray from reference point to window element
3063 : Real64 const PHRAY, // Altitude of ray from reference point to window element (radians)
3064 : int const LSHCAL, // Interior shade calculation flag: 0=not yet calculated, 1=already calculated
3065 : int const InShelfSurf, // Inside daylighting shelf surface number
3066 : Real64 const COSB, // Cosine of angle between window outward normal and ray from reference point to window element
3067 : Real64 const ObTrans, // Product of solar transmittances of exterior obstructions hit by ray from reference point through a window element
3068 : Real64 const TVISB, // Visible transmittance of window for COSB angle of incidence (times light well efficiency, if appropriate)
3069 : Real64 const DOMEGA, // Solid angle subtended by window element wrt reference point (steradians)
3070 : int const ICtrl, // Window control counter
3071 : WinShadingType const ShType, // Window shading type
3072 : int const BlNum, // Window blind number
3073 : Real64 const THRAY, // Azimuth of ray from reference point to window element (radians)
3074 : Vector3<Real64> const &WNORM2, // Unit vector normal to window
3075 : DataDaylighting::ExtWinType const ExtWinType, // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
3076 : int const IConst, // Construction counter
3077 : Real64 const AZVIEW, // Azimuth of view vector in absolute coord system for glare calculation (radians)
3078 : Vector3<Real64> const &RREF2, // Location of virtual reference point in absolute coordinate system
3079 : bool const hitIntObs, // True iff interior obstruction hit
3080 : bool const hitExtObs, // True iff ray from ref pt to ext win hits an exterior obstruction
3081 : DataDaylighting::CalledFor const CalledFrom, // indicate which type of routine called this routine
3082 : Real64 &TVISIntWin, // Visible transmittance of int win at COSBIntWin for light from ext win
3083 : Real64 &TVISIntWinDisk, // Visible transmittance of int win at COSBIntWin for sun
3084 : int const MapNum)
3085 : {
3086 :
3087 : // SUBROUTINE INFORMATION:
3088 : // AUTHOR B. Griffith
3089 : // DATE WRITTEN November 2012, refactor from legacy code by Fred Winklemann
3090 : // MODIFIED na
3091 : // RE-ENGINEERED na
3092 :
3093 : // PURPOSE OF THIS SUBROUTINE:
3094 : // collect code for calculations sun position aspects for daylighting coefficients
3095 :
3096 : // METHODOLOGY EMPLOYED:
3097 : // switch as need to serve both reference points and map points based on calledFrom
3098 : using General::POLYF;
3099 :
3100 99651404 : if (state.dataSurface->SurfSunCosHourly(iHour)(3) < DataEnvironment::SunIsUpValue) return;
3101 :
3102 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3103 32161756 : static Vector3<Real64> const RREF(0.0); // Location of a reference point in absolute coordinate system //Autodesk Was used uninitialized:
3104 : // Never set here // Made static for performance and const for now until issue addressed
3105 32161756 : auto &XEDIRSK = state.dataDaylightingManager->XEDIRSK;
3106 32161756 : auto &XAVWLSK = state.dataDaylightingManager->XAVWLSK;
3107 32161756 : auto &RAYCOS = state.dataDaylightingManager->RAYCOS;
3108 32161756 : auto &TransBmBmMult = state.dataDaylightingManager->TransBmBmMult;
3109 32161756 : auto &TransBmBmMultRefl = state.dataDaylightingManager->TransBmBmMultRefl;
3110 32161756 : auto &HP = state.dataDaylightingManager->HP;
3111 : int JB; // Slat angle counter
3112 : Real64 ProfAng; // Solar profile angle on a window (radians)
3113 : Real64 POSFAC; // Position factor for a window element / ref point / view vector combination
3114 : Real64 XR; // Horizontal displacement ratio
3115 : Real64 YR; // Vertical displacement ratio
3116 : bool hit; // True iff ray from ref point thru window element hits an obstruction
3117 :
3118 : Real64 ObTransDisk; // Product of solar transmittances of exterior obstructions hit by ray from reference point to sun
3119 : Real64 LumAtHitPtFrSun; // Luminance at hit point of obstruction by reflection of direct light from sun (cd/m2)
3120 : int ISky; // Sky type index: 1=clear, 2=clear turbid, 3=intermediate, 4=overcast
3121 :
3122 : Real64 ELUM; // Sky or ground luminance (cd/m2)
3123 : Real64 DEDIR; // Illuminance contribution at reference point from window element (lux)
3124 : Real64 COSI; // Cosine of angle between direct sun and window outward normal
3125 : bool hitWin; // True iff ray passes thru window
3126 : Real64 TVISS; // Direct solar visible transmittance of window at given angle of incidence
3127 : // (times light well efficiency, if appropriate)
3128 : Real64 XAVWL; // XAVWL*TVISS is contribution of window luminance from solar disk (cd/m2)
3129 :
3130 : Real64 SlatAng; // Blind slat angle (rad)
3131 : int NearestHitSurfNum; // Surface number of nearest obstruction
3132 : int NearestHitSurfNumX; // Surface number to use when obstruction is a shadowing surface
3133 32161756 : auto &NearestHitPt = state.dataDaylightingManager->NearestHitPt; // Hit point of ray on nearest obstruction
3134 32161756 : auto &GroundHitPt = state.dataDaylightingManager->GroundHitPt; // Coordinates of point that ray hits ground (m)
3135 32161756 : auto &ObsHitPt = state.dataDaylightingManager->ObsHitPt; // Coordinates of hit point on an obstruction (m)
3136 32161756 : auto &ReflNorm = state.dataDaylightingManager->ReflNorm; // Normal vector to reflecting surface
3137 32161756 : auto &SunVecMir = state.dataDaylightingManager->SunVecMir; // Sun ray mirrored in reflecting surface
3138 32161756 : auto &HitPtRefl = state.dataDaylightingManager->HitPtRefl; // Point that ray hits reflecting surface
3139 32161756 : auto &HitPtObs = state.dataDaylightingManager->HitPtObs; // Hit point on obstruction
3140 32161756 : auto &HitPtIntWinDisk = state.dataDaylightingManager->HitPtIntWinDisk; // Intersection point on an interior window for ray from ref pt to sun (m)
3141 : Real64 Alfa; // Intermediate variables
3142 : bool hitObs; // True iff obstruction is hit
3143 : Real64 ObsVisRefl; // Visible reflectance of obstruction
3144 : Real64 SkyReflVisLum; // Reflected sky luminance at hit point divided by
3145 :
3146 : int RecSurfNum; // Receiving surface number
3147 : int ReflSurfNum; // Reflecting surface number
3148 : int ReflSurfNumX;
3149 : Real64 CosIncAngRefl; // Cos of angle of incidence of beam on reflecting surface
3150 : Real64 CosIncAngRec; // Cos of angle of incidence of reflected beam on receiving window
3151 : bool hitRefl; // True iff ray hits reflecting surface
3152 : Real64 ReflDistanceSq; // Distance squared between ref pt and hit point on reflecting surf (m^2)
3153 : Real64 ReflDistance; // Distance between ref pt and hit point on reflecting surf (m)
3154 : bool hitObsRefl; // True iff obstruction hit between ref pt and reflection point
3155 : int ReflSurfRecNum; // Receiving surface number for a reflecting window
3156 : Real64 SpecReflectance; // Specular reflectance of a reflecting surface
3157 : Real64 TVisRefl; // Bare window vis trans for reflected beam
3158 : // (times light well efficiency, if appropriate)
3159 : Real64 PHSUNrefl; // Altitude angle of reflected sun (radians)
3160 : Real64 THSUNrefl; // Azimuth anggle of reflected sun (radians)
3161 :
3162 : bool hitIntWinDisk; // True iff ray from ref pt to sun passes thru an int window
3163 : bool hitIntObsDisk; // True iff ray from ref pt to sun hits an interior obstruction
3164 : // bool hitExtObsDisk; // True iff ray from ref pt to sun hits an exterior obstruction //Unused Set but never
3165 : // used
3166 :
3167 : int IntWinDiskHitNum; // Surface number of int window intersected by ray betw ref pt and sun
3168 : Real64 COSBIntWin; // Cos of angle between int win outward normal and ray betw ref pt and
3169 : // exterior window element or between ref pt and sun
3170 : Real64 TVisIntWinMult; // Interior window vis trans multiplier for ext win in adjacent zone
3171 : Real64 TVisIntWinDiskMult; // Interior window vis trans solar disk multiplier for ext win in adj zone
3172 : Real64 WindowSolidAngleDaylightPoint;
3173 :
3174 32161756 : ++ISunPos;
3175 :
3176 : // Altitude of sun (degrees)
3177 32161756 : state.dataDaylightingManager->PHSUN = state.dataDaylightingManager->PHSUNHR(iHour);
3178 32161756 : state.dataDaylightingManager->SPHSUN = state.dataDaylightingManager->SPHSUNHR(iHour);
3179 32161756 : state.dataDaylightingManager->CPHSUN = state.dataDaylightingManager->CPHSUNHR(iHour);
3180 :
3181 : // Azimuth of sun in absolute coord sys
3182 32161756 : state.dataDaylightingManager->THSUN = state.dataDaylightingManager->THSUNHR(iHour);
3183 :
3184 : // First time through, call routine to calculate inter-reflected illuminance
3185 : // at reference point and luminance of window with shade, screen or blind.
3186 :
3187 : // Rob/TH - Not sure whether this call is necessary for interior zones with interior windows only.
3188 : // new code would be -
3189 : // IF (LSHCAL == 1 .AND. ExtWinType /= AdjZoneExtWin) CALL DayltgInterReflectedIllum(ISunPos,IHR,ZoneNum,IWin2)
3190 32161756 : int enclNum = 0; // enclosure index
3191 32161756 : int zoneNum = 0; // zone index
3192 32161756 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
3193 6250876 : zoneNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).zoneIndex;
3194 6250876 : enclNum = state.dataDaylightingData->daylightControl(daylightCtrlNum).enclIndex;
3195 25910880 : } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
3196 25910880 : assert(MapNum > 0);
3197 25910880 : zoneNum = state.dataDaylightingData->IllumMapCalc(MapNum).zoneIndex;
3198 25910880 : enclNum = state.dataDaylightingData->IllumMapCalc(MapNum).enclIndex;
3199 : }
3200 32161756 : if (state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF) {
3201 32160268 : if (LSHCAL == 1) DayltgInterReflectedIllum(state, ISunPos, iHour, enclNum, IWin2);
3202 : } else {
3203 1488 : if (LSHCAL == 1) DayltgInterReflectedIllumComplexFenestration(state, IWin2, WinEl, iHour, daylightCtrlNum, iRefPoint, CalledFrom, MapNum);
3204 1488 : if (COSB <= 0.0) return;
3205 1488 : DayltgDirectIllumComplexFenestration(state, IWin, WinEl, iHour, iRefPoint, CalledFrom, MapNum);
3206 : // Call direct sun component only once since calculation is done for entire window
3207 1488 : if (WinEl == (NWX * NWY)) {
3208 186 : DayltgDirectSunDiskComplexFenestration(state, IWin2, iHour, iRefPoint, WinEl, AZVIEW, CalledFrom, MapNum);
3209 : }
3210 1488 : return;
3211 : }
3212 :
3213 : // Daylighting shelf simplification: The shelf completely blocks all view of the window,
3214 : // only interrelflected illumination is allowed (see DayltgInterReflectedIllum above).
3215 : // Everything else in this loop has to do with direct luminance from the window.
3216 32160268 : if (InShelfSurf > 0) return;
3217 :
3218 31769908 : if (COSB <= 0.0) return;
3219 :
3220 31769908 : XEDIRSK = 0.0;
3221 : // XEDIRSU = 0.0; //Unused Set but never used
3222 31769908 : XAVWLSK = 0.0;
3223 31769908 : Real64 const Ray_3(Ray(3));
3224 31769908 : Real64 const DOMEGA_Ray_3(DOMEGA * Ray_3);
3225 :
3226 : // Add contribution of this window element to glare and to
3227 : // direct illuminance at reference point
3228 :
3229 : // The I,J,K indices for sky and sun components of direct illuminance
3230 : // (EDIRSK, EDIRSU) and average window luminance (AVWLSK, AVWLSU) are:
3231 : // I=1 for clear sky, =2 Clear turbid, =3 Intermediate, =4 Overcast;
3232 : // J=1 for bare window, =2 for window with shade or fixed slat-angle blind;
3233 : // = 2,3,...,MaxSlatAngs+1 for window with variable slat-angle blind;
3234 : // K = sun position index.
3235 :
3236 : // ----- CASE I -- BARE WINDOW (no shading device)
3237 :
3238 : // Beam solar and sky solar reflected from nearest obstruction.
3239 : // In the following hitIntObs == false ==> no interior obstructions hit, and
3240 : // hitExtObs == true ==> one or more exterior obstructions hit.
3241 31769908 : if (state.dataSurface->CalcSolRefl && !hitIntObs && hitExtObs) {
3242 : // One or more exterior obstructions was hit; get contribution of reflection
3243 : // from nearest obstruction.
3244 : // Find obstruction whose hit point is closest to this ray's window element
3245 0 : DayltgClosestObstruction(state, RWIN2, Ray, NearestHitSurfNum, NearestHitPt);
3246 0 : if (NearestHitSurfNum > 0) {
3247 :
3248 : // Beam solar reflected from nearest obstruction
3249 :
3250 0 : DayltgSurfaceLumFromSun(state, iHour, Ray, NearestHitSurfNum, NearestHitPt, LumAtHitPtFrSun);
3251 0 : state.dataDaylightingManager->AVWLSU(iHour, 1) += LumAtHitPtFrSun * TVISB;
3252 0 : if (PHRAY >= 0.0) state.dataDaylightingManager->EDIRSU(iHour, 1) += LumAtHitPtFrSun * DOMEGA_Ray_3 * TVISB;
3253 :
3254 : // Sky solar reflected from nearest obstruction
3255 :
3256 0 : int const ObsConstrNum = state.dataSurface->SurfActiveConstruction(NearestHitSurfNum);
3257 0 : if (ObsConstrNum > 0) {
3258 : // Exterior building surface is nearest hit
3259 0 : if (!state.dataConstruction->Construct(ObsConstrNum).TypeIsWindow) {
3260 : // Obstruction is not a window, i.e., is an opaque surface
3261 0 : ObsVisRefl = 1.0 - state.dataMaterial->Material(state.dataConstruction->Construct(ObsConstrNum).LayerPoint(1)).AbsorpVisible;
3262 : } else {
3263 : // Obstruction is a window; assume it is bare
3264 0 : ObsVisRefl = state.dataConstruction->Construct(ObsConstrNum).ReflectVisDiffFront;
3265 : }
3266 : } else {
3267 : // Shadowing surface is nearest hit
3268 0 : if (state.dataSurface->SurfDaylightingShelfInd(NearestHitSurfNum) > 0) {
3269 : // This is a daylighting shelf, for which reflection is separately calculated
3270 0 : ObsVisRefl = 0.0;
3271 : } else {
3272 0 : ObsVisRefl = state.dataSurface->SurfShadowDiffuseVisRefl(NearestHitSurfNum);
3273 0 : if (state.dataSurface->SurfShadowGlazingConstruct(NearestHitSurfNum) > 0)
3274 0 : ObsVisRefl +=
3275 0 : state.dataSurface->SurfShadowGlazingFrac(NearestHitSurfNum) *
3276 0 : state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(NearestHitSurfNum)).ReflectVisDiffFront;
3277 : }
3278 : }
3279 0 : NearestHitSurfNumX = NearestHitSurfNum;
3280 : // Each shadowing surface has a "mirror" duplicate surface facing in the opposite direction.
3281 : // The following gets the correct side of a shadowing surface for reflection.
3282 0 : if (state.dataSurface->Surface(NearestHitSurfNum).IsShadowing) {
3283 0 : if (dot(Ray, state.dataSurface->Surface(NearestHitSurfNum).OutNormVec) > 0.0) NearestHitSurfNumX = NearestHitSurfNum + 1;
3284 : }
3285 0 : if (!state.dataSysVars->DetailedSkyDiffuseAlgorithm || !state.dataSurface->ShadingTransmittanceVaries ||
3286 0 : state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
3287 0 : SkyReflVisLum = ObsVisRefl * state.dataSurface->Surface(NearestHitSurfNumX).ViewFactorSky *
3288 0 : state.dataSolarShading->SurfDifShdgRatioIsoSky(NearestHitSurfNumX) / DataGlobalConstants::Pi;
3289 : } else {
3290 0 : SkyReflVisLum = ObsVisRefl * state.dataSurface->Surface(NearestHitSurfNumX).ViewFactorSky *
3291 0 : state.dataSolarShading->SurfDifShdgRatioIsoSkyHRTS(1, iHour, NearestHitSurfNumX) / DataGlobalConstants::Pi;
3292 : }
3293 0 : assert(equal_dimensions(state.dataDaylightingManager->AVWLSK, state.dataDaylightingManager->EDIRSK));
3294 0 : auto l2(state.dataDaylightingManager->GILSK.index(iHour, 1));
3295 0 : auto l3(state.dataDaylightingManager->AVWLSK.index(iHour, 1, 1));
3296 0 : for (ISky = 1; ISky <= 4; ++ISky, ++l2, ++l3) { // [ l2 ] == ( ISky, iHour ) // [ l3 ] == ( ISky, 1, iHour )
3297 0 : XAVWLSK(ISky) = state.dataDaylightingManager->GILSK[l2] * SkyReflVisLum;
3298 0 : state.dataDaylightingManager->AVWLSK[l3] += XAVWLSK(ISky) * TVISB;
3299 0 : if (PHRAY >= 0.0) {
3300 0 : XEDIRSK(ISky) = state.dataDaylightingManager->GILSK[l2] * SkyReflVisLum * DOMEGA_Ray_3;
3301 0 : state.dataDaylightingManager->EDIRSK[l3] += XEDIRSK(ISky) * TVISB;
3302 : }
3303 : }
3304 : }
3305 : } // End of check if solar reflection calculation is in effect
3306 :
3307 31769908 : if (ObTrans > 1.e-6) {
3308 : // Ray did not hit an obstruction or the transmittance product of hit obstructions is non-zero.
3309 : // Contribution of sky or ground luminance in cd/m2
3310 30955888 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Diffuser) {
3311 : // Make all transmitted light diffuse for a TDD with a bare diffuser
3312 2448 : assert(equal_dimensions(state.dataDaylightingManager->AVWLSK, state.dataDaylightingManager->WLUMSK));
3313 2448 : assert(equal_dimensions(state.dataDaylightingManager->AVWLSK, state.dataDaylightingManager->EDIRSK));
3314 2448 : auto l3(state.dataDaylightingManager->AVWLSK.index(iHour, 1, 1));
3315 12240 : for (ISky = 1; ISky <= 4; ++ISky, ++l3) { // [ l3 ] == ( ISky, 1, iHour )
3316 9792 : state.dataDaylightingManager->AVWLSK[l3] += state.dataDaylightingManager->WLUMSK[l3];
3317 9792 : if (ISky == 1) {
3318 2448 : state.dataDaylightingManager->AVWLSU(iHour, 1) += state.dataDaylightingManager->WLUMSU(iHour, 1);
3319 2448 : state.dataDaylightingManager->AVWLSUdisk(iHour, 1) += state.dataDaylightingManager->WLUMSUdisk(iHour, 1);
3320 : }
3321 9792 : if (PHRAY > 0.0) {
3322 9792 : state.dataDaylightingManager->EDIRSK[l3] += state.dataDaylightingManager->WLUMSK[l3] * DOMEGA_Ray_3;
3323 9792 : if (ISky == 1) state.dataDaylightingManager->EDIRSU(iHour, 1) += state.dataDaylightingManager->WLUMSU(iHour, 1) * DOMEGA_Ray_3;
3324 : }
3325 : }
3326 :
3327 : } else { // Bare window
3328 : // Tuned Hoisted operations out of loop and linear indexing
3329 30953440 : if (state.dataSurface->CalcSolRefl) { // Coordinates of ground point hit by the ray
3330 768 : Alfa = std::acos(-Ray_3);
3331 768 : Real64 const Ray_1(Ray(1));
3332 768 : Real64 const Ray_2(Ray(2));
3333 : // Beta = std::atan2( Ray_2, Ray_1 ); //Unused Tuning below eliminated use
3334 768 : Real64 HorDis((RWIN2(3) - state.dataSurface->GroundLevelZ) *
3335 768 : std::tan(Alfa)); // Distance between ground hit point and proj'n of center
3336 768 : GroundHitPt(3) = state.dataSurface->GroundLevelZ;
3337 : // Tuned Replaced by below: sqrt is faster than sincos
3338 : // GroundHitPt( 1 ) = RWIN2( 1 ) + HorDis * std::cos( Beta );
3339 : // GroundHitPt( 2 ) = RWIN2( 2 ) + HorDis * std::sin( Beta );
3340 768 : Real64 const Ray_r(std::sqrt(square(Ray_1) + square(Ray_2)));
3341 768 : if (Ray_r > 0.0) {
3342 768 : HorDis /= Ray_r;
3343 768 : GroundHitPt(1) = RWIN2(1) + HorDis * Ray_1;
3344 768 : GroundHitPt(2) = RWIN2(2) + HorDis * Ray_2;
3345 : } else { // Treat as angle==0
3346 0 : GroundHitPt(1) = RWIN2(1) + HorDis;
3347 0 : GroundHitPt(2) = RWIN2(2);
3348 : }
3349 : }
3350 30953440 : Real64 const GILSK_mult((state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi) * ObTrans * SkyObstructionMult);
3351 30953440 : Real64 const TVISB_ObTrans(TVISB * ObTrans);
3352 30953440 : Real64 const AVWLSU_add(TVISB_ObTrans * state.dataDaylightingManager->GILSU(iHour) *
3353 30953440 : (state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi));
3354 61906880 : Vector3<Real64> const SUNCOS_iHour(state.dataSurface->SurfSunCosHourly(iHour));
3355 30953440 : assert(equal_dimensions(state.dataDaylightingManager->EDIRSK, state.dataDaylightingManager->AVWLSK));
3356 30953440 : auto l(state.dataDaylightingManager->EDIRSK.index(iHour, 1, 1));
3357 154767200 : for (ISky = 1; ISky <= 4; ++ISky, ++l) { // [ l ] == ( iHour, 1, ISky )
3358 123813760 : if (PHRAY > 0.0) { // Ray heads upward to sky
3359 123472844 : ELUM = DayltgSkyLuminance(state, ISky, THRAY, PHRAY);
3360 123472844 : XEDIRSK(ISky) = ELUM * DOMEGA_Ray_3;
3361 123472844 : DEDIR = XEDIRSK(ISky) * TVISB;
3362 123472844 : state.dataDaylightingManager->EDIRSK[l] += DEDIR * ObTrans;
3363 123472844 : state.dataDaylightingManager->AVWLSK[l] += ELUM * TVISB_ObTrans;
3364 123472844 : XAVWLSK(ISky) = ELUM * ObTrans;
3365 : } else { // PHRAY <= 0.
3366 : // Ray heads downward to ground.
3367 : // Contribution from sky diffuse reflected from ground
3368 340916 : XAVWLSK(ISky) = state.dataDaylightingManager->GILSK(iHour, ISky) * GILSK_mult;
3369 340916 : state.dataDaylightingManager->AVWLSK[l] += TVISB * XAVWLSK(ISky);
3370 : // Contribution from beam solar reflected from ground (beam reaching ground point
3371 : // can be obstructed [SunObstructionMult < 1.0] if CalcSolRefl = .TRUE.)
3372 340916 : if (ISky == 1) {
3373 : // SunObstructionMult = 1.0; //Tuned
3374 85229 : if (state.dataSurface->CalcSolRefl) { // Coordinates of ground point hit by the ray
3375 : // Sun reaches ground point if vector from this point to the sun is unobstructed
3376 240 : hitObs = false;
3377 1155 : for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
3378 : PierceSurface(state, ObsSurfNum, GroundHitPt, SUNCOS_iHour, ObsHitPt, hitObs);
3379 942 : if (hitObs) break;
3380 : }
3381 : // if ( hitObs ) SunObstructionMult = 0.0;
3382 240 : if (!hitObs) state.dataDaylightingManager->AVWLSU(iHour, 1) += AVWLSU_add;
3383 : } else {
3384 84989 : state.dataDaylightingManager->AVWLSU(iHour, 1) += AVWLSU_add;
3385 : }
3386 : } // End of check if ISky = 1
3387 : } // End of check if ray is going up or down
3388 : } // End of loop over sky types
3389 : } // End of check if bare window or TDD:DIFFUSER
3390 : } // End of check if ObTrans > 1.E-6
3391 :
3392 : // Illuminance from beam solar (without interior reflection)
3393 : // Just run this once on the last pass
3394 31769908 : if (iXelement == NWX && iYelement == NWY) { // Last pass
3395 :
3396 : // Beam solar reaching reference point directly without exterior reflection
3397 :
3398 : // Unit vector from ref. pt. to sun
3399 317368 : RAYCOS(1) = state.dataDaylightingManager->CPHSUN * std::cos(state.dataDaylightingManager->THSUN);
3400 317368 : RAYCOS(2) = state.dataDaylightingManager->CPHSUN * std::sin(state.dataDaylightingManager->THSUN);
3401 317368 : RAYCOS(3) = state.dataDaylightingManager->SPHSUN;
3402 :
3403 : // Is sun on front side of exterior window?
3404 317368 : COSI = dot(WNORM2, RAYCOS);
3405 317368 : if (COSI > 0.0) {
3406 :
3407 : // Does RAYCOS pass thru exterior window? HP is point that RAYCOS intersects window plane.
3408 : PierceSurface(state, IWin2, RREF2, RAYCOS, HP, hitWin);
3409 240911 : hitIntObsDisk = false;
3410 240911 : if (hitWin) {
3411 8373 : if (ExtWinType == DataDaylighting::ExtWinType::InZoneExtWin) {
3412 : // Check for interior obstructions between reference point and HP.
3413 8147 : DayltgHitInteriorObstruction(state, IWin2, RREF2, HP, hitIntObsDisk);
3414 : }
3415 8373 : ObTransDisk = 0.0; // Init value
3416 : // Init flag for vector from RP to sun passing through interior window
3417 8373 : hitIntWinDisk = false;
3418 8373 : if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) { // This block is for RPs in zones with interior windows
3419 : // adjacent to zones with exterior windows
3420 : // Does RAYCOS pass through interior window in zone containing RP?
3421 : // Loop over zone surfaces looking for interior windows between reference point and sun
3422 226 : auto &thisZone = state.dataHeatBal->Zone(zoneNum);
3423 452 : for (int spaceNum : thisZone.spaceIndexes) {
3424 226 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
3425 452 : for (int IntWinDisk = thisSpace.WindowSurfaceFirst, IntWinDisk_end = thisSpace.WindowSurfaceLast;
3426 452 : IntWinDisk <= IntWinDisk_end;
3427 : ++IntWinDisk) {
3428 226 : if (state.dataSurface->Surface(IntWinDisk).ExtBoundCond >= 1) {
3429 452 : if (state.dataSurface->Surface(state.dataSurface->Surface(IntWinDisk).ExtBoundCond).Zone ==
3430 226 : state.dataSurface->Surface(IWin2).Zone) {
3431 : PierceSurface(state, IntWinDisk, RREF, RAYCOS, HitPtIntWinDisk, hitIntWinDisk);
3432 226 : if (hitIntWinDisk) {
3433 0 : IntWinDiskHitNum = IntWinDisk;
3434 0 : COSBIntWin = dot(state.dataSurface->Surface(IntWinDisk).OutNormVec, RAYCOS);
3435 0 : if (COSBIntWin <= 0.0) {
3436 0 : hitIntWinDisk = false;
3437 0 : IntWinDiskHitNum = 0;
3438 0 : continue;
3439 : }
3440 0 : TVISIntWinDisk = POLYF(
3441 : COSBIntWin,
3442 0 : state.dataConstruction->Construct(state.dataSurface->Surface(IntWinDisk).Construction).TransVisBeamCoef);
3443 0 : break;
3444 : }
3445 : }
3446 : }
3447 : }
3448 : }
3449 :
3450 226 : if (!hitIntWinDisk) { // Vector from RP to sun does not pass through interior window
3451 226 : ObTransDisk = 0.0;
3452 226 : hit = true; //! fcw Is this needed?
3453 : }
3454 :
3455 : // Check for interior obstructions between ref point and interior window
3456 226 : hitIntObsDisk = false;
3457 226 : if (hitIntWinDisk) {
3458 0 : DayltgHitInteriorObstruction(state, IntWinDiskHitNum, RREF, HitPtIntWinDisk, hitIntObsDisk);
3459 : // If no obstruction between RP and hit int win, check for obstruction
3460 : // between int win and ext win
3461 0 : if (!hitIntObsDisk) {
3462 0 : DayltgHitBetWinObstruction(state, IntWinDiskHitNum, IWin2, HitPtIntWinDisk, HP, hitIntObsDisk);
3463 : }
3464 : }
3465 226 : if (hitIntObsDisk) ObTransDisk = 0.0;
3466 : } // case where RP is in zone with interior window adjacent to zone with exterior window
3467 :
3468 : // hitExtObsDisk = false; //Unused Set but never used
3469 : // RJH 08-25-07 hitIntWinDisk should not be reset to false here, and should be tested below.
3470 : // This is to correct logic flaw causing direct solar to reach adjacent zone refpt
3471 : // when vector to sun does not pass through interior window
3472 : // hitIntWinDisk = false
3473 8373 : if (!hitIntObsDisk) { // No interior obstruction was hit
3474 : // Net transmittance of exterior obstructions encountered by RAYCOS
3475 : // ObTransDisk = 1.0 will be returned if no exterior obstructions are hit.
3476 8369 : DayltgHitObstruction(state, iHour, IWin2, RREF2, RAYCOS, ObTransDisk);
3477 : // if ( ObTransDisk < 1.0 ) hitExtObsDisk = true; //Unused Set but never used
3478 : // RJH 08-26-07 However, if this is a case of interior window
3479 : // and vector to sun does not pass through interior window
3480 : // then reset ObTransDisk to 0.0 since it is the key test for adding
3481 : // contribution of sun to RP below.
3482 8369 : if ((ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) && (!hitIntWinDisk)) {
3483 226 : ObTransDisk = 0.0;
3484 : }
3485 : }
3486 :
3487 : // PETER: need side wall mounted TDD to test this
3488 : // PETER: probably need to replace RREF2 with RWIN2
3489 : // PETER: need to check for interior obstructions too.
3490 :
3491 8373 : if (ObTransDisk > 1.e-6) {
3492 :
3493 : // Sun reaches reference point; increment illuminance.
3494 : // Direct normal illuminance is normalized to 1.0
3495 :
3496 7829 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Diffuser) {
3497 : // No beam is transmitted. Takes care of TDD with a bare diffuser and all types of blinds.
3498 0 : TVISS = 0.0;
3499 : } else {
3500 : // Beam transmittance for bare window and all types of blinds
3501 15658 : TVISS = POLYF(COSI, state.dataConstruction->Construct(IConst).TransVisBeamCoef) * state.dataSurface->SurfWinGlazedFrac(IWin) *
3502 7829 : state.dataSurface->SurfWinLightWellEff(IWin);
3503 7829 : if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin && hitIntWinDisk) TVISS *= TVISIntWinDisk;
3504 : }
3505 :
3506 7829 : state.dataDaylightingManager->EDIRSUdisk(iHour, 1) = RAYCOS(3) * TVISS * ObTransDisk; // Bare window
3507 :
3508 7829 : TransBmBmMult = 0.0;
3509 7829 : if (ANY_BLIND(ShType)) {
3510 0 : ProfileAngle(state, IWin, RAYCOS, state.dataHeatBal->Blind(BlNum).SlatOrientation, ProfAng);
3511 : // Contribution of beam passing through slats and reaching reference point
3512 0 : for (JB = 1; JB <= MaxSlatAngs; ++JB) {
3513 : // IF (.NOT.SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT
3514 0 : if (state.dataSurface->SurfWinMovableSlats(IWin)) {
3515 0 : SlatAng = (JB - 1) * DataGlobalConstants::Pi / (MaxSlatAngs - 1);
3516 : } else {
3517 0 : SlatAng = state.dataHeatBal->Blind(BlNum).SlatAngle * DataGlobalConstants::DegToRadians;
3518 : }
3519 0 : TransBmBmMult(JB) = General::BlindBeamBeamTrans(ProfAng,
3520 : SlatAng,
3521 0 : state.dataHeatBal->Blind(BlNum).SlatWidth,
3522 0 : state.dataHeatBal->Blind(BlNum).SlatSeparation,
3523 0 : state.dataHeatBal->Blind(BlNum).SlatThickness);
3524 0 : state.dataDaylightingManager->EDIRSUdisk(iHour, JB + 1) = RAYCOS(3) * TVISS * TransBmBmMult(JB) * ObTransDisk;
3525 :
3526 : // do this only once for fixed slat blinds
3527 0 : if (!state.dataSurface->SurfWinMovableSlats(IWin)) break;
3528 : }
3529 7829 : } else if (ShType == WinShadingType::ExtScreen) {
3530 : // pass angle from sun to window normal here using PHSUN and THSUN from above and surface angles
3531 : // SunAltitudeToWindowNormalAngle = PHSUN - SurfaceWindow(IWin)%Phi
3532 : // SunAzimuthToWindowNormalAngle = THSUN - SurfaceWindow(IWin)%Theta
3533 0 : CalcScreenTransmittance(state,
3534 : IWin,
3535 0 : (state.dataDaylightingManager->PHSUN - state.dataSurface->SurfWinPhi(IWin)),
3536 0 : (state.dataDaylightingManager->THSUN - state.dataSurface->SurfWinTheta(IWin)));
3537 0 : TransBmBmMult(1) = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).BmBmTrans;
3538 0 : state.dataDaylightingManager->EDIRSUdisk(iHour, 2) = RAYCOS(3) * TVISS * TransBmBmMult(1) * ObTransDisk;
3539 : }
3540 :
3541 7829 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
3542 : // Glare from solar disk
3543 :
3544 : // Position factor for sun (note that AZVIEW is wrt y-axis and THSUN is wrt
3545 : // x-axis of absolute coordinate system.
3546 5933 : XR = std::tan(std::abs(DataGlobalConstants::PiOvr2 - AZVIEW - state.dataDaylightingManager->THSUN) + 0.001);
3547 5933 : YR = std::tan(state.dataDaylightingManager->PHSUN + 0.001);
3548 5933 : POSFAC = DayltgGlarePositionFactor(XR, YR);
3549 :
3550 5933 : WindowSolidAngleDaylightPoint = state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint);
3551 :
3552 5933 : if (POSFAC != 0.0 && WindowSolidAngleDaylightPoint > 0.000001) {
3553 : // Increment window luminance. Luminance of solar disk (cd/m2)
3554 : // is 1.47*10^4*(direct normal solar illuminance) for direct normal solar
3555 : // illuminance in lux (lumens/m2). For purposes of calculating daylight factors
3556 : // direct normal solar illuminance = 1.0.
3557 : // Solid angle subtended by sun is 0.000068 steradians
3558 :
3559 3771 : XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) / std::pow(WindowSolidAngleDaylightPoint, 0.8);
3560 3771 : state.dataDaylightingManager->AVWLSUdisk(iHour, 1) = XAVWL * TVISS * ObTransDisk; // Bare window
3561 :
3562 3771 : if (ANY_BLIND(ShType)) {
3563 0 : for (JB = 1; JB <= MaxSlatAngs; ++JB) {
3564 : // IF (.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT
3565 0 : state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) = XAVWL * TVISS * TransBmBmMult(JB) * ObTransDisk;
3566 0 : if (!state.dataSurface->SurfWinMovableSlats(IWin)) break;
3567 : }
3568 3771 : } else if (ShType == WinShadingType::ExtScreen) {
3569 0 : state.dataDaylightingManager->AVWLSUdisk(iHour, 2) = XAVWL * TVISS * TransBmBmMult(1) * ObTransDisk;
3570 : }
3571 : } // Position Factor
3572 : }
3573 : } // Beam avoids all obstructions
3574 : } // Beam passes thru window
3575 : } // Sun on front side
3576 :
3577 : // Beam solar reaching reference point after beam-beam (specular) reflection from
3578 : // an exterior surface
3579 :
3580 317368 : if (state.dataSurface->CalcSolRefl) {
3581 : // Receiving surface number corresponding this window
3582 96 : RecSurfNum = state.dataSurface->SurfShadowRecSurfNum(IWin2);
3583 96 : if (RecSurfNum > 0) { // interior windows do not apply
3584 96 : if (state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs > 0) {
3585 : // This window has associated obstructions that could reflect beam onto the window
3586 288 : for (int loop = 1, loop_end = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs; loop <= loop_end;
3587 : ++loop) {
3588 192 : ReflSurfNum = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).PossibleObsSurfNums(loop);
3589 192 : ReflSurfNumX = ReflSurfNum;
3590 : // Each shadowing surface has a "mirror" duplicate surface facing in the opposite direction.
3591 : // The following gets the correct side of a shadowing surface for reflection.
3592 192 : if (state.dataSurface->Surface(ReflSurfNum).IsShadowing) {
3593 192 : if (dot(RAYCOS, state.dataSurface->Surface(ReflSurfNum).OutNormVec) < 0.0) ReflSurfNumX = ReflSurfNum + 1;
3594 : }
3595 : // Require that the surface can have specular reflection
3596 384 : if (state.dataSurface->Surface(ReflSurfNum).Class == SurfaceClass::Window ||
3597 192 : state.dataSurface->SurfShadowGlazingFrac(ReflSurfNum) > 0.0) {
3598 0 : ReflNorm = state.dataSurface->Surface(ReflSurfNumX).OutNormVec;
3599 : // Vector to sun that is mirrored in obstruction
3600 0 : SunVecMir = RAYCOS - 2.0 * dot(RAYCOS, ReflNorm) * ReflNorm;
3601 : // Skip if reflecting surface is not sunlit
3602 0 : if (state.dataHeatBal->SurfSunlitFrac(iHour, 1, ReflSurfNumX) < 0.01) continue;
3603 : // Skip if altitude angle of mirrored sun is negative since reflected sun cannot
3604 : // reach reference point in this case
3605 0 : if (SunVecMir(3) <= 0.0) continue;
3606 : // Cosine of incidence angle of reflected beam on window
3607 0 : CosIncAngRec = dot(state.dataSurface->Surface(IWin2).OutNormVec, SunVecMir);
3608 0 : if (CosIncAngRec <= 0.0) continue;
3609 : // Does ray from ref. pt. along SunVecMir pass through window?
3610 : PierceSurface(state, IWin2, RREF2, SunVecMir, HP, hitWin);
3611 0 : if (!hitWin) continue; // Ray did not pass through window
3612 : // Check if this ray hits interior obstructions
3613 0 : DayltgHitInteriorObstruction(state, IWin2, RREF2, HP, hit);
3614 0 : if (hit) continue; // Interior obstruction was hit
3615 : // Does ray hit this reflecting surface?
3616 : PierceSurface(state, ReflSurfNum, RREF2, SunVecMir, HitPtRefl, hitRefl);
3617 0 : if (!hitRefl) continue; // Ray did not hit this reflecting surface
3618 0 : ReflDistanceSq = distance_squared(HitPtRefl, RREF2);
3619 0 : ReflDistance = std::sqrt(ReflDistanceSq);
3620 : // Is ray from ref. pt. to reflection point (HitPtRefl) obstructed?
3621 0 : hitObsRefl = false;
3622 0 : for (int loop2 = 1, loop2_end = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).NumPossibleObs;
3623 0 : loop2 <= loop2_end;
3624 : ++loop2) {
3625 0 : int const ObsSurfNum = state.dataSolarReflectionManager->SolReflRecSurf(RecSurfNum).PossibleObsSurfNums(loop2);
3626 0 : if (ObsSurfNum == ReflSurfNum || ObsSurfNum == state.dataSurface->Surface(ReflSurfNum).BaseSurf) continue;
3627 : PierceSurface(state, ObsSurfNum, RREF2, SunVecMir, ReflDistance, HitPtObs, hitObs); // ReflDistance cutoff added
3628 0 : if (hitObs) { // => Could skip distance check (unless < vs <= ReflDistance really matters)
3629 0 : if (distance_squared(HitPtObs, RREF2) < ReflDistanceSq) { // Distance squared from ref pt to reflection point
3630 0 : hitObsRefl = true;
3631 0 : break;
3632 : }
3633 : }
3634 : }
3635 0 : if (hitObsRefl) continue; // Obstruction closer than reflection pt. was hit; go to next obstruction
3636 : // There is no obstruction for this ray between ref pt and hit pt on reflecting surface.
3637 : // See if ray from hit pt on reflecting surface to original (unmirrored) sun position is obstructed
3638 0 : hitObs = false;
3639 0 : if (state.dataSurface->Surface(ReflSurfNum).Class == SurfaceClass::Window) {
3640 : // Reflecting surface is a window.
3641 : // Receiving surface number for this reflecting window.
3642 0 : ReflSurfRecNum = state.dataSurface->SurfShadowRecSurfNum(ReflSurfNum);
3643 0 : if (ReflSurfRecNum > 0) {
3644 : // Loop over possible obstructions for this reflecting window
3645 0 : for (int loop2 = 1, loop2_end = state.dataSolarReflectionManager->SolReflRecSurf(ReflSurfRecNum).NumPossibleObs;
3646 0 : loop2 <= loop2_end;
3647 : ++loop2) {
3648 : int const ObsSurfNum =
3649 0 : state.dataSolarReflectionManager->SolReflRecSurf(ReflSurfRecNum).PossibleObsSurfNums(loop2);
3650 : PierceSurface(state, ObsSurfNum, HitPtRefl, RAYCOS, HitPtObs, hitObs);
3651 0 : if (hitObs) break;
3652 : }
3653 : }
3654 : } else {
3655 : // Reflecting surface is a building shade
3656 0 : for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
3657 0 : if (ObsSurfNum == ReflSurfNum) continue;
3658 : PierceSurface(state, ObsSurfNum, HitPtRefl, RAYCOS, HitPtObs, hitObs);
3659 0 : if (hitObs) break;
3660 : }
3661 : } // End of check if reflector is a window or shadowing surface
3662 :
3663 0 : if (hitObs) continue; // Obstruction hit between reflection hit point and sun; go to next obstruction
3664 :
3665 : // No obstructions. Calculate reflected beam illuminance at ref. pt. from this reflecting surface.
3666 0 : SpecReflectance = 0.0;
3667 0 : CosIncAngRefl = std::abs(dot(RAYCOS, ReflNorm));
3668 0 : if (state.dataSurface->Surface(ReflSurfNum).Class == SurfaceClass::Window) {
3669 0 : int const ConstrNumRefl = state.dataSurface->SurfActiveConstruction(ReflSurfNum);
3670 0 : SpecReflectance =
3671 0 : POLYF(std::abs(CosIncAngRefl), state.dataConstruction->Construct(ConstrNumRefl).ReflSolBeamFrontCoef);
3672 : }
3673 0 : if (state.dataSurface->Surface(ReflSurfNum).IsShadowing && state.dataSurface->SurfShadowGlazingConstruct(ReflSurfNum) > 0)
3674 0 : SpecReflectance = state.dataSurface->SurfShadowGlazingFrac(ReflSurfNum) *
3675 0 : POLYF(std::abs(CosIncAngRefl),
3676 0 : state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(ReflSurfNum))
3677 : .ReflSolBeamFrontCoef);
3678 0 : TVisRefl = POLYF(CosIncAngRec, state.dataConstruction->Construct(IConst).TransVisBeamCoef) *
3679 0 : state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
3680 0 : state.dataDaylightingManager->EDIRSUdisk(iHour, 1) += SunVecMir(3) * SpecReflectance * TVisRefl; // Bare window
3681 :
3682 0 : TransBmBmMultRefl = 0.0;
3683 0 : if (ANY_BLIND(ShType)) {
3684 0 : ProfileAngle(state, IWin, SunVecMir, state.dataHeatBal->Blind(BlNum).SlatOrientation, ProfAng);
3685 : // Contribution of reflected beam passing through slats and reaching reference point
3686 0 : Real64 const Pi_SlatAng_fac(DataGlobalConstants::Pi / (MaxSlatAngs - 1));
3687 0 : for (JB = 1; JB <= MaxSlatAngs; ++JB) {
3688 : // IF (.NOT.SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT
3689 0 : if (state.dataSurface->SurfWinMovableSlats(IWin)) {
3690 0 : SlatAng = double(JB - 1) * Pi_SlatAng_fac;
3691 : } else {
3692 0 : SlatAng = state.dataHeatBal->Blind(BlNum).SlatAngle * DataGlobalConstants::DegToRadians;
3693 : }
3694 0 : TransBmBmMultRefl(JB) = General::BlindBeamBeamTrans(ProfAng,
3695 : SlatAng,
3696 0 : state.dataHeatBal->Blind(BlNum).SlatWidth,
3697 0 : state.dataHeatBal->Blind(BlNum).SlatSeparation,
3698 0 : state.dataHeatBal->Blind(BlNum).SlatThickness);
3699 0 : state.dataDaylightingManager->EDIRSUdisk(iHour, JB + 1) +=
3700 0 : SunVecMir(3) * SpecReflectance * TVisRefl * TransBmBmMultRefl(JB);
3701 :
3702 0 : if (!state.dataSurface->SurfWinMovableSlats(IWin)) break;
3703 : }
3704 0 : } else if (ShType == WinShadingType::ExtScreen) {
3705 : // pass angle from sun to window normal here using PHSUN and THSUN from above and
3706 : // surface angles SunAltitudeToWindowNormalAngle = PHSUN - SurfaceWindow(IWin)%Phi
3707 : // SunAzimuthToWindowNormalAngle = THSUN - SurfaceWindow(IWin)%Theta
3708 0 : CalcScreenTransmittance(state,
3709 : IWin,
3710 0 : (state.dataDaylightingManager->PHSUN - state.dataSurface->SurfWinPhi(IWin)),
3711 0 : (state.dataDaylightingManager->THSUN - state.dataSurface->SurfWinTheta(IWin)));
3712 0 : TransBmBmMultRefl(1) = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).BmBmTrans;
3713 0 : state.dataDaylightingManager->EDIRSUdisk(iHour, 2) +=
3714 0 : SunVecMir(3) * SpecReflectance * TVisRefl * TransBmBmMultRefl(1);
3715 : } // End of check if window has a blind or screen
3716 :
3717 : // Glare from reflected solar disk
3718 :
3719 0 : PHSUNrefl = SunVecMir(3);
3720 0 : THSUNrefl = std::atan2(SunVecMir(2), SunVecMir(1));
3721 0 : XR = std::tan(std::abs(DataGlobalConstants::PiOvr2 - AZVIEW - THSUNrefl) + 0.001);
3722 0 : YR = std::tan(PHSUNrefl + 0.001);
3723 0 : POSFAC = DayltgGlarePositionFactor(XR, YR);
3724 0 : if (POSFAC != 0.0 && state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint) > 0.000001) {
3725 0 : XAVWL = 14700.0 * std::sqrt(0.000068 * POSFAC) * double(NWX * NWY) /
3726 0 : std::pow(state.dataSurface->SurfaceWindow(IWin).SolidAngAtRefPtWtd(iRefPoint), 0.8);
3727 0 : state.dataDaylightingManager->AVWLSUdisk(iHour, 1) += XAVWL * TVisRefl * SpecReflectance; // Bare window
3728 0 : if (ANY_BLIND(ShType)) {
3729 0 : for (JB = 1; JB <= MaxSlatAngs; ++JB) {
3730 : // IF(.NOT. SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT
3731 0 : state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) +=
3732 0 : XAVWL * TVisRefl * SpecReflectance * TransBmBmMultRefl(JB);
3733 0 : if (!state.dataSurface->SurfWinMovableSlats(IWin)) break;
3734 : }
3735 0 : } else if (ShType == WinShadingType::ExtScreen) {
3736 0 : state.dataDaylightingManager->AVWLSUdisk(iHour, 2) += XAVWL * TVisRefl * SpecReflectance * TransBmBmMultRefl(1);
3737 : }
3738 : }
3739 : } // End of check that obstruction can specularly reflect
3740 : } // End of loop over obstructions associated with this window
3741 :
3742 : } // End of check if this window has associated obstructions
3743 : } // End of check to see if this is exterior type window
3744 : } // End of check if exterior reflection calculation is in effect
3745 :
3746 : } // Last pass
3747 :
3748 31769908 : if ((ICtrl > 0 && (ANY_BLIND(ShType) || ANY_SHADE_SCREEN(ShType))) || state.dataSurface->SurfWinSolarDiffusing(IWin)) {
3749 :
3750 : // ----- CASE II -- WINDOW WITH SCREEN, SHADE, BLIND, OR DIFFUSING WINDOW
3751 :
3752 : // Interior window visible transmittance multiplier for exterior window in adjacent zone
3753 6000 : TVisIntWinMult = 1.0;
3754 6000 : TVisIntWinDiskMult = 1.0;
3755 6000 : if (state.dataSurface->Surface(IWin).SolarEnclIndex != state.dataDaylightingData->daylightControl(daylightCtrlNum).enclIndex) {
3756 0 : TVisIntWinMult = TVISIntWin;
3757 0 : TVisIntWinDiskMult = TVISIntWinDisk;
3758 : }
3759 :
3760 6000 : Real64 const DOMEGA_Ray_3_TVisIntWinMult(DOMEGA_Ray_3 * TVisIntWinMult);
3761 30000 : for (ISky = 1; ISky <= 4; ++ISky) {
3762 24000 : for (JB = 1; JB <= MaxSlatAngs; ++JB) {
3763 : // IF (.NOT.SurfaceWindow(IWin)%MovableSlats .AND. JB > 1) EXIT
3764 24000 : state.dataDaylightingManager->AVWLSK(iHour, JB + 1, ISky) +=
3765 24000 : state.dataDaylightingManager->WLUMSK(iHour, JB + 1, ISky) * TVisIntWinMult;
3766 24000 : if (ISky == 1) {
3767 6000 : state.dataDaylightingManager->AVWLSU(iHour, JB + 1) += state.dataDaylightingManager->WLUMSU(iHour, JB + 1) * TVisIntWinMult;
3768 6000 : state.dataDaylightingManager->AVWLSUdisk(iHour, JB + 1) +=
3769 6000 : state.dataDaylightingManager->WLUMSUdisk(iHour, JB + 1) * TVisIntWinDiskMult;
3770 : }
3771 24000 : if (PHRAY > 0.0) {
3772 21792 : state.dataDaylightingManager->EDIRSK(iHour, JB + 1, ISky) +=
3773 21792 : state.dataDaylightingManager->WLUMSK(iHour, JB + 1, ISky) * DOMEGA_Ray_3_TVisIntWinMult;
3774 21792 : if (ISky == 1)
3775 5448 : state.dataDaylightingManager->EDIRSU(iHour, JB + 1) +=
3776 5448 : state.dataDaylightingManager->WLUMSU(iHour, JB + 1) * DOMEGA_Ray_3_TVisIntWinMult;
3777 : }
3778 24000 : if (!state.dataSurface->SurfWinMovableSlats(IWin)) break;
3779 : }
3780 : }
3781 : }
3782 : }
3783 :
3784 360720 : void FigureRefPointDayltgFactorsToAddIllums(EnergyPlusData &state,
3785 : int const daylightCtrlNum, // Current daylighting control number
3786 : int const iRefPoint,
3787 : int const iHour,
3788 : int &ISunPos,
3789 : int const IWin,
3790 : int const loopwin,
3791 : int const NWX, // Number of window elements in x direction for dayltg calc
3792 : int const NWY, // Number of window elements in y direction for dayltg calc
3793 : int const ICtrl // Window control counter
3794 : )
3795 : {
3796 :
3797 : // SUBROUTINE INFORMATION:
3798 : // AUTHOR B. Griffith, Oct 2012, derived from legacy code by Fred Winkelmann
3799 : // DATE WRITTEN Oct. 2012
3800 : // MODIFIED na
3801 : // RE-ENGINEERED na
3802 :
3803 : // PURPOSE OF THIS SUBROUTINE:
3804 : // calculation worker routine to fill daylighting coefficients
3805 :
3806 : // METHODOLOGY EMPLOYED:
3807 : // this version is just for reference points.
3808 :
3809 : // SUBROUTINE PARAMETER DEFINITIONS:
3810 360720 : Real64 constexpr tmpDFCalc(0.05); // cut off illuminance (lux) for exterior horizontal in calculating the daylighting and glare factors
3811 :
3812 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3813 : int ISky; // Sky type index: 1=clear, 2=clear turbid, 3=intermediate, 4=overcast
3814 : int JSH; // Shading index: J=1 is unshaded window, J=2 is shaded window
3815 : Real64 VTR; // For switchable glazing, ratio of visible transmittance of fully-switched state to that of the unswitched state
3816 :
3817 360720 : if (state.dataSurface->SurfSunCosHourly(iHour)(3) < DataEnvironment::SunIsUpValue) return;
3818 :
3819 159202 : ++ISunPos;
3820 :
3821 : // Altitude of sun (degrees)
3822 159202 : state.dataDaylightingManager->PHSUN = state.dataDaylightingManager->PHSUNHR(iHour);
3823 159202 : state.dataDaylightingManager->SPHSUN = state.dataDaylightingManager->SPHSUNHR(iHour);
3824 159202 : state.dataDaylightingManager->CPHSUN = state.dataDaylightingManager->CPHSUNHR(iHour);
3825 :
3826 : // Azimuth of sun in absolute coord sys
3827 159202 : state.dataDaylightingManager->THSUN = state.dataDaylightingManager->THSUNHR(iHour);
3828 :
3829 159202 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
3830 159202 : int const enclNum = state.dataSurface->Surface(IWin).SolarEnclIndex;
3831 :
3832 796010 : for (ISky = 1; ISky <= 4; ++ISky) { // Loop over sky types
3833 :
3834 : // Loop over shading index (1=bare window; 2=diffusing glazing, shade, screen or fixed slat-angle blind;
3835 : // 2 to MaxSlatAngs+1 for variable slat-angle blind)
3836 :
3837 : // TH. 9/22/2009. CR 7625 - daylight illuminance spikes during some sunset hours due to the calculated sky and sun
3838 : // related daylight factors > 1, which theoretically can occur when sun is perpendicular to the window
3839 : // and interior surfaces with high visible reflectance.
3840 : // Added tmpDFCalc (default to 0.05 lux) as the cap for GILSK and GILSU in calculating the daylight factors
3841 : // the assumption behind it is if exterior horizontal surface does not get daylight, spaces do not get daylight.
3842 :
3843 1910424 : for (JSH = 1; JSH <= MaxSlatAngs + 1; ++JSH) {
3844 1910424 : if (!state.dataSurface->SurfWinMovableSlats(IWin) && JSH > 2) break;
3845 :
3846 1273616 : if (state.dataDaylightingManager->GILSK(iHour, ISky) > tmpDFCalc) {
3847 1273616 : thisDaylightControl.DaylIllFacSky(iHour, JSH, ISky, iRefPoint, loopwin) =
3848 2547232 : (state.dataDaylightingManager->EDIRSK(iHour, JSH, ISky) + state.dataDaylightingManager->EINTSK(iHour, JSH, ISky)) /
3849 1273616 : state.dataDaylightingManager->GILSK(iHour, ISky);
3850 1273616 : thisDaylightControl.DaylSourceFacSky(iHour, JSH, ISky, iRefPoint, loopwin) =
3851 1273616 : state.dataDaylightingManager->AVWLSK(iHour, JSH, ISky) / (NWX * NWY * state.dataDaylightingManager->GILSK(iHour, ISky));
3852 1273616 : thisDaylightControl.DaylBackFacSky(iHour, JSH, ISky, iRefPoint, loopwin) =
3853 2547232 : state.dataDaylightingManager->EINTSK(iHour, JSH, ISky) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect /
3854 1273616 : (DataGlobalConstants::Pi * state.dataDaylightingManager->GILSK(iHour, ISky));
3855 : } else {
3856 0 : thisDaylightControl.DaylIllFacSky(iHour, JSH, ISky, iRefPoint, loopwin) = 0.0;
3857 0 : thisDaylightControl.DaylSourceFacSky(iHour, JSH, ISky, iRefPoint, loopwin) = 0.0;
3858 0 : thisDaylightControl.DaylBackFacSky(iHour, JSH, ISky, iRefPoint, loopwin) = 0.0;
3859 : }
3860 :
3861 1273616 : if (ISky == 1) {
3862 318404 : if (state.dataDaylightingManager->GILSU(iHour) > tmpDFCalc) {
3863 301326 : thisDaylightControl.DaylIllFacSun(iHour, JSH, iRefPoint, loopwin) =
3864 602652 : (state.dataDaylightingManager->EDIRSU(iHour, JSH) + state.dataDaylightingManager->EINTSU(iHour, JSH)) /
3865 301326 : (state.dataDaylightingManager->GILSU(iHour) + 0.0001);
3866 301326 : thisDaylightControl.DaylIllFacSunDisk(iHour, JSH, iRefPoint, loopwin) =
3867 602652 : (state.dataDaylightingManager->EDIRSUdisk(iHour, JSH) + state.dataDaylightingManager->EINTSUdisk(iHour, JSH)) /
3868 301326 : (state.dataDaylightingManager->GILSU(iHour) + 0.0001);
3869 :
3870 301326 : thisDaylightControl.DaylSourceFacSun(iHour, JSH, iRefPoint, loopwin) =
3871 301326 : state.dataDaylightingManager->AVWLSU(iHour, JSH) / (NWX * NWY * (state.dataDaylightingManager->GILSU(iHour) + 0.0001));
3872 301326 : thisDaylightControl.DaylSourceFacSunDisk(iHour, JSH, iRefPoint, loopwin) =
3873 301326 : state.dataDaylightingManager->AVWLSUdisk(iHour, JSH) / (NWX * NWY * (state.dataDaylightingManager->GILSU(iHour) + 0.0001));
3874 :
3875 301326 : thisDaylightControl.DaylBackFacSun(iHour, JSH, iRefPoint, loopwin) =
3876 602652 : state.dataDaylightingManager->EINTSU(iHour, JSH) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect /
3877 301326 : (DataGlobalConstants::Pi * (state.dataDaylightingManager->GILSU(iHour) + 0.0001));
3878 301326 : thisDaylightControl.DaylBackFacSunDisk(iHour, JSH, iRefPoint, loopwin) =
3879 602652 : state.dataDaylightingManager->EINTSUdisk(iHour, JSH) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect /
3880 301326 : (DataGlobalConstants::Pi * (state.dataDaylightingManager->GILSU(iHour) + 0.0001));
3881 : } else {
3882 17078 : thisDaylightControl.DaylIllFacSun(iHour, JSH, iRefPoint, loopwin) = 0.0;
3883 17078 : thisDaylightControl.DaylIllFacSunDisk(iHour, JSH, iRefPoint, loopwin) = 0.0;
3884 :
3885 17078 : thisDaylightControl.DaylSourceFacSun(iHour, JSH, iRefPoint, loopwin) = 0.0;
3886 17078 : thisDaylightControl.DaylSourceFacSunDisk(iHour, JSH, iRefPoint, loopwin) = 0.0;
3887 :
3888 17078 : thisDaylightControl.DaylBackFacSun(iHour, JSH, iRefPoint, loopwin) = 0.0;
3889 17078 : thisDaylightControl.DaylBackFacSunDisk(iHour, JSH, iRefPoint, loopwin) = 0.0;
3890 : }
3891 : }
3892 : } // End of shading index loop, JSH
3893 :
3894 : // For switchable glazing put daylighting factors for switched (dark) state in IS=2 location
3895 636808 : if (ICtrl > 0) {
3896 8936 : if (state.dataSurface->WindowShadingControl(ICtrl).ShadingType == WinShadingType::SwitchableGlazing) {
3897 8360 : VTR = state.dataSurface->SurfWinVisTransRatio(IWin);
3898 8360 : thisDaylightControl.DaylIllFacSky(iHour, 2, ISky, iRefPoint, loopwin) =
3899 8360 : thisDaylightControl.DaylIllFacSky(iHour, 1, ISky, iRefPoint, loopwin) * VTR;
3900 8360 : thisDaylightControl.DaylSourceFacSky(iHour, 2, ISky, iRefPoint, loopwin) =
3901 8360 : thisDaylightControl.DaylSourceFacSky(iHour, 1, ISky, iRefPoint, loopwin) * VTR;
3902 8360 : thisDaylightControl.DaylBackFacSky(iHour, 2, ISky, iRefPoint, loopwin) =
3903 8360 : thisDaylightControl.DaylBackFacSky(iHour, 1, ISky, iRefPoint, loopwin) * VTR;
3904 8360 : if (ISky == 1) {
3905 2090 : thisDaylightControl.DaylIllFacSun(iHour, 2, iRefPoint, loopwin) =
3906 2090 : thisDaylightControl.DaylIllFacSun(iHour, 1, iRefPoint, loopwin) * VTR;
3907 2090 : thisDaylightControl.DaylSourceFacSun(iHour, 2, iRefPoint, loopwin) =
3908 2090 : thisDaylightControl.DaylSourceFacSun(iHour, 1, iRefPoint, loopwin) * VTR;
3909 2090 : thisDaylightControl.DaylBackFacSun(iHour, 2, iRefPoint, loopwin) =
3910 2090 : thisDaylightControl.DaylBackFacSun(iHour, 1, iRefPoint, loopwin) * VTR;
3911 2090 : thisDaylightControl.DaylIllFacSunDisk(iHour, 2, iRefPoint, loopwin) =
3912 2090 : thisDaylightControl.DaylIllFacSunDisk(iHour, 1, iRefPoint, loopwin) * VTR;
3913 2090 : thisDaylightControl.DaylSourceFacSunDisk(iHour, 2, iRefPoint, loopwin) =
3914 2090 : thisDaylightControl.DaylSourceFacSunDisk(iHour, 1, iRefPoint, loopwin) * VTR;
3915 2090 : thisDaylightControl.DaylBackFacSunDisk(iHour, 2, iRefPoint, loopwin) =
3916 2090 : thisDaylightControl.DaylBackFacSunDisk(iHour, 1, iRefPoint, loopwin) * VTR;
3917 : }
3918 : }
3919 : } // ICtrl > 0
3920 :
3921 : } // End of sky type loop, ISky
3922 : }
3923 :
3924 321600 : void FigureMapPointDayltgFactorsToAddIllums(EnergyPlusData &state,
3925 : int const MapNum,
3926 : int const iMapPoint,
3927 : int const iHour,
3928 : int const IWin,
3929 : int const loopwin,
3930 : int const ICtrl // Window control counter
3931 : )
3932 : {
3933 :
3934 : // SUBROUTINE INFORMATION:
3935 : // AUTHOR B. Griffith, Oct 2012, derived from legacy code by Fred Winkelmann, Peter Ellis, Linda Lawrie
3936 : // DATE WRITTEN Nov. 2012
3937 :
3938 : // PURPOSE OF THIS SUBROUTINE:
3939 : // calculation worker routine to fill daylighting coefficients
3940 :
3941 : // METHODOLOGY EMPLOYED:
3942 : // this version is just for map points.
3943 :
3944 : // SUBROUTINE PARAMETER DEFINITIONS:
3945 321600 : Real64 constexpr tmpDFCalc(0.05); // cut off illuminance (lux) for exterior horizontal in calculating
3946 : // the daylighting and glare factors
3947 :
3948 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3949 : int ISky; // Sky type index: 1=clear, 2=clear turbid, 3=intermediate, 4=overcast
3950 : int JSH; // Shading index: J=1 is unshaded window, J=2 is shaded window
3951 : Real64 VTR; // For switchable glazing, ratio of visible transmittance of
3952 : // fully-switched state to that of the unswitched state
3953 :
3954 321600 : if (state.dataSurface->SurfSunCosHourly(iHour)(3) < DataEnvironment::SunIsUpValue) return;
3955 :
3956 804000 : for (ISky = 1; ISky <= 4; ++ISky) { // Loop over sky types
3957 :
3958 : // Loop over shading index (1=bare window; 2=diffusing glazing, shade, screen or fixed slat-angle blind;
3959 : // 2 to MaxSlatAngs+1 for variable slat-angle blind)
3960 :
3961 : // TH. 9/22/2009. CR 7625 - daylight illuminance spikes during some sunset hours due to the calculated sky and sun
3962 : // related daylight factors > 1, which theoretically can occur when sun is perpendicular to the window
3963 : // and interior surfaces with high visible reflectance.
3964 : // Added tmpDFCalc (default to 0.05 lux) as the cap for GILSK and GILSU in calculating the daylight factors
3965 : // the assumption behind it is if exterior horizontal surface does not get daylight, spaces do not get daylight.
3966 :
3967 1929600 : for (JSH = 1; JSH <= MaxSlatAngs + 1; ++JSH) {
3968 1929600 : if (!state.dataSurface->SurfWinMovableSlats(IWin) && JSH > 2) break;
3969 :
3970 1286400 : if (state.dataDaylightingManager->GILSK(iHour, ISky) > tmpDFCalc) {
3971 1286400 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, JSH, ISky, iMapPoint, loopwin) =
3972 2572800 : (state.dataDaylightingManager->EDIRSK(iHour, JSH, ISky) + state.dataDaylightingManager->EINTSK(iHour, JSH, ISky)) /
3973 1286400 : state.dataDaylightingManager->GILSK(iHour, ISky);
3974 : } else {
3975 0 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, JSH, ISky, iMapPoint, loopwin) = 0.0;
3976 : }
3977 :
3978 1286400 : if (ISky == 1) {
3979 321600 : if (state.dataDaylightingManager->GILSU(iHour) > tmpDFCalc) {
3980 308200 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSun(iHour, JSH, iMapPoint, loopwin) =
3981 616400 : (state.dataDaylightingManager->EDIRSU(iHour, JSH) + state.dataDaylightingManager->EINTSU(iHour, JSH)) /
3982 308200 : (state.dataDaylightingManager->GILSU(iHour) + 0.0001);
3983 308200 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSunDisk(iHour, JSH, iMapPoint, loopwin) =
3984 616400 : (state.dataDaylightingManager->EDIRSUdisk(iHour, JSH) + state.dataDaylightingManager->EINTSUdisk(iHour, JSH)) /
3985 308200 : (state.dataDaylightingManager->GILSU(iHour) + 0.0001);
3986 :
3987 : } else {
3988 13400 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSun(iHour, JSH, iMapPoint, loopwin) = 0.0;
3989 13400 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSunDisk(iHour, JSH, iMapPoint, loopwin) = 0.0;
3990 : }
3991 : }
3992 : } // End of shading index loop, JSH
3993 :
3994 : // For switchable glazing put daylighting factors for switched (dark) state in IS=2 location
3995 643200 : if (ICtrl > 0) {
3996 585600 : if (state.dataSurface->WindowShadingControl(ICtrl).ShadingType == WinShadingType::SwitchableGlazing) {
3997 585600 : VTR = state.dataSurface->SurfWinVisTransRatio(IWin);
3998 585600 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, 2, ISky, iMapPoint, loopwin) =
3999 585600 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSky(iHour, 1, ISky, iMapPoint, loopwin) * VTR;
4000 585600 : if (ISky == 1) {
4001 146400 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSun(iHour, 2, iMapPoint, loopwin) =
4002 146400 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSun(iHour, 1, iMapPoint, loopwin) * VTR;
4003 146400 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSunDisk(iHour, 2, iMapPoint, loopwin) =
4004 146400 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllFacSunDisk(iHour, 1, iMapPoint, loopwin) * VTR;
4005 : }
4006 : }
4007 : } // ICtrl > 0
4008 :
4009 : } // End of sky type loop, ISky
4010 : }
4011 :
4012 771 : void GetDaylightingParametersInput(EnergyPlusData &state)
4013 : {
4014 :
4015 : // SUBROUTINE INFORMATION:
4016 : // AUTHOR Linda Lawrie
4017 : // DATE WRITTEN Oct 2004
4018 :
4019 : // PURPOSE OF THIS SUBROUTINE:
4020 : // This subroutine provides a simple structure to get all daylighting
4021 : // parameters.
4022 :
4023 : using namespace DElightManagerF; // Module for managing DElight subroutines
4024 :
4025 : int TotDaylightingControls; // Total Daylighting:Controls inputs (splitflux or delight type)
4026 : bool ErrorsFound; // Error flag
4027 : Real64 dLatitude; // double for argument passing
4028 : int iErrorFlag; // Error Flag for warning/errors returned from DElight
4029 1542 : std::string cErrorMsg; // Each DElight Error Message can be up to 200 characters long
4030 : bool bEndofErrFile; // End of Error File flag
4031 : bool bRecordsOnErrFile; // true if there are records on the error file
4032 : int NumReports;
4033 : int NumNames;
4034 : int NumNumbers;
4035 : int IOStat;
4036 :
4037 771 : if (!state.dataDaylightingManager->getDaylightingParametersInputFlag) return;
4038 771 : state.dataDaylightingManager->getDaylightingParametersInputFlag = false;
4039 :
4040 771 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
4041 771 : ErrorsFound = false;
4042 771 : cCurrentModuleObject = "Daylighting:Controls";
4043 771 : TotDaylightingControls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
4044 771 : if (TotDaylightingControls > 0) {
4045 62 : state.dataDaylightingData->enclDaylight.allocate(state.dataViewFactor->NumOfSolarEnclosures);
4046 62 : GetInputDayliteRefPt(state, ErrorsFound);
4047 62 : GetDaylightingControls(state, ErrorsFound);
4048 62 : GeometryTransformForDaylighting(state);
4049 62 : GetInputIlluminanceMap(state, ErrorsFound);
4050 62 : GetLightWellData(state, ErrorsFound);
4051 62 : if (ErrorsFound) ShowFatalError(state, "Program terminated for above reasons, related to DAYLIGHTING");
4052 62 : DayltgSetupAdjZoneListsAndPointers(state);
4053 : }
4054 :
4055 771 : state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl = 0;
4056 771 : state.dataDaylightingManager->maxNumRefPtInAnyEncl = 0;
4057 : // Loop through all daylighting controls to find total reference points in each enclosure
4058 1058 : for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
4059 287 : int numRefPoints = state.dataDaylightingData->daylightControl(daylightCtrlNum).TotalDaylRefPoints;
4060 287 : state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl = max(numRefPoints, state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
4061 : }
4062 5582 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
4063 4811 : state.dataDaylightingManager->maxNumRefPtInAnyEncl =
4064 4811 : max(state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints, state.dataDaylightingManager->maxNumRefPtInAnyEncl);
4065 : }
4066 :
4067 6745 : for (int SurfNum : state.dataSurface->AllHTWindowSurfaceList) {
4068 5974 : int const surfEnclNum = state.dataSurface->Surface(SurfNum).SolarEnclIndex;
4069 5974 : int const numEnclRefPoints = state.dataViewFactor->EnclSolInfo(surfEnclNum).TotalEnclosureDaylRefPoints;
4070 5974 : if (numEnclRefPoints > 0) {
4071 842 : if (!state.dataSurface->SurfWinSurfDayLightInit(SurfNum)) {
4072 842 : state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPt.allocate(numEnclRefPoints);
4073 842 : state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPt = 0.0;
4074 842 : state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPtWtd.allocate(numEnclRefPoints);
4075 842 : state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPtWtd = 0.0;
4076 842 : state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPt.allocate(2, numEnclRefPoints);
4077 842 : state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPt = 0.0;
4078 842 : state.dataSurface->SurfaceWindow(SurfNum).BackLumFromWinAtRefPt.allocate(2, numEnclRefPoints);
4079 842 : state.dataSurface->SurfaceWindow(SurfNum).BackLumFromWinAtRefPt = 0.0;
4080 842 : state.dataSurface->SurfaceWindow(SurfNum).SourceLumFromWinAtRefPt.allocate(2, numEnclRefPoints);
4081 842 : state.dataSurface->SurfaceWindow(SurfNum).SourceLumFromWinAtRefPt = 0.0;
4082 842 : state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPtRep.allocate(numEnclRefPoints);
4083 842 : state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPtRep = 0.0;
4084 842 : state.dataSurface->SurfaceWindow(SurfNum).LumWinFromRefPtRep.allocate(numEnclRefPoints);
4085 842 : state.dataSurface->SurfaceWindow(SurfNum).LumWinFromRefPtRep = 0.0;
4086 842 : state.dataSurface->SurfWinSurfDayLightInit(SurfNum) = true;
4087 : }
4088 : } else {
4089 5132 : int SurfNumAdj = state.dataSurface->Surface(SurfNum).ExtBoundCond;
4090 5132 : if (SurfNumAdj > 0) {
4091 13 : int const adjSurfEnclNum = state.dataSurface->Surface(SurfNumAdj).SolarEnclIndex;
4092 13 : int const numAdjEnclRefPoints = state.dataViewFactor->EnclSolInfo(adjSurfEnclNum).TotalEnclosureDaylRefPoints;
4093 13 : if (numAdjEnclRefPoints > 0) {
4094 1 : if (!state.dataSurface->SurfWinSurfDayLightInit(SurfNum)) {
4095 1 : state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPt.allocate(numAdjEnclRefPoints);
4096 1 : state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPt = 0.0;
4097 1 : state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPtWtd.allocate(numAdjEnclRefPoints);
4098 1 : state.dataSurface->SurfaceWindow(SurfNum).SolidAngAtRefPtWtd = 0.0;
4099 1 : state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPt.allocate(2, numAdjEnclRefPoints);
4100 1 : state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPt = 0.0;
4101 1 : state.dataSurface->SurfaceWindow(SurfNum).BackLumFromWinAtRefPt.allocate(2, numAdjEnclRefPoints);
4102 1 : state.dataSurface->SurfaceWindow(SurfNum).BackLumFromWinAtRefPt = 0.0;
4103 1 : state.dataSurface->SurfaceWindow(SurfNum).SourceLumFromWinAtRefPt.allocate(2, numAdjEnclRefPoints);
4104 1 : state.dataSurface->SurfaceWindow(SurfNum).SourceLumFromWinAtRefPt = 0.0;
4105 1 : state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPtRep.allocate(numAdjEnclRefPoints);
4106 1 : state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPtRep = 0.0;
4107 1 : state.dataSurface->SurfaceWindow(SurfNum).LumWinFromRefPtRep.allocate(numAdjEnclRefPoints);
4108 1 : state.dataSurface->SurfaceWindow(SurfNum).LumWinFromRefPtRep = 0.0;
4109 1 : state.dataSurface->SurfWinSurfDayLightInit(SurfNum) = true;
4110 : }
4111 : }
4112 : }
4113 : }
4114 :
4115 5974 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond == ExternalEnvironment) {
4116 :
4117 5960 : if (state.dataSurface->Surface(SurfNum).HasShadeControl) {
4118 143 : auto &thisSurfEnclosure(state.dataViewFactor->EnclSolInfo(state.dataSurface->Surface(SurfNum).SolarEnclIndex));
4119 143 : if (state.dataSurface->WindowShadingControl(state.dataSurface->Surface(SurfNum).activeWindowShadingControl).GlareControlIsActive) {
4120 : // Error if GlareControlIsActive but window is not in a Daylighting:Detailed zone
4121 30 : if (thisSurfEnclosure.TotalEnclosureDaylRefPoints == 0) {
4122 0 : ShowSevereError(state, "Window=" + state.dataSurface->Surface(SurfNum).Name + " has Window Shading Control with");
4123 0 : ShowContinueError(state, "GlareControlIsActive = Yes but it is not in a Daylighting zone or enclosure.");
4124 0 : ShowContinueError(state,
4125 0 : "Zone or enclosure indicated=" +
4126 0 : state.dataViewFactor->EnclSolInfo(state.dataSurface->Surface(SurfNum).SolarEnclIndex).Name);
4127 0 : ErrorsFound = true;
4128 : }
4129 : // Error if GlareControlIsActive and window is in a Daylighting:Detailed zone/enclosure with
4130 : // an interior window adjacent to another Daylighting:Detailed zone/enclosure
4131 30 : if (thisSurfEnclosure.TotalEnclosureDaylRefPoints > 0) {
4132 357 : for (int const intWin : thisSurfEnclosure.SurfacePtr) {
4133 327 : int const SurfNumAdj = state.dataSurface->Surface(intWin).ExtBoundCond;
4134 327 : if (state.dataSurface->Surface(intWin).Class == SurfaceClass::Window && SurfNumAdj > 0) {
4135 0 : auto &adjSurfEnclosure(state.dataViewFactor->EnclSolInfo(state.dataSurface->Surface(SurfNumAdj).SolarEnclIndex));
4136 0 : if (adjSurfEnclosure.TotalEnclosureDaylRefPoints > 0) {
4137 0 : ShowSevereError(state, "Window=" + state.dataSurface->Surface(SurfNum).Name + " has Window Shading Control with");
4138 0 : ShowContinueError(state, "GlareControlIsActive = Yes and is in a Daylighting zone or enclosure");
4139 0 : ShowContinueError(state, "that shares an interior window with another Daylighting zone or enclosure");
4140 0 : ShowContinueError(state, "Adjacent Zone or Enclosure indicated=" + adjSurfEnclosure.Name);
4141 0 : ErrorsFound = true;
4142 : }
4143 : }
4144 : }
4145 : }
4146 : }
4147 :
4148 143 : if (state.dataSurface->WindowShadingControl(state.dataSurface->Surface(SurfNum).activeWindowShadingControl).shadingControlType ==
4149 : WindowShadingControlType::MeetDaylIlumSetp) {
4150 : // Error if window has shadingControlType = MeetDaylightingIlluminanceSetpoint &
4151 : // but is not in a Daylighting:Detailed zone
4152 2 : if (thisSurfEnclosure.TotalEnclosureDaylRefPoints == 0) {
4153 0 : ShowSevereError(state, "Window=" + state.dataSurface->Surface(SurfNum).Name + " has Window Shading Control with");
4154 0 : ShowContinueError(state, "MeetDaylightingIlluminanceSetpoint but it is not in a Daylighting zone or enclosure.");
4155 0 : ShowContinueError(state, "Zone or enclosure indicated=" + thisSurfEnclosure.Name);
4156 0 : ErrorsFound = true;
4157 : }
4158 : // Error if window has shadingControlType = MeetDaylightIlluminanceSetpoint and is in a &
4159 : // Daylighting:Detailed zone with an interior window adjacent to another Daylighting:Detailed zone
4160 2 : if (thisSurfEnclosure.TotalEnclosureDaylRefPoints > 0) {
4161 22 : for (int const intWin : thisSurfEnclosure.SurfacePtr) {
4162 20 : int const SurfNumAdj = state.dataSurface->Surface(intWin).ExtBoundCond;
4163 20 : if (state.dataSurface->Surface(intWin).Class == SurfaceClass::Window && SurfNumAdj > 0) {
4164 0 : auto &adjSurfEnclosure(state.dataViewFactor->EnclSolInfo(state.dataSurface->Surface(SurfNumAdj).SolarEnclIndex));
4165 0 : if (adjSurfEnclosure.TotalEnclosureDaylRefPoints > 0) {
4166 0 : ShowSevereError(state, "Window=" + state.dataSurface->Surface(SurfNum).Name + " has Window Shading Control with");
4167 0 : ShowContinueError(state, "MeetDaylightIlluminanceSetpoint and is in a Daylighting zone or enclosure");
4168 0 : ShowContinueError(state, "that shares an interior window with another Daylighting zone or enclosure");
4169 0 : ShowContinueError(state, "Adjacent Zone or enclosure indicated=" + adjSurfEnclosure.Name);
4170 0 : ErrorsFound = true;
4171 : }
4172 : }
4173 : }
4174 : }
4175 : }
4176 : }
4177 : }
4178 : }
4179 :
4180 771 : if (!state.dataHeatBal->AnyAirBoundary) {
4181 44365 : for (int SurfLoop = 1; SurfLoop <= state.dataSurface->TotSurfaces; ++SurfLoop) {
4182 43597 : if (state.dataSurface->Surface(SurfLoop).Class == SurfaceClass::Window && state.dataSurface->Surface(SurfLoop).ExtSolar) {
4183 5940 : int const enclOfSurf = state.dataSurface->Surface(SurfLoop).SolarEnclIndex;
4184 12716 : if (state.dataViewFactor->EnclSolInfo(enclOfSurf).TotalEnclosureDaylRefPoints > 0 &&
4185 6776 : !state.dataViewFactor->EnclSolInfo(enclOfSurf).HasInterZoneWindow &&
4186 836 : state.dataDaylightingData->enclDaylight(enclOfSurf).hasSplitFluxDaylighting) {
4187 2305 : for (int refPtNum = 1; refPtNum <= state.dataViewFactor->EnclSolInfo(enclOfSurf).TotalEnclosureDaylRefPoints; ++refPtNum) {
4188 7360 : SetupOutputVariable(state,
4189 2944 : format("Daylighting Window Reference Point {} Illuminance", refPtNum),
4190 : OutputProcessor::Unit::lux,
4191 2944 : state.dataSurface->SurfaceWindow(SurfLoop).IllumFromWinAtRefPtRep(refPtNum),
4192 : OutputProcessor::SOVTimeStepType::Zone,
4193 : OutputProcessor::SOVStoreType::Average,
4194 1472 : state.dataSurface->Surface(SurfLoop).Name);
4195 7360 : SetupOutputVariable(state,
4196 2944 : format("Daylighting Window Reference Point {} View Luminance", refPtNum),
4197 : OutputProcessor::Unit::cd_m2,
4198 2944 : state.dataSurface->SurfaceWindow(SurfLoop).LumWinFromRefPtRep(refPtNum),
4199 : OutputProcessor::SOVTimeStepType::Zone,
4200 : OutputProcessor::SOVStoreType::Average,
4201 1472 : state.dataSurface->Surface(SurfLoop).Name);
4202 : }
4203 : }
4204 : }
4205 : }
4206 : } else {
4207 18 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
4208 154 : for (int const enclSurfNum : state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr) {
4209 139 : if (state.dataSurface->Surface(enclSurfNum).Class == SurfaceClass::Window && state.dataSurface->Surface(enclSurfNum).ExtSolar) {
4210 39 : if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints > 0 &&
4211 21 : !state.dataViewFactor->EnclSolInfo(enclNum).HasInterZoneWindow &&
4212 3 : state.dataDaylightingData->enclDaylight(enclNum).hasSplitFluxDaylighting) {
4213 3 : int refPtCount = 0;
4214 9 : for (int controlNum : state.dataDaylightingData->enclDaylight(enclNum).daylightControlIndexes) {
4215 12 : for (int refPtNum = 1; refPtNum <= state.dataDaylightingData->daylightControl(controlNum).TotalDaylRefPoints;
4216 : ++refPtNum) {
4217 6 : ++refPtCount; // Count reference points across each daylighting control in the same enclosure
4218 : std::string const varKey =
4219 12 : state.dataSurface->Surface(enclSurfNum).Name + " to " +
4220 : state.dataDaylightingData
4221 6 : ->DaylRefPt(state.dataDaylightingData->daylightControl(controlNum).DaylRefPtNum(refPtNum))
4222 18 : .Name;
4223 12 : SetupOutputVariable(state,
4224 : "Daylighting Window Reference Point Illuminance",
4225 : OutputProcessor::Unit::lux,
4226 6 : state.dataSurface->SurfaceWindow(enclSurfNum).IllumFromWinAtRefPtRep(refPtCount),
4227 : OutputProcessor::SOVTimeStepType::Zone,
4228 : OutputProcessor::SOVStoreType::Average,
4229 6 : varKey);
4230 12 : SetupOutputVariable(state,
4231 : "Daylighting Window Reference Point View Luminance",
4232 : OutputProcessor::Unit::cd_m2,
4233 6 : state.dataSurface->SurfaceWindow(enclSurfNum).LumWinFromRefPtRep(refPtCount),
4234 : OutputProcessor::SOVTimeStepType::Zone,
4235 : OutputProcessor::SOVStoreType::Average,
4236 6 : varKey);
4237 : }
4238 : }
4239 : }
4240 : }
4241 : }
4242 : }
4243 : }
4244 :
4245 : // RJH DElight Modification Begin - Calls to DElight preprocessing subroutines
4246 771 : if (doesDayLightingUseDElight(state)) {
4247 3 : dLatitude = state.dataEnvrn->Latitude;
4248 3 : DisplayString(state, "Calculating DElight Daylighting Factors");
4249 3 : DElightInputGenerator(state);
4250 : // Init Error Flag to 0 (no Warnings or Errors)
4251 3 : DisplayString(state, "ReturnFrom DElightInputGenerator");
4252 3 : iErrorFlag = 0;
4253 3 : DisplayString(state, "Calculating DElight DaylightCoefficients");
4254 3 : GenerateDElightDaylightCoefficients(dLatitude, iErrorFlag);
4255 : // Check Error Flag for Warnings or Errors returning from DElight
4256 : // RJH 2008-03-07: open file for READWRITE and DELETE file after processing
4257 3 : DisplayString(state, "ReturnFrom DElight DaylightCoefficients Calc");
4258 3 : if (iErrorFlag != 0) {
4259 : // Open DElight Daylight Factors Error File for reading
4260 0 : auto iDElightErrorFile = state.files.outputDelightDfdmpFilePath.try_open(state.files.outputControl.delightdfdmp);
4261 :
4262 : // Sequentially read lines in DElight Daylight Factors Error File
4263 : // and process them using standard EPlus warning/error handling calls
4264 : // Process all error/warning messages first
4265 : // Then, if any error has occurred, ShowFatalError to terminate processing
4266 0 : bEndofErrFile = !iDElightErrorFile.good();
4267 0 : bRecordsOnErrFile = false;
4268 0 : while (!bEndofErrFile) {
4269 0 : auto cErrorLine = iDElightErrorFile.readLine();
4270 0 : if (cErrorLine.eof) {
4271 0 : bEndofErrFile = true;
4272 0 : continue;
4273 : }
4274 0 : bRecordsOnErrFile = true;
4275 : // Is the current line a Warning message?
4276 0 : if (has_prefix(cErrorLine.data, "WARNING: ")) {
4277 0 : cErrorMsg = cErrorLine.data.substr(9);
4278 0 : ShowWarningError(state, cErrorMsg);
4279 : }
4280 : // Is the current line an Error message?
4281 0 : if (has_prefix(cErrorLine.data, "ERROR: ")) {
4282 0 : cErrorMsg = cErrorLine.data.substr(7);
4283 0 : ShowSevereError(state, cErrorMsg);
4284 0 : iErrorFlag = 1;
4285 : }
4286 : }
4287 :
4288 : // Close and Delete DElight Error File
4289 0 : if (iDElightErrorFile.is_open()) {
4290 0 : iDElightErrorFile.close();
4291 0 : FileSystem::removeFile(iDElightErrorFile.filePath);
4292 : }
4293 :
4294 : // If any DElight Error occurred then ShowFatalError to terminate
4295 0 : if (iErrorFlag > 0) {
4296 0 : ErrorsFound = true;
4297 : }
4298 : } else {
4299 3 : if (FileSystem::fileExists(state.files.outputDelightDfdmpFilePath.filePath)) {
4300 3 : FileSystem::removeFile(state.files.outputDelightDfdmpFilePath.filePath);
4301 : }
4302 : }
4303 : }
4304 : // RJH DElight Modification End - Calls to DElight preprocessing subroutines
4305 :
4306 : // TH 6/3/2010, added to report daylight factors
4307 771 : cCurrentModuleObject = "Output:DaylightFactors";
4308 771 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
4309 771 : if (NumReports > 0) {
4310 7 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4311 : cCurrentModuleObject,
4312 : 1,
4313 1 : state.dataIPShortCut->cAlphaArgs,
4314 : NumNames,
4315 1 : state.dataIPShortCut->rNumericArgs,
4316 : NumNumbers,
4317 : IOStat,
4318 1 : state.dataIPShortCut->lNumericFieldBlanks,
4319 1 : state.dataIPShortCut->lAlphaFieldBlanks,
4320 1 : state.dataIPShortCut->cAlphaFieldNames,
4321 1 : state.dataIPShortCut->cNumericFieldNames);
4322 1 : if (has_prefix(state.dataIPShortCut->cAlphaArgs(1), "SIZINGDAYS")) {
4323 1 : state.dataDaylightingData->DFSReportSizingDays = true;
4324 0 : } else if (has_prefix(state.dataIPShortCut->cAlphaArgs(1), "ALLSHADOWCALCULATIONDAYS")) {
4325 0 : state.dataDaylightingData->DFSReportAllShadowCalculationDays = true;
4326 : }
4327 : }
4328 :
4329 771 : if (ErrorsFound) ShowFatalError(state, "Program terminated for above reasons");
4330 : }
4331 :
4332 62 : void GetInputIlluminanceMap(EnergyPlusData &state, bool &ErrorsFound)
4333 : {
4334 : // Perform the GetInput function for the Output:IlluminanceMap
4335 : // Glazer - June 2016 (moved from GetDaylightingControls)
4336 : using DataStringGlobals::CharComma;
4337 : using DataStringGlobals::CharSpace;
4338 : using DataStringGlobals::CharTab;
4339 :
4340 : int MapNum;
4341 : int IOStat;
4342 : int NumAlpha;
4343 : int NumNumber;
4344 : int MapStyleIn;
4345 : int AddMapPoints;
4346 : int RefPt;
4347 : int X;
4348 : int Y;
4349 : Real64 CosBldgRelNorth; // Cosine of Building rotation
4350 : Real64 SinBldgRelNorth; // Sine of Building rotation
4351 : Real64 CosZoneRelNorth; // Cosine of Zone rotation
4352 : Real64 SinZoneRelNorth; // Sine of Zone rotation
4353 62 : Real64 CosBldgRotAppGonly(0.0); // Cosine of the building rotation for appendix G only ( relative north )
4354 62 : Real64 SinBldgRotAppGonly(0.0); // Sine of the building rotation for appendix G only ( relative north )
4355 : Real64 Xb; // temp var for transformation calc
4356 : Real64 Yb; // temp var for transformation calc
4357 : Real64 Xo;
4358 : Real64 XnoRot;
4359 : Real64 Xtrans;
4360 : Real64 Yo;
4361 : Real64 YnoRot;
4362 : Real64 Ytrans;
4363 : bool doTransform;
4364 : Real64 OldAspectRatio;
4365 : Real64 NewAspectRatio;
4366 124 : Array1D_bool ZoneMsgDone;
4367 :
4368 62 : auto &Zone(state.dataHeatBal->Zone);
4369 :
4370 62 : CosBldgRelNorth =
4371 62 : std::cos(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * DataGlobalConstants::DegToRadians);
4372 62 : SinBldgRelNorth =
4373 62 : std::sin(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * DataGlobalConstants::DegToRadians);
4374 : // these are only for Building Rotation for Appendix G when using world coordinate system
4375 62 : CosBldgRotAppGonly = std::cos(-state.dataHeatBal->BuildingRotationAppendixG * DataGlobalConstants::DegToRadians);
4376 62 : SinBldgRotAppGonly = std::sin(-state.dataHeatBal->BuildingRotationAppendixG * DataGlobalConstants::DegToRadians);
4377 :
4378 62 : doTransform = false;
4379 62 : OldAspectRatio = 1.0;
4380 62 : NewAspectRatio = 1.0;
4381 :
4382 62 : CheckForGeometricTransform(state, doTransform, OldAspectRatio, NewAspectRatio);
4383 62 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
4384 62 : cCurrentModuleObject = "Output:IlluminanceMap";
4385 62 : int TotIllumMaps = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
4386 :
4387 62 : state.dataDaylightingData->IllumMap.allocate(TotIllumMaps);
4388 62 : state.dataDaylightingData->IllumMapCalc.allocate(TotIllumMaps);
4389 :
4390 62 : if (TotIllumMaps > 0) {
4391 12 : for (MapNum = 1; MapNum <= TotIllumMaps; ++MapNum) {
4392 49 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4393 : cCurrentModuleObject,
4394 : MapNum,
4395 7 : state.dataIPShortCut->cAlphaArgs,
4396 : NumAlpha,
4397 7 : state.dataIPShortCut->rNumericArgs,
4398 : NumNumber,
4399 : IOStat,
4400 7 : state.dataIPShortCut->lNumericFieldBlanks,
4401 7 : state.dataIPShortCut->lAlphaFieldBlanks,
4402 7 : state.dataIPShortCut->cAlphaFieldNames,
4403 7 : state.dataIPShortCut->cNumericFieldNames);
4404 7 : state.dataDaylightingData->IllumMap(MapNum).Name = state.dataIPShortCut->cAlphaArgs(1);
4405 7 : state.dataDaylightingData->IllumMap(MapNum).zoneIndex = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), Zone);
4406 :
4407 7 : if (state.dataDaylightingData->IllumMap(MapNum).zoneIndex == 0) {
4408 0 : ShowSevereError(state,
4409 0 : cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid " +
4410 0 : state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" + state.dataIPShortCut->cAlphaArgs(2) + "\".");
4411 0 : ErrorsFound = true;
4412 : } else {
4413 : // set enclosure index for first space in zone
4414 7 : int zoneNum = state.dataDaylightingData->IllumMap(MapNum).zoneIndex;
4415 7 : int enclNum = state.dataHeatBal->space(state.dataHeatBal->Zone(zoneNum).spaceIndexes(1)).solarEnclosureNum;
4416 7 : state.dataDaylightingData->IllumMap(MapNum).enclIndex = enclNum;
4417 : // check that all spaces in the zone are in the same enclosure
4418 7 : for (int spaceCounter = 2; spaceCounter <= state.dataHeatBal->Zone(zoneNum).numSpaces; ++spaceCounter) {
4419 0 : int spaceNum = state.dataHeatBal->Zone(zoneNum).spaceIndexes(spaceCounter);
4420 0 : if (enclNum != state.dataHeatBal->space(spaceNum).solarEnclosureNum) {
4421 0 : ShowSevereError(state,
4422 0 : cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
4423 : "\" All spaces in the zone must be in the same enclosure for daylighting illuminance maps.");
4424 0 : ErrorsFound = true;
4425 0 : break;
4426 : }
4427 : }
4428 : }
4429 :
4430 7 : state.dataDaylightingData->IllumMapCalc(MapNum).zoneIndex = state.dataDaylightingData->IllumMap(MapNum).zoneIndex;
4431 7 : state.dataDaylightingData->IllumMapCalc(MapNum).enclIndex = state.dataDaylightingData->IllumMap(MapNum).enclIndex;
4432 7 : state.dataDaylightingData->IllumMap(MapNum).Z = state.dataIPShortCut->rNumericArgs(1);
4433 :
4434 7 : state.dataDaylightingData->IllumMap(MapNum).Xmin = state.dataIPShortCut->rNumericArgs(2);
4435 7 : state.dataDaylightingData->IllumMap(MapNum).Xmax = state.dataIPShortCut->rNumericArgs(3);
4436 7 : if (state.dataIPShortCut->rNumericArgs(2) > state.dataIPShortCut->rNumericArgs(3)) {
4437 0 : ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid entry.");
4438 0 : ShowContinueError(state,
4439 0 : format("...{} {:.2R} must be <= {} {:.2R}.",
4440 0 : state.dataIPShortCut->cNumericFieldNames(2),
4441 0 : state.dataIPShortCut->rNumericArgs(2),
4442 0 : state.dataIPShortCut->cNumericFieldNames(3),
4443 0 : state.dataIPShortCut->rNumericArgs(3)));
4444 0 : ErrorsFound = true;
4445 : }
4446 7 : state.dataDaylightingData->IllumMap(MapNum).Xnum = state.dataIPShortCut->rNumericArgs(4);
4447 7 : if (state.dataDaylightingData->IllumMap(MapNum).Xnum != 1) {
4448 7 : state.dataDaylightingData->IllumMap(MapNum).Xinc =
4449 14 : (state.dataDaylightingData->IllumMap(MapNum).Xmax - state.dataDaylightingData->IllumMap(MapNum).Xmin) /
4450 7 : (state.dataDaylightingData->IllumMap(MapNum).Xnum - 1);
4451 : } else {
4452 0 : state.dataDaylightingData->IllumMap(MapNum).Xinc = 0.0;
4453 : }
4454 :
4455 7 : state.dataDaylightingData->IllumMap(MapNum).Ymin = state.dataIPShortCut->rNumericArgs(5);
4456 7 : state.dataDaylightingData->IllumMap(MapNum).Ymax = state.dataIPShortCut->rNumericArgs(6);
4457 7 : if (state.dataIPShortCut->rNumericArgs(5) > state.dataIPShortCut->rNumericArgs(6)) {
4458 0 : ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid entry.");
4459 0 : ShowContinueError(state,
4460 0 : format("...{} {:.2R} must be <= {} {:.2R}.",
4461 0 : state.dataIPShortCut->cNumericFieldNames(5),
4462 0 : state.dataIPShortCut->rNumericArgs(5),
4463 0 : state.dataIPShortCut->cNumericFieldNames(6),
4464 0 : state.dataIPShortCut->rNumericArgs(6)));
4465 0 : ErrorsFound = true;
4466 : }
4467 7 : state.dataDaylightingData->IllumMap(MapNum).Ynum = state.dataIPShortCut->rNumericArgs(7);
4468 7 : if (state.dataDaylightingData->IllumMap(MapNum).Ynum != 1) {
4469 7 : state.dataDaylightingData->IllumMap(MapNum).Yinc =
4470 14 : (state.dataDaylightingData->IllumMap(MapNum).Ymax - state.dataDaylightingData->IllumMap(MapNum).Ymin) /
4471 7 : (state.dataDaylightingData->IllumMap(MapNum).Ynum - 1);
4472 : } else {
4473 0 : state.dataDaylightingData->IllumMap(MapNum).Yinc = 0.0;
4474 : }
4475 7 : if (state.dataDaylightingData->IllumMap(MapNum).Xnum * state.dataDaylightingData->IllumMap(MapNum).Ynum >
4476 : DataDaylighting::MaxMapRefPoints) {
4477 0 : ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", too many map points specified.");
4478 0 : ShowContinueError(state,
4479 0 : format("...{}[{}] * {}[{}].= [{}] must be <= [{}].",
4480 0 : state.dataIPShortCut->cNumericFieldNames(4),
4481 0 : state.dataDaylightingData->IllumMap(MapNum).Xnum,
4482 0 : state.dataIPShortCut->cNumericFieldNames(7),
4483 0 : state.dataDaylightingData->IllumMap(MapNum).Ynum,
4484 0 : state.dataDaylightingData->IllumMap(MapNum).Xnum * state.dataDaylightingData->IllumMap(MapNum).Ynum,
4485 0 : DataDaylighting::MaxMapRefPoints));
4486 0 : ErrorsFound = true;
4487 : }
4488 : } // MapNum
4489 5 : cCurrentModuleObject = "OutputControl:IlluminanceMap:Style";
4490 5 : MapStyleIn = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
4491 :
4492 5 : if (MapStyleIn == 0) {
4493 4 : state.dataIPShortCut->cAlphaArgs(1) = "COMMA";
4494 4 : state.dataDaylightingData->MapColSep = CharComma; // comma
4495 1 : } else if (MapStyleIn == 1) {
4496 7 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4497 : cCurrentModuleObject,
4498 : 1,
4499 1 : state.dataIPShortCut->cAlphaArgs,
4500 : NumAlpha,
4501 1 : state.dataIPShortCut->rNumericArgs,
4502 : NumNumber,
4503 : IOStat,
4504 1 : state.dataIPShortCut->lNumericFieldBlanks,
4505 1 : state.dataIPShortCut->lAlphaFieldBlanks,
4506 1 : state.dataIPShortCut->cAlphaFieldNames,
4507 1 : state.dataIPShortCut->cNumericFieldNames);
4508 1 : if (state.dataIPShortCut->cAlphaArgs(1) == "COMMA") {
4509 1 : state.dataDaylightingData->MapColSep = CharComma; // comma
4510 0 : } else if (state.dataIPShortCut->cAlphaArgs(1) == "TAB") {
4511 0 : state.dataDaylightingData->MapColSep = CharTab; // tab
4512 0 : } else if (state.dataIPShortCut->cAlphaArgs(1) == "FIXED" || state.dataIPShortCut->cAlphaArgs(1) == "SPACE") {
4513 0 : state.dataDaylightingData->MapColSep = CharSpace; // space
4514 : } else {
4515 0 : state.dataDaylightingData->MapColSep = CharComma; // comma
4516 0 : ShowWarningError(state,
4517 0 : cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" +
4518 0 : state.dataIPShortCut->cAlphaArgs(1) + "\", Commas will be used to separate fields.");
4519 0 : state.dataIPShortCut->cAlphaArgs(1) = "COMMA";
4520 : }
4521 : }
4522 5 : print(state.files.eio, "! <Daylighting:Illuminance Maps>,#Maps,Style\n");
4523 5 : ConvertCaseToLower(state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cAlphaArgs(2));
4524 5 : state.dataIPShortCut->cAlphaArgs(1).erase(1);
4525 5 : state.dataIPShortCut->cAlphaArgs(1) += state.dataIPShortCut->cAlphaArgs(2).substr(1);
4526 5 : print(state.files.eio, "Daylighting:Illuminance Maps,{},{}\n", TotIllumMaps, state.dataIPShortCut->cAlphaArgs(1));
4527 : }
4528 :
4529 : // Check for illuminance maps associated with this zone
4530 69 : for (MapNum = 1; MapNum <= TotIllumMaps; ++MapNum) {
4531 7 : if (state.dataDaylightingData->IllumMap(MapNum).zoneIndex > 0) {
4532 7 : auto &zone(Zone(state.dataDaylightingData->IllumMap(MapNum).zoneIndex));
4533 : // Calc cos and sin of Zone Relative North values for later use in transforming Reference Point coordinates
4534 7 : CosZoneRelNorth = std::cos(-zone.RelNorth * DataGlobalConstants::DegToRadians);
4535 7 : SinZoneRelNorth = std::sin(-zone.RelNorth * DataGlobalConstants::DegToRadians);
4536 7 : if (state.dataDaylightingData->IllumMap(MapNum).Xnum * state.dataDaylightingData->IllumMap(MapNum).Ynum > 0) {
4537 : // Add additional daylighting reference points for map
4538 7 : AddMapPoints = state.dataDaylightingData->IllumMap(MapNum).Xnum * state.dataDaylightingData->IllumMap(MapNum).Ynum;
4539 7 : state.dataDaylightingData->IllumMapCalc(MapNum).TotalMapRefPoints = AddMapPoints;
4540 7 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord.allocate(3, AddMapPoints);
4541 7 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord = 0.0;
4542 7 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds.allocate(AddMapPoints);
4543 7 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds = true;
4544 7 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPt.allocate(AddMapPoints);
4545 7 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPt = 0.0;
4546 7 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPtHr.allocate(AddMapPoints);
4547 7 : state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPtHr = 0.0;
4548 :
4549 7 : if (AddMapPoints > DataDaylighting::MaxMapRefPoints) {
4550 0 : ShowSevereError(state, "GetDaylighting Parameters: Total Map Reference points entered is greater than maximum allowed.");
4551 0 : ShowContinueError(state, "Occurs in Zone=" + zone.Name);
4552 0 : ShowContinueError(state,
4553 0 : format("Maximum reference points allowed={}, entered amount ( when error first occurred )={}",
4554 : DataDaylighting::MaxMapRefPoints,
4555 0 : AddMapPoints));
4556 0 : ErrorsFound = true;
4557 0 : break;
4558 : }
4559 7 : RefPt = 1;
4560 : // Calc cos and sin of Zone Relative North values for later use in transforming Map Point coordinates
4561 : // CosZoneRelNorth = std::cos( -zone.RelNorth * DegToRadians ); //Tuned These should not be changing
4562 : // SinZoneRelNorth = std::sin( -zone.RelNorth * DegToRadians );
4563 7 : if (state.dataDaylightingData->IllumMap(MapNum).Xnum != 1) {
4564 7 : state.dataDaylightingData->IllumMap(MapNum).Xinc =
4565 14 : (state.dataDaylightingData->IllumMap(MapNum).Xmax - state.dataDaylightingData->IllumMap(MapNum).Xmin) /
4566 7 : (state.dataDaylightingData->IllumMap(MapNum).Xnum - 1);
4567 : } else {
4568 0 : state.dataDaylightingData->IllumMap(MapNum).Xinc = 0.0;
4569 : }
4570 7 : if (state.dataDaylightingData->IllumMap(MapNum).Ynum != 1) {
4571 7 : state.dataDaylightingData->IllumMap(MapNum).Yinc =
4572 14 : (state.dataDaylightingData->IllumMap(MapNum).Ymax - state.dataDaylightingData->IllumMap(MapNum).Ymin) /
4573 7 : (state.dataDaylightingData->IllumMap(MapNum).Ynum - 1);
4574 : } else {
4575 0 : state.dataDaylightingData->IllumMap(MapNum).Yinc = 0.0;
4576 : }
4577 :
4578 : // Map points and increments are stored in AbsCoord and then that is operated on if relative coords entered.
4579 77 : for (Y = 1; Y <= state.dataDaylightingData->IllumMap(MapNum).Ynum; ++Y) {
4580 620 : for (X = 1; X <= state.dataDaylightingData->IllumMap(MapNum).Xnum; ++X) {
4581 550 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) =
4582 550 : state.dataDaylightingData->IllumMap(MapNum).Xmin + (X - 1) * state.dataDaylightingData->IllumMap(MapNum).Xinc;
4583 550 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) =
4584 550 : state.dataDaylightingData->IllumMap(MapNum).Ymin + (Y - 1) * state.dataDaylightingData->IllumMap(MapNum).Yinc;
4585 550 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) = state.dataDaylightingData->IllumMap(MapNum).Z;
4586 550 : ++RefPt;
4587 : }
4588 : }
4589 7 : RefPt = 1;
4590 77 : for (Y = 1; Y <= state.dataDaylightingData->IllumMap(MapNum).Ynum; ++Y) {
4591 620 : for (X = 1; X <= state.dataDaylightingData->IllumMap(MapNum).Xnum; ++X) {
4592 550 : if (!state.dataSurface->DaylRefWorldCoordSystem) {
4593 1050 : Xb = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) * CosZoneRelNorth -
4594 700 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) * SinZoneRelNorth + zone.OriginX;
4595 1050 : Yb = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) * SinZoneRelNorth +
4596 700 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) * CosZoneRelNorth + zone.OriginY;
4597 350 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) = Xb * CosBldgRelNorth - Yb * SinBldgRelNorth;
4598 350 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) = Xb * SinBldgRelNorth + Yb * CosBldgRelNorth;
4599 350 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) += zone.OriginZ;
4600 350 : if (doTransform) {
4601 0 : Xo = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(
4602 0 : 1, RefPt); // world coordinates.... shifted by relative north angle...
4603 0 : Yo = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt);
4604 : // next derotate the building
4605 0 : XnoRot = Xo * CosBldgRelNorth + Yo * SinBldgRelNorth;
4606 0 : YnoRot = Yo * CosBldgRelNorth - Xo * SinBldgRelNorth;
4607 : // translate
4608 0 : Xtrans = XnoRot * std::sqrt(NewAspectRatio / OldAspectRatio);
4609 0 : Ytrans = YnoRot * std::sqrt(OldAspectRatio / NewAspectRatio);
4610 : // rerotate
4611 0 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) =
4612 0 : Xtrans * CosBldgRelNorth - Ytrans * SinBldgRelNorth;
4613 :
4614 0 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) =
4615 0 : Xtrans * SinBldgRelNorth + Ytrans * CosBldgRelNorth;
4616 : }
4617 : } else {
4618 200 : Xb = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt);
4619 200 : Yb = state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt);
4620 200 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) =
4621 200 : Xb * CosBldgRotAppGonly - Yb * SinBldgRotAppGonly;
4622 200 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) =
4623 200 : Xb * SinBldgRotAppGonly + Yb * CosBldgRotAppGonly;
4624 : }
4625 550 : if (RefPt == 1) {
4626 7 : state.dataDaylightingData->IllumMap(MapNum).Xmin =
4627 7 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt);
4628 7 : state.dataDaylightingData->IllumMap(MapNum).Ymin =
4629 7 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt);
4630 7 : state.dataDaylightingData->IllumMap(MapNum).Xmax =
4631 7 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt);
4632 7 : state.dataDaylightingData->IllumMap(MapNum).Ymax =
4633 7 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt);
4634 7 : state.dataDaylightingData->IllumMap(MapNum).Z =
4635 7 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt);
4636 : }
4637 550 : state.dataDaylightingData->IllumMap(MapNum).Xmin =
4638 550 : min(state.dataDaylightingData->IllumMap(MapNum).Xmin,
4639 550 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt));
4640 550 : state.dataDaylightingData->IllumMap(MapNum).Ymin =
4641 550 : min(state.dataDaylightingData->IllumMap(MapNum).Ymin,
4642 550 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt));
4643 550 : state.dataDaylightingData->IllumMap(MapNum).Xmax =
4644 550 : max(state.dataDaylightingData->IllumMap(MapNum).Xmax,
4645 550 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt));
4646 550 : state.dataDaylightingData->IllumMap(MapNum).Ymax =
4647 550 : max(state.dataDaylightingData->IllumMap(MapNum).Ymax,
4648 550 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt));
4649 1100 : if ((state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) < zone.MinimumX &&
4650 550 : (zone.MinimumX - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt)) > 0.001) ||
4651 550 : (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) > zone.MaximumX &&
4652 550 : (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) - zone.MaximumX) > 0.001) ||
4653 550 : (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) < zone.MinimumY &&
4654 550 : (zone.MinimumY - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt)) > 0.001) ||
4655 550 : (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) > zone.MaximumY &&
4656 550 : (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) - zone.MaximumY) > 0.001) ||
4657 550 : (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) < zone.MinimumZ &&
4658 1100 : (zone.MinimumZ - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt)) > 0.001) ||
4659 550 : (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) > zone.MaximumZ &&
4660 0 : (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) - zone.MaximumZ) > 0.001)) {
4661 0 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(RefPt) = false;
4662 : }
4663 : // Test extremes of Map Points against Zone Min/Max
4664 550 : if (RefPt == 1 || RefPt == state.dataDaylightingData->IllumMapCalc(MapNum).TotalMapRefPoints) {
4665 42 : if ((state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) < zone.MinimumX ||
4666 14 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) > zone.MaximumX) &&
4667 0 : !state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(RefPt)) {
4668 0 : ShowWarningError(state,
4669 0 : format("GetInputIlluminanceMap: Reference Map point #[{}], X Value outside Zone Min/Max X, Zone={}",
4670 : RefPt,
4671 0 : zone.Name));
4672 0 : ShowContinueError(state,
4673 0 : format("...X Reference Point= {:.2R}, Zone Minimum X= {:.2R}, Zone Maximum X= {:.2R}",
4674 0 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt),
4675 : zone.MinimumX,
4676 0 : zone.MaximumX));
4677 0 : if (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) < zone.MinimumX) {
4678 0 : ShowContinueError(
4679 : state,
4680 0 : format("...X Reference Distance Outside MinimumX= {:.4R} m.",
4681 0 : zone.MinimumX - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt)));
4682 : } else {
4683 0 : ShowContinueError(
4684 : state,
4685 0 : format("...X Reference Distance Outside MaximumX= {:.4R} m.",
4686 0 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt) - zone.MaximumX));
4687 : }
4688 : }
4689 42 : if ((state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) < zone.MinimumY ||
4690 14 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) > zone.MaximumY) &&
4691 0 : !state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(RefPt)) {
4692 0 : ShowWarningError(state,
4693 0 : format("GetInputIlluminanceMap: Reference Map point #[{}], Y Value outside Zone Min/Max Y, Zone={}",
4694 : RefPt,
4695 0 : zone.Name));
4696 0 : ShowContinueError(state,
4697 0 : format("...Y Reference Point= {:.2R}, Zone Minimum Y= {:.2R}, Zone Maximum Y= {:.2R}",
4698 0 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt),
4699 : zone.MinimumY,
4700 0 : zone.MaximumY));
4701 0 : if (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) < zone.MinimumY) {
4702 0 : ShowContinueError(
4703 : state,
4704 0 : format("...Y Reference Distance Outside MinimumY= {:.4R} m.",
4705 0 : zone.MinimumY - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt)));
4706 : } else {
4707 0 : ShowContinueError(
4708 : state,
4709 0 : format("...Y Reference Distance Outside MaximumY= {:.4R} m.",
4710 0 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt) - zone.MaximumY));
4711 : }
4712 : }
4713 42 : if ((state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) < zone.MinimumZ ||
4714 14 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) > zone.MaximumZ) &&
4715 0 : !state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(RefPt)) {
4716 0 : ShowWarningError(state,
4717 0 : format("GetInputIlluminanceMap: Reference Map point #[{}], Z Value outside Zone Min/Max Z, Zone={}",
4718 : RefPt,
4719 0 : zone.Name));
4720 0 : ShowContinueError(state,
4721 0 : format("...Z Reference Point= {:.2R}, Zone Minimum Z= {:.2R}, Zone Maximum Z= {:.2R}",
4722 0 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt),
4723 : zone.MinimumZ,
4724 0 : zone.MaximumZ));
4725 0 : if (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) < zone.MinimumZ) {
4726 0 : ShowContinueError(
4727 : state,
4728 0 : format("...Z Reference Distance Outside MinimumZ= {:.4R} m.",
4729 0 : zone.MinimumZ - state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt)));
4730 : } else {
4731 0 : ShowContinueError(
4732 : state,
4733 0 : format("...Z Reference Distance Outside MaximumZ= {:.4R} m.",
4734 0 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(3, RefPt) - zone.MaximumZ));
4735 : }
4736 : }
4737 : }
4738 550 : ++RefPt;
4739 : } // X
4740 : } // Y
4741 : }
4742 : }
4743 : } // MapNum
4744 62 : ZoneMsgDone.dimension(state.dataGlobal->NumOfZones, false);
4745 69 : for (MapNum = 1; MapNum <= TotIllumMaps; ++MapNum) {
4746 7 : if (state.dataDaylightingData->IllumMap(MapNum).zoneIndex == 0) continue;
4747 7 : int enclNum = state.dataDaylightingData->IllumMap(MapNum).enclIndex;
4748 7 : if (!state.dataDaylightingData->enclDaylight(enclNum).hasSplitFluxDaylighting &&
4749 0 : !ZoneMsgDone(state.dataDaylightingData->IllumMap(MapNum).zoneIndex)) {
4750 0 : ShowSevereError(state,
4751 0 : "Zone Name in Output:IlluminanceMap is not used for Daylighting:Controls=" +
4752 0 : Zone(state.dataDaylightingData->IllumMap(MapNum).zoneIndex).Name);
4753 0 : ErrorsFound = true;
4754 : }
4755 : }
4756 62 : ZoneMsgDone.deallocate();
4757 :
4758 62 : if (TotIllumMaps > 0) {
4759 5 : print(state.files.eio,
4760 : "! <Daylighting:Illuminance Maps:Detail>,Name,Zone,XMin {{m}},XMax {{m}},Xinc {{m}},#X Points,YMin "
4761 5 : "{{m}},YMax {{m}},Yinc {{m}},#Y Points,Z {{m}}\n");
4762 : }
4763 69 : for (MapNum = 1; MapNum <= TotIllumMaps; ++MapNum) {
4764 84 : print(state.files.eio,
4765 : "Daylighting:Illuminance Maps:Detail,{},{},{:.2R},{:.2R},{:.2R},{},{:.2R},{:.2R},{:.2R},{},{:.2R}\n",
4766 7 : state.dataDaylightingData->IllumMap(MapNum).Name,
4767 7 : Zone(state.dataDaylightingData->IllumMap(MapNum).zoneIndex).Name,
4768 7 : state.dataDaylightingData->IllumMap(MapNum).Xmin,
4769 7 : state.dataDaylightingData->IllumMap(MapNum).Xmax,
4770 7 : state.dataDaylightingData->IllumMap(MapNum).Xinc,
4771 7 : state.dataDaylightingData->IllumMap(MapNum).Xnum,
4772 7 : state.dataDaylightingData->IllumMap(MapNum).Ymin,
4773 7 : state.dataDaylightingData->IllumMap(MapNum).Ymax,
4774 7 : state.dataDaylightingData->IllumMap(MapNum).Yinc,
4775 7 : state.dataDaylightingData->IllumMap(MapNum).Ynum,
4776 14 : state.dataDaylightingData->IllumMap(MapNum).Z);
4777 : }
4778 :
4779 62 : if (ErrorsFound) return;
4780 : }
4781 :
4782 62 : void GetDaylightingControls(EnergyPlusData &state, bool &ErrorsFound)
4783 : {
4784 : // AUTHOR Fred Winkelmann
4785 : // DATE WRITTEN March 2002
4786 : // MODIFIED Glazer - July 2016 - Move geometry transformation portion, rearrange input, allow more than three reference points
4787 : // Obtain the user input data for Daylighting:Controls object in the input file.
4788 :
4789 : int IOStat;
4790 : int NumAlpha;
4791 : int NumNumber;
4792 :
4793 : // Smallest deviation from unity for the sum of all fractions
4794 : // Accept approx 4 to 8 ULP error (technically abs(1.0 + sumFracs) should be close to 2)
4795 : // constexpr Real64 FractionTolerance(4 * std::numeric_limits<Real64>::epsilon());
4796 : // Instead, we use a 0.001 = 0.1% tolerance
4797 62 : constexpr Real64 FractionTolerance(0.001);
4798 62 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
4799 62 : cCurrentModuleObject = "Daylighting:Controls";
4800 62 : int totDaylightingControls = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
4801 62 : state.dataDaylightingData->daylightControl.allocate(totDaylightingControls);
4802 124 : Array1D<bool> spaceHasDaylightingControl;
4803 62 : spaceHasDaylightingControl.dimension(state.dataGlobal->numSpaces, false);
4804 : // Reset to zero in case this is called more than once in unit tests
4805 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
4806 708 : state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints = 0;
4807 : }
4808 349 : for (int controlNum = 1; controlNum <= totDaylightingControls; ++controlNum) {
4809 287 : state.dataIPShortCut->cAlphaArgs = "";
4810 287 : state.dataIPShortCut->rNumericArgs = 0.0;
4811 2009 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
4812 : cCurrentModuleObject,
4813 : controlNum,
4814 287 : state.dataIPShortCut->cAlphaArgs,
4815 : NumAlpha,
4816 287 : state.dataIPShortCut->rNumericArgs,
4817 : NumNumber,
4818 : IOStat,
4819 287 : state.dataIPShortCut->lNumericFieldBlanks,
4820 287 : state.dataIPShortCut->lAlphaFieldBlanks,
4821 287 : state.dataIPShortCut->cAlphaFieldNames,
4822 287 : state.dataIPShortCut->cNumericFieldNames);
4823 287 : auto &daylightControl(state.dataDaylightingData->daylightControl(controlNum));
4824 287 : daylightControl.Name = state.dataIPShortCut->cAlphaArgs(1);
4825 :
4826 : // Is it a space or zone name?
4827 287 : int const spaceNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->space);
4828 287 : if (spaceNum > 0) {
4829 287 : daylightControl.spaceIndex = spaceNum;
4830 287 : daylightControl.zoneIndex = state.dataHeatBal->space(spaceNum).zoneNum;
4831 287 : daylightControl.enclIndex = state.dataHeatBal->space(spaceNum).solarEnclosureNum;
4832 : // Check if this is a duplicate
4833 287 : if (spaceHasDaylightingControl(spaceNum)) {
4834 0 : ShowSevereError(state,
4835 0 : cCurrentModuleObject + "=\"" + daylightControl.Name + "\" Space=" + "=\"" + state.dataHeatBal->space(spaceNum).Name +
4836 0 : "\" already has a " + cCurrentModuleObject + " object assigned to it. Only one per Space is allowed.");
4837 0 : ErrorsFound = true;
4838 0 : continue;
4839 : }
4840 : } else {
4841 0 : int const zoneNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->Zone);
4842 0 : if (zoneNum == 0) {
4843 0 : ShowSevereError(state,
4844 0 : cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" +
4845 0 : state.dataIPShortCut->cAlphaArgs(2) + "\".");
4846 0 : ErrorsFound = true;
4847 0 : continue;
4848 : } else {
4849 0 : daylightControl.zoneIndex = zoneNum;
4850 :
4851 : // set enclosure index for first space in zone
4852 0 : int enclNum = state.dataHeatBal->space(state.dataHeatBal->Zone(zoneNum).spaceIndexes(1)).solarEnclosureNum;
4853 0 : daylightControl.enclIndex = enclNum;
4854 : // check that all spaces in the zone are in the same enclosure
4855 0 : for (int spaceCounter = 2; spaceCounter <= state.dataHeatBal->Zone(zoneNum).numSpaces; ++spaceCounter) {
4856 0 : int zoneSpaceNum = state.dataHeatBal->Zone(zoneNum).spaceIndexes(spaceCounter);
4857 0 : if (daylightControl.enclIndex != state.dataHeatBal->space(zoneSpaceNum).solarEnclosureNum) {
4858 0 : ShowSevereError(state,
4859 0 : cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" +
4860 0 : state.dataIPShortCut->cAlphaArgs(2) +
4861 : "\" All spaces in the zone must be in the same enclosure for daylighting.");
4862 0 : ErrorsFound = true;
4863 0 : break;
4864 : }
4865 : // Check if this is a duplicate
4866 0 : if (spaceHasDaylightingControl(zoneSpaceNum)) {
4867 0 : ShowSevereError(state,
4868 0 : cCurrentModuleObject + "=\"" + daylightControl.Name + "\" Space=" + "=\"" +
4869 0 : state.dataHeatBal->space(zoneSpaceNum).Name + "\" already has a " + cCurrentModuleObject +
4870 : " object assigned to it. Only one per Space is allowed.");
4871 0 : ErrorsFound = true;
4872 0 : continue;
4873 : }
4874 : }
4875 : }
4876 : }
4877 :
4878 287 : state.dataDaylightingData->enclDaylight(daylightControl.enclIndex).daylightControlIndexes.emplace_back(controlNum);
4879 287 : daylightControl.ZoneName = state.dataHeatBal->Zone(daylightControl.zoneIndex).Name;
4880 :
4881 287 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(3), "SPLITFLUX")) { // Field: Daylighting Method
4882 284 : daylightControl.DaylightMethod = DataDaylighting::DaylightingMethod::SplitFlux;
4883 284 : state.dataDaylightingData->enclDaylight(daylightControl.enclIndex).hasSplitFluxDaylighting = true;
4884 3 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(3), "DELIGHT")) {
4885 3 : daylightControl.DaylightMethod = DataDaylighting::DaylightingMethod::DElight;
4886 0 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
4887 0 : daylightControl.DaylightMethod = DataDaylighting::DaylightingMethod::SplitFlux;
4888 0 : state.dataDaylightingData->enclDaylight(daylightControl.enclIndex).hasSplitFluxDaylighting = true;
4889 : } else {
4890 0 : ShowWarningError(state,
4891 0 : "Invalid " + state.dataIPShortCut->cAlphaFieldNames(3) + " = " + state.dataIPShortCut->cAlphaArgs(3) + ", occurs in " +
4892 0 : cCurrentModuleObject + "object for " + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1));
4893 0 : ShowContinueError(state, "SplitFlux assumed, and the simulation continues.");
4894 : }
4895 :
4896 287 : if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) { // Field: Availability Schedule Name
4897 5 : daylightControl.AvailSchedNum = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(4));
4898 5 : if (daylightControl.AvailSchedNum == 0) {
4899 0 : ShowWarningError(state,
4900 0 : "Invalid " + state.dataIPShortCut->cAlphaFieldNames(4) + " = " + state.dataIPShortCut->cAlphaArgs(4) +
4901 0 : ", occurs in " + cCurrentModuleObject + "object for " + cCurrentModuleObject + "=\"" +
4902 0 : state.dataIPShortCut->cAlphaArgs(1));
4903 0 : ShowContinueError(state, "Schedule was not found so controls will always be available, and the simulation continues.");
4904 0 : daylightControl.AvailSchedNum = DataGlobalConstants::ScheduleAlwaysOn;
4905 : }
4906 : } else {
4907 282 : daylightControl.AvailSchedNum = DataGlobalConstants::ScheduleAlwaysOn;
4908 : }
4909 :
4910 287 : int typeNum = getEnumerationValue(DataDaylighting::LtgCtrlTypeNamesUC, UtilityRoutines::MakeUPPERCase(state.dataIPShortCut->cAlphaArgs(5)));
4911 287 : daylightControl.LightControlType = static_cast<DataDaylighting::LtgCtrlType>(typeNum);
4912 287 : if (daylightControl.LightControlType == DataDaylighting::LtgCtrlType::Invalid) {
4913 0 : ShowWarningError(state,
4914 0 : "Invalid " + state.dataIPShortCut->cAlphaFieldNames(5) + " = " + state.dataIPShortCut->cAlphaArgs(5) + ", occurs in " +
4915 0 : cCurrentModuleObject + "object for " + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1));
4916 0 : ShowContinueError(state, "Continuous assumed, and the simulation continues.");
4917 : }
4918 :
4919 287 : daylightControl.MinPowerFraction =
4920 287 : state.dataIPShortCut->rNumericArgs(1); // Field: Minimum Input Power Fraction for Continuous Dimming Control
4921 287 : daylightControl.MinLightFraction =
4922 287 : state.dataIPShortCut->rNumericArgs(2); // Field: Minimum Light Output Fraction for Continuous Dimming Control
4923 287 : daylightControl.LightControlSteps = state.dataIPShortCut->rNumericArgs(3); // Field: Number of Stepped Control Steps
4924 287 : daylightControl.LightControlProbability =
4925 287 : state.dataIPShortCut->rNumericArgs(4); // Field: Probability Lighting will be Reset When Needed in Manual Stepped Control
4926 :
4927 287 : if (!state.dataIPShortCut->lAlphaFieldBlanks(6)) { // Field: Glare Calculation Daylighting Reference Point Name
4928 284 : daylightControl.glareRefPtNumber =
4929 284 : UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(6),
4930 284 : state.dataDaylightingData->DaylRefPt,
4931 : &DataDaylighting::RefPointData::Name); // Field: Glare Calculation Daylighting Reference Point Name
4932 284 : if (daylightControl.glareRefPtNumber == 0) {
4933 0 : ShowSevereError(state,
4934 0 : cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(6) + "=\"" +
4935 0 : state.dataIPShortCut->cAlphaArgs(6) + "\" for object named: " + state.dataIPShortCut->cAlphaArgs(1));
4936 0 : ErrorsFound = true;
4937 0 : continue;
4938 : }
4939 3 : } else if (daylightControl.DaylightMethod == DataDaylighting::DaylightingMethod::SplitFlux) {
4940 0 : ShowWarningError(
4941 0 : state, "No " + state.dataIPShortCut->cAlphaFieldNames(6) + " provided for object named: " + state.dataIPShortCut->cAlphaArgs(1));
4942 0 : ShowContinueError(state, "No glare calculation performed, and the simulation continues.");
4943 : }
4944 :
4945 287 : if (!state.dataIPShortCut->lNumericFieldBlanks(5)) {
4946 285 : daylightControl.ViewAzimuthForGlare =
4947 285 : state.dataIPShortCut->rNumericArgs(5); // Field: Glare Calculation Azimuth Angle of View Direction Clockwise from Zone y-Axis
4948 : } else {
4949 2 : daylightControl.ViewAzimuthForGlare = 0.;
4950 : }
4951 :
4952 287 : daylightControl.MaxGlareallowed = state.dataIPShortCut->rNumericArgs(6); // Field: Maximum Allowable Discomfort Glare Index
4953 287 : daylightControl.DElightGriddingResolution = state.dataIPShortCut->rNumericArgs(7); // Field: DElight Gridding Resolution
4954 :
4955 287 : int curTotalDaylRefPts = NumAlpha - 6; // first six alpha fields are not part of extensible group
4956 287 : daylightControl.TotalDaylRefPoints = curTotalDaylRefPts;
4957 287 : state.dataViewFactor->EnclSolInfo(daylightControl.enclIndex).TotalEnclosureDaylRefPoints += curTotalDaylRefPts;
4958 287 : state.dataDaylightingData->ZoneDaylight(daylightControl.zoneIndex).totRefPts += curTotalDaylRefPts;
4959 287 : state.dataDaylightingData->maxRefPointsPerControl = max(state.dataDaylightingData->maxRefPointsPerControl, curTotalDaylRefPts);
4960 287 : if ((NumNumber - 7) / 2 != daylightControl.TotalDaylRefPoints) {
4961 0 : ShowSevereError(state,
4962 0 : cCurrentModuleObject + "The number of extensible numeric fields and alpha fields is inconsistent for: " +
4963 0 : state.dataIPShortCut->cAlphaArgs(1));
4964 0 : ShowContinueError(
4965 : state,
4966 0 : "For each field: " + state.dataIPShortCut->cAlphaFieldNames(NumAlpha) +
4967 : " there needs to be the following fields: Fraction Controlled by Reference Point and Illuminance Setpoint at Reference Point");
4968 0 : ErrorsFound = true;
4969 : }
4970 287 : daylightControl.DaylRefPtNum.allocate(curTotalDaylRefPts);
4971 287 : daylightControl.FracZoneDaylit.allocate(curTotalDaylRefPts);
4972 287 : daylightControl.IllumSetPoint.allocate(curTotalDaylRefPts);
4973 287 : daylightControl.DaylIllumAtRefPt.allocate(curTotalDaylRefPts);
4974 287 : daylightControl.GlareIndexAtRefPt.allocate(curTotalDaylRefPts);
4975 287 : daylightControl.DaylRefPtAbsCoord.allocate(3, curTotalDaylRefPts);
4976 287 : daylightControl.DaylRefPtInBounds.allocate(curTotalDaylRefPts);
4977 287 : daylightControl.RefPtPowerReductionFactor.allocate(curTotalDaylRefPts);
4978 287 : daylightControl.BacLum.allocate(curTotalDaylRefPts);
4979 287 : daylightControl.TimeExceedingGlareIndexSPAtRefPt.allocate(curTotalDaylRefPts);
4980 287 : daylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt.allocate(curTotalDaylRefPts);
4981 :
4982 753 : for (int refPt = 1; refPt <= curTotalDaylRefPts; ++refPt) {
4983 466 : daylightControl.DaylRefPtNum(refPt) = 0;
4984 466 : daylightControl.FracZoneDaylit(refPt) = 0.0;
4985 466 : daylightControl.IllumSetPoint(refPt) = 0.0;
4986 466 : daylightControl.DaylIllumAtRefPt(refPt) = 0.0;
4987 466 : daylightControl.GlareIndexAtRefPt(refPt) = 0.0;
4988 466 : daylightControl.DaylRefPtInBounds(refPt) = true;
4989 466 : daylightControl.RefPtPowerReductionFactor(refPt) = 1.0;
4990 466 : daylightControl.BacLum(refPt) = 0.0;
4991 466 : daylightControl.TimeExceedingGlareIndexSPAtRefPt(refPt) = 0.0;
4992 466 : daylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt(refPt) = 0.0;
4993 1864 : for (int coord = 1; coord <= 3; ++coord) {
4994 1398 : daylightControl.DaylRefPtAbsCoord(coord, refPt) = 0.0;
4995 : }
4996 : }
4997 :
4998 287 : int countRefPts = 0;
4999 753 : for (int refPtNum = 1; refPtNum <= curTotalDaylRefPts; ++refPtNum) {
5000 466 : daylightControl.DaylRefPtNum(refPtNum) =
5001 466 : UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(6 + refPtNum),
5002 466 : state.dataDaylightingData->DaylRefPt,
5003 : &DataDaylighting::RefPointData::Name); // Field: Daylighting Reference Point Name
5004 466 : if (daylightControl.DaylRefPtNum(refPtNum) == 0) {
5005 0 : ShowSevereError(state,
5006 0 : cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(6 + refPtNum) + "=\"" +
5007 0 : state.dataIPShortCut->cAlphaArgs(6 + refPtNum) + "\" for object named: " + state.dataIPShortCut->cAlphaArgs(1));
5008 0 : ErrorsFound = true;
5009 0 : continue;
5010 : } else {
5011 466 : ++countRefPts;
5012 : }
5013 466 : daylightControl.FracZoneDaylit(refPtNum) =
5014 466 : state.dataIPShortCut->rNumericArgs(6 + refPtNum * 2); // Field: Fraction Controlled by Reference Point
5015 466 : daylightControl.IllumSetPoint(refPtNum) =
5016 466 : state.dataIPShortCut->rNumericArgs(7 + refPtNum * 2); // Field: Illuminance Setpoint at Reference Point
5017 :
5018 466 : if (daylightControl.DaylightMethod == DataDaylighting::DaylightingMethod::SplitFlux) {
5019 1840 : SetupOutputVariable(state,
5020 920 : format("Daylighting Reference Point {} Illuminance", refPtNum),
5021 : OutputProcessor::Unit::lux,
5022 920 : daylightControl.DaylIllumAtRefPt(refPtNum),
5023 : OutputProcessor::SOVTimeStepType::Zone,
5024 : OutputProcessor::SOVStoreType::Average,
5025 : daylightControl.Name);
5026 1840 : SetupOutputVariable(state,
5027 920 : format("Daylighting Reference Point {} Daylight Illuminance Setpoint Exceeded Time", refPtNum),
5028 : OutputProcessor::Unit::hr,
5029 920 : daylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt(refPtNum),
5030 : OutputProcessor::SOVTimeStepType::Zone,
5031 : OutputProcessor::SOVStoreType::Summed,
5032 : daylightControl.Name);
5033 1840 : SetupOutputVariable(state,
5034 920 : format("Daylighting Reference Point {} Glare Index", refPtNum),
5035 : OutputProcessor::Unit::None,
5036 920 : daylightControl.GlareIndexAtRefPt(refPtNum),
5037 : OutputProcessor::SOVTimeStepType::Zone,
5038 : OutputProcessor::SOVStoreType::Average,
5039 : daylightControl.Name);
5040 1840 : SetupOutputVariable(state,
5041 920 : format("Daylighting Reference Point {} Glare Index Setpoint Exceeded Time", refPtNum),
5042 : OutputProcessor::Unit::hr,
5043 920 : daylightControl.TimeExceedingGlareIndexSPAtRefPt(refPtNum),
5044 : OutputProcessor::SOVTimeStepType::Zone,
5045 : OutputProcessor::SOVStoreType::Summed,
5046 : daylightControl.Name);
5047 : }
5048 : }
5049 : // Register Error if 0 DElight RefPts have been input for valid DElight object
5050 287 : if (countRefPts < 1) {
5051 0 : ShowSevereError(state, "No Reference Points input for " + cCurrentModuleObject + " zone =" + daylightControl.ZoneName);
5052 0 : ErrorsFound = true;
5053 : }
5054 :
5055 287 : Real64 sumFracs = sum(daylightControl.FracZoneDaylit);
5056 287 : daylightControl.sumFracLights = sumFracs;
5057 287 : if ((1.0 - sumFracs) > FractionTolerance) {
5058 166 : ShowWarningError(state, "GetDaylightingControls: Fraction of zone or space controlled by the Daylighting reference points is < 1.0.");
5059 498 : ShowContinueError(state,
5060 498 : format("..discovered in {}=\"{}\", only {:.3R} of the zone or space is controlled.",
5061 : cCurrentModuleObject,
5062 : daylightControl.Name,
5063 498 : sum(daylightControl.FracZoneDaylit)));
5064 121 : } else if ((sumFracs - 1.0) > FractionTolerance) {
5065 0 : ShowSevereError(state, "GetDaylightingControls: Fraction of zone or space controlled by the Daylighting reference points is > 1.0.");
5066 0 : ShowContinueError(state,
5067 0 : format("..discovered in {}=\"{}\", trying to control {:.3R} of the zone or space.",
5068 : cCurrentModuleObject,
5069 : daylightControl.Name,
5070 0 : sum(daylightControl.FracZoneDaylit)));
5071 0 : ErrorsFound = true;
5072 : }
5073 :
5074 287 : if (daylightControl.LightControlType == DataDaylighting::LtgCtrlType::Stepped && daylightControl.LightControlSteps <= 0) {
5075 0 : ShowWarningError(state, "GetDaylightingControls: For Stepped Control, the number of steps must be > 0");
5076 0 : ShowContinueError(
5077 0 : state, "..discovered in \"" + cCurrentModuleObject + "\" for Zone=\"" + state.dataIPShortCut->cAlphaArgs(2) + "\", will use 1");
5078 0 : daylightControl.LightControlSteps = 1;
5079 : }
5080 574 : SetupOutputVariable(state,
5081 : "Daylighting Lighting Power Multiplier",
5082 : OutputProcessor::Unit::None,
5083 : daylightControl.PowerReductionFactor,
5084 : OutputProcessor::SOVTimeStepType::Zone,
5085 : OutputProcessor::SOVStoreType::Average,
5086 287 : daylightControl.Name);
5087 : }
5088 62 : }
5089 :
5090 62 : void GeometryTransformForDaylighting(EnergyPlusData &state)
5091 : {
5092 : // AUTHOR Fred Winkelmann
5093 : // DATE WRITTEN March 2002
5094 : // MODIFIED Glazer - July 2016 - separated this from GetInput function
5095 : // For splitflux daylighting, transform the geometry
5096 :
5097 : using InternalHeatGains::CheckLightsReplaceableMinMaxForZone;
5098 : using InternalHeatGains::GetDesignLightingLevelForZone;
5099 : using namespace OutputReportPredefined;
5100 : using ScheduleManager::GetScheduleIndex;
5101 :
5102 : int refPtNum;
5103 124 : std::string refName;
5104 : Real64 CosBldgRelNorth; // Cosine of Building rotation
5105 : Real64 SinBldgRelNorth; // Sine of Building rotation
5106 : Real64 CosZoneRelNorth; // Cosine of Zone rotation
5107 : Real64 SinZoneRelNorth; // Sine of Zone rotation
5108 62 : Real64 CosBldgRotAppGonly(0.0); // Cosine of the building rotation for appendix G only ( relative north )
5109 62 : Real64 SinBldgRotAppGonly(0.0); // Sine of the building rotation for appendix G only ( relative north )
5110 : Real64 Xb; // temp var for transformation calc
5111 : Real64 Yb; // temp var for transformation calc
5112 : Real64 Xo;
5113 : Real64 XnoRot;
5114 : Real64 Xtrans;
5115 : Real64 Yo;
5116 : Real64 YnoRot;
5117 : Real64 Ytrans;
5118 : bool doTransform;
5119 : Real64 OldAspectRatio;
5120 : Real64 NewAspectRatio;
5121 : Real64 rLightLevel;
5122 :
5123 : // Calc cos and sin of Building Relative North values for later use in transforming Reference Point coordinates
5124 62 : CosBldgRelNorth =
5125 62 : std::cos(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * DataGlobalConstants::DegToRadians);
5126 62 : SinBldgRelNorth =
5127 62 : std::sin(-(state.dataHeatBal->BuildingAzimuth + state.dataHeatBal->BuildingRotationAppendixG) * DataGlobalConstants::DegToRadians);
5128 : // these are only for Building Rotation for Appendix G when using world coordinate system
5129 62 : CosBldgRotAppGonly = std::cos(-state.dataHeatBal->BuildingRotationAppendixG * DataGlobalConstants::DegToRadians);
5130 62 : SinBldgRotAppGonly = std::sin(-state.dataHeatBal->BuildingRotationAppendixG * DataGlobalConstants::DegToRadians);
5131 :
5132 62 : doTransform = false;
5133 62 : OldAspectRatio = 1.0;
5134 62 : NewAspectRatio = 1.0;
5135 :
5136 62 : CheckForGeometricTransform(state, doTransform, OldAspectRatio, NewAspectRatio);
5137 349 : for (int controlNum = 1; controlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++controlNum) {
5138 287 : auto &daylCntrl = state.dataDaylightingData->daylightControl(controlNum);
5139 287 : auto &zone(state.dataHeatBal->Zone(daylCntrl.zoneIndex));
5140 :
5141 : // Calc cos and sin of Zone Relative North values for later use in transforming Reference Point coordinates
5142 287 : CosZoneRelNorth = std::cos(-zone.RelNorth * DataGlobalConstants::DegToRadians);
5143 287 : SinZoneRelNorth = std::sin(-zone.RelNorth * DataGlobalConstants::DegToRadians);
5144 :
5145 287 : rLightLevel = GetDesignLightingLevelForZone(state, daylCntrl.zoneIndex);
5146 287 : CheckLightsReplaceableMinMaxForZone(state, daylCntrl.zoneIndex);
5147 :
5148 753 : for (refPtNum = 1; refPtNum <= daylCntrl.TotalDaylRefPoints; ++refPtNum) {
5149 466 : auto &curRefPt(state.dataDaylightingData->DaylRefPt(daylCntrl.DaylRefPtNum(refPtNum))); // get the active daylighting:referencepoint
5150 466 : curRefPt.indexToFracAndIllum = refPtNum; // back reference to the index to the ZoneDaylight structure arrays related to reference points
5151 466 : if (state.dataSurface->DaylRefWorldCoordSystem) {
5152 : // transform only by appendix G rotation
5153 7 : daylCntrl.DaylRefPtAbsCoord(1, refPtNum) = curRefPt.x * CosBldgRotAppGonly - curRefPt.y * SinBldgRotAppGonly;
5154 7 : daylCntrl.DaylRefPtAbsCoord(2, refPtNum) = curRefPt.x * SinBldgRotAppGonly + curRefPt.y * CosBldgRotAppGonly;
5155 7 : daylCntrl.DaylRefPtAbsCoord(3, refPtNum) = curRefPt.z;
5156 : } else {
5157 : // Transform reference point coordinates into building coordinate system
5158 459 : Xb = curRefPt.x * CosZoneRelNorth - curRefPt.y * SinZoneRelNorth + zone.OriginX;
5159 459 : Yb = curRefPt.x * SinZoneRelNorth + curRefPt.y * CosZoneRelNorth + zone.OriginY;
5160 : // Transform into World Coordinate System
5161 459 : daylCntrl.DaylRefPtAbsCoord(1, refPtNum) = Xb * CosBldgRelNorth - Yb * SinBldgRelNorth;
5162 459 : daylCntrl.DaylRefPtAbsCoord(2, refPtNum) = Xb * SinBldgRelNorth + Yb * CosBldgRelNorth;
5163 459 : daylCntrl.DaylRefPtAbsCoord(3, refPtNum) = curRefPt.z + zone.OriginZ;
5164 459 : if (doTransform) {
5165 0 : Xo = daylCntrl.DaylRefPtAbsCoord(1, refPtNum); // world coordinates.... shifted by relative north angle...
5166 0 : Yo = daylCntrl.DaylRefPtAbsCoord(2, refPtNum);
5167 : // next derotate the building
5168 0 : XnoRot = Xo * CosBldgRelNorth + Yo * SinBldgRelNorth;
5169 0 : YnoRot = Yo * CosBldgRelNorth - Xo * SinBldgRelNorth;
5170 : // translate
5171 0 : Xtrans = XnoRot * std::sqrt(NewAspectRatio / OldAspectRatio);
5172 0 : Ytrans = YnoRot * std::sqrt(OldAspectRatio / NewAspectRatio);
5173 : // rerotate
5174 0 : daylCntrl.DaylRefPtAbsCoord(1, refPtNum) = Xtrans * CosBldgRelNorth - Ytrans * SinBldgRelNorth;
5175 0 : daylCntrl.DaylRefPtAbsCoord(2, refPtNum) = Xtrans * SinBldgRelNorth + Ytrans * CosBldgRelNorth;
5176 : }
5177 : }
5178 466 : refName = curRefPt.Name;
5179 466 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtZone, refName, daylCntrl.ZoneName);
5180 466 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtCtrlName, refName, daylCntrl.Name);
5181 466 : if (daylCntrl.DaylightMethod == DataDaylighting::DaylightingMethod::SplitFlux) {
5182 460 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtKind, refName, "SplitFlux");
5183 : } else {
5184 6 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtKind, refName, "DElight");
5185 : }
5186 : // ( 1=continuous, 2=stepped, 3=continuous/off )
5187 466 : if (daylCntrl.LightControlType == DataDaylighting::LtgCtrlType::Continuous) {
5188 59 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtCtrlType, refName, "Continuous");
5189 407 : } else if (daylCntrl.LightControlType == DataDaylighting::LtgCtrlType::Stepped) {
5190 129 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtCtrlType, refName, "Stepped");
5191 278 : } else if (daylCntrl.LightControlType == DataDaylighting::LtgCtrlType::ContinuousOff) {
5192 278 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtCtrlType, refName, "Continuous/Off");
5193 : }
5194 466 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtFrac, refName, daylCntrl.FracZoneDaylit(refPtNum));
5195 466 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtWInst, refName, rLightLevel);
5196 466 : PreDefTableEntry(state, state.dataOutRptPredefined->pdchDyLtWCtrl, refName, rLightLevel * daylCntrl.FracZoneDaylit(refPtNum));
5197 :
5198 466 : if (daylCntrl.DaylRefPtAbsCoord(1, refPtNum) < zone.MinimumX || daylCntrl.DaylRefPtAbsCoord(1, refPtNum) > zone.MaximumX) {
5199 0 : daylCntrl.DaylRefPtInBounds(refPtNum) = false;
5200 0 : ShowWarningError(state, "GeometryTransformForDaylighting: Reference point X Value outside Zone Min/Max X, Zone=" + zone.Name);
5201 0 : ShowContinueError(state,
5202 0 : format("...X Reference Point= {:.2R}, Zone Minimum X= {:.2R}, Zone Maximum X= {:.2R}",
5203 : daylCntrl.DaylRefPtAbsCoord(1, refPtNum),
5204 : zone.MinimumX,
5205 0 : zone.MaximumX));
5206 0 : if (daylCntrl.DaylRefPtAbsCoord(1, refPtNum) < zone.MinimumX) {
5207 0 : ShowContinueError(
5208 : state,
5209 0 : format("...X Reference Distance Outside MinimumX= {:.4R} m.", zone.MinimumX - daylCntrl.DaylRefPtAbsCoord(1, refPtNum)));
5210 : } else {
5211 0 : ShowContinueError(
5212 : state,
5213 0 : format("...X Reference Distance Outside MaximumX= {:.4R} m.", daylCntrl.DaylRefPtAbsCoord(1, refPtNum) - zone.MaximumX));
5214 : }
5215 : }
5216 466 : if (daylCntrl.DaylRefPtAbsCoord(2, refPtNum) < zone.MinimumY || daylCntrl.DaylRefPtAbsCoord(2, refPtNum) > zone.MaximumY) {
5217 0 : daylCntrl.DaylRefPtInBounds(refPtNum) = false;
5218 0 : ShowWarningError(state, "GeometryTransformForDaylighting: Reference point Y Value outside Zone Min/Max Y, Zone=" + zone.Name);
5219 0 : ShowContinueError(state,
5220 0 : format("...Y Reference Point= {:.2R}, Zone Minimum Y= {:.2R}, Zone Maximum Y= {:.2R}",
5221 : daylCntrl.DaylRefPtAbsCoord(2, refPtNum),
5222 : zone.MinimumY,
5223 0 : zone.MaximumY));
5224 0 : if (daylCntrl.DaylRefPtAbsCoord(2, refPtNum) < zone.MinimumY) {
5225 0 : ShowContinueError(
5226 : state,
5227 0 : format("...Y Reference Distance Outside MinimumY= {:.4R} m.", zone.MinimumY - daylCntrl.DaylRefPtAbsCoord(2, refPtNum)));
5228 : } else {
5229 0 : ShowContinueError(
5230 : state,
5231 0 : format("...Y Reference Distance Outside MaximumY= {:.4R} m.", daylCntrl.DaylRefPtAbsCoord(2, refPtNum) - zone.MaximumY));
5232 : }
5233 : }
5234 466 : if (daylCntrl.DaylRefPtAbsCoord(3, refPtNum) < zone.MinimumZ || daylCntrl.DaylRefPtAbsCoord(3, refPtNum) > zone.MaximumZ) {
5235 0 : daylCntrl.DaylRefPtInBounds(refPtNum) = false;
5236 0 : ShowWarningError(state, "GeometryTransformForDaylighting: Reference point Z Value outside Zone Min/Max Z, Zone=" + zone.Name);
5237 0 : ShowContinueError(state,
5238 0 : format("...Z Reference Point= {:.2R}, Zone Minimum Z= {:.2R}, Zone Maximum Z= {:.2R}",
5239 : daylCntrl.DaylRefPtAbsCoord(3, refPtNum),
5240 : zone.MinimumZ,
5241 0 : zone.MaximumZ));
5242 0 : if (daylCntrl.DaylRefPtAbsCoord(3, refPtNum) < zone.MinimumZ) {
5243 0 : ShowContinueError(
5244 : state,
5245 0 : format("...Z Reference Distance Outside MinimumZ= {:.4R} m.", zone.MinimumZ - daylCntrl.DaylRefPtAbsCoord(3, refPtNum)));
5246 : } else {
5247 0 : ShowContinueError(
5248 : state,
5249 0 : format("...Z Reference Distance Outside MaximumZ= {:.4R} m.", daylCntrl.DaylRefPtAbsCoord(3, refPtNum) - zone.MaximumZ));
5250 : }
5251 : }
5252 : } // for (refPtNum) reference point
5253 : } // for (controlNum) daylighting control
5254 62 : }
5255 :
5256 62 : void GetInputDayliteRefPt(EnergyPlusData &state, bool &ErrorsFound)
5257 : {
5258 : // Perform GetInput function for the Daylighting:ReferencePoint object
5259 : // Glazer - July 2016
5260 :
5261 62 : int RefPtNum = 0;
5262 : int IOStat;
5263 : int NumAlpha;
5264 : int NumNumber;
5265 62 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
5266 62 : cCurrentModuleObject = "Daylighting:ReferencePoint";
5267 62 : int TotRefPoints = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
5268 62 : state.dataDaylightingData->DaylRefPt.allocate(TotRefPoints);
5269 528 : for (auto &pt : state.dataDaylightingData->DaylRefPt) {
5270 3262 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
5271 : cCurrentModuleObject,
5272 : ++RefPtNum,
5273 466 : state.dataIPShortCut->cAlphaArgs,
5274 : NumAlpha,
5275 466 : state.dataIPShortCut->rNumericArgs,
5276 : NumNumber,
5277 : IOStat,
5278 466 : state.dataIPShortCut->lNumericFieldBlanks,
5279 466 : state.dataIPShortCut->lAlphaFieldBlanks,
5280 466 : state.dataIPShortCut->cAlphaFieldNames,
5281 466 : state.dataIPShortCut->cNumericFieldNames);
5282 466 : pt.Name = state.dataIPShortCut->cAlphaArgs(1);
5283 466 : pt.ZoneNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->Zone);
5284 466 : if (pt.ZoneNum == 0) {
5285 0 : int spaceNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->space);
5286 0 : if (spaceNum == 0) {
5287 0 : ShowSevereError(state,
5288 0 : cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid " +
5289 0 : state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" + state.dataIPShortCut->cAlphaArgs(2) + "\".");
5290 0 : ErrorsFound = true;
5291 : } else {
5292 0 : pt.ZoneNum = state.dataHeatBal->space(spaceNum).zoneNum;
5293 : }
5294 : }
5295 466 : pt.x = state.dataIPShortCut->rNumericArgs(1);
5296 466 : pt.y = state.dataIPShortCut->rNumericArgs(2);
5297 466 : pt.z = state.dataIPShortCut->rNumericArgs(3);
5298 : }
5299 62 : }
5300 :
5301 1025 : bool doesDayLightingUseDElight(EnergyPlusData &state)
5302 : {
5303 1306 : for (auto &znDayl : state.dataDaylightingData->daylightControl) {
5304 284 : if (znDayl.DaylightMethod == DataDaylighting::DaylightingMethod::DElight) {
5305 3 : return true;
5306 : }
5307 : }
5308 1022 : return false;
5309 : }
5310 :
5311 771 : void CheckTDDsAndLightShelvesInDaylitZones(EnergyPlusData &state)
5312 : {
5313 : // SUBROUTINE INFORMATION:
5314 : // AUTHOR Brent Griffith
5315 : // DATE WRITTEN Dec 2007
5316 : // MODIFIED na
5317 : // RE-ENGINEERED na
5318 :
5319 : // PURPOSE OF THIS SUBROUTINE:
5320 : // This subroutine checks daylighting input for TDDs and light shelfs
5321 : // which need to be checked after daylighting input has been read in (CR 7145)
5322 : // (eventually this should be changed once/if implementations change to decouple from daylighting calcs so that
5323 : // these devices can be used in models without daylighting controls
5324 : // CR 7145 was for TDDs, but also implenting check for light shelves, the other "daylighting device"
5325 :
5326 : // METHODOLOGY EMPLOYED:
5327 : // loop thru daylighting devices and check that their zones have daylight controls
5328 :
5329 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5330 : int PipeNum; // TDD pipe object number
5331 : int ShelfNum; // light shelf object number
5332 : int SurfNum; // daylight device surface number
5333 : bool ErrorsFound;
5334 :
5335 771 : ErrorsFound = false;
5336 :
5337 773 : for (PipeNum = 1; PipeNum <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++PipeNum) {
5338 2 : SurfNum = state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diffuser;
5339 2 : if (SurfNum > 0) {
5340 2 : int const pipeEnclNum = state.dataSurface->Surface(SurfNum).SolarEnclIndex;
5341 2 : if (state.dataViewFactor->EnclSolInfo(pipeEnclNum).TotalEnclosureDaylRefPoints == 0) {
5342 0 : ShowWarningError(state,
5343 0 : "DaylightingDevice:Tubular = " + state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name +
5344 : ": is not connected to a Zone that has Daylighting, no visible transmittance will be modeled through the "
5345 : "daylighting device.");
5346 : }
5347 :
5348 : } else { // SurfNum == 0
5349 : // should not come here (would have already been caught in TDD get input), but is an error
5350 0 : ShowSevereError(
5351 0 : state, "DaylightingDevice:Tubular = " + state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name + ": Diffuser surface not found ");
5352 0 : ErrorsFound = true;
5353 : }
5354 : } // PipeNum
5355 :
5356 772 : for (ShelfNum = 1; ShelfNum <= (int)state.dataDaylightingDevicesData->Shelf.size(); ++ShelfNum) {
5357 1 : SurfNum = state.dataDaylightingDevicesData->Shelf(ShelfNum).Window;
5358 1 : if (SurfNum == 0) {
5359 : // should not come here (would have already been caught in shelf get input), but is an error
5360 0 : ShowSevereError(state, "DaylightingDevice:Shelf = " + state.dataDaylightingDevicesData->Shelf(ShelfNum).Name + ": window not found ");
5361 0 : ErrorsFound = true;
5362 : }
5363 : } // ShelfNum
5364 :
5365 771 : if (ErrorsFound) ShowFatalError(state, "CheckTDDsAndLightShelvesInDaylitZones: Errors in DAYLIGHTING input.");
5366 771 : }
5367 :
5368 771 : void AssociateWindowShadingControlWithDaylighting(EnergyPlusData &state)
5369 : {
5370 843 : for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
5371 72 : if (state.dataSurface->WindowShadingControl(iShadeCtrl).DaylightingControlName.empty()) continue;
5372 25 : int found = -1;
5373 27 : for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
5374 27 : if (UtilityRoutines::SameString(state.dataSurface->WindowShadingControl(iShadeCtrl).DaylightingControlName,
5375 27 : state.dataDaylightingData->daylightControl(daylightCtrlNum).Name)) {
5376 25 : found = daylightCtrlNum;
5377 25 : break;
5378 : }
5379 : }
5380 25 : if (found > 0) {
5381 25 : state.dataSurface->WindowShadingControl(iShadeCtrl).DaylightControlIndex = found;
5382 : } else {
5383 0 : ShowWarningError(state, "AssociateWindowShadingControlWithDaylighting: Daylighting object name used in WindowShadingControl not found.");
5384 0 : ShowContinueError(state,
5385 0 : "..The WindowShadingControl object=\"" + state.dataSurface->WindowShadingControl(iShadeCtrl).Name +
5386 0 : "\" and referenes an object named: \"" +
5387 0 : state.dataSurface->WindowShadingControl(iShadeCtrl).DaylightingControlName + "\"");
5388 : }
5389 : }
5390 771 : }
5391 :
5392 62 : void GetLightWellData(EnergyPlusData &state, bool &ErrorsFound) // If errors found in input
5393 : {
5394 :
5395 : // SUBROUTINE INFORMATION:
5396 : // AUTHOR Fred Winkelmann
5397 : // DATE WRITTEN Apr 2004
5398 : // MODIFIED na
5399 : // RE-ENGINEERED na
5400 :
5401 : // PURPOSE OF THIS SUBROUTINE:
5402 : // Gets data for a light well associated with a rectangular exterior window.
5403 : // Calculates light well efficiency, defined as the ratio of the amount of visible
5404 : // solar radiation leaving a well to the amount entering the well.
5405 :
5406 : // METHODOLOGY EMPLOYED:
5407 : // Based on fit to Fig. 8-21, "Efficiency factors for various depths of light wells
5408 : // based on well-interreflectance values," Lighting Handbook, 8th Edition, Illuminating
5409 : // Engineering Society of North America, 1993.
5410 :
5411 : // Using/Aliasing
5412 :
5413 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5414 :
5415 : int IOStat; // IO Status when calling get input subroutine
5416 : int NumAlpha; // Number of alpha names being passed
5417 : int NumProp; // Number of properties being passed
5418 : int TotLightWells; // Total Light Well objects
5419 : int loop; // DO loop index
5420 : int SurfNum; // Surface number
5421 : bool WrongSurfaceType; // True if associated surface is not an exterior window
5422 : Real64 HeightWell; // Well height (from window to bottom of well) (m)
5423 : Real64 PerimWell; // Well perimeter (at bottom of well) (m)
5424 : Real64 AreaWell; // Well area (at bottom of well) (m2)
5425 : Real64 VisReflWell; // Area-weighted visible reflectance of well walls
5426 : Real64 WellCavRatio; // Well cavity ratio
5427 62 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
5428 : // Get the total number of Light Well objects
5429 62 : cCurrentModuleObject = "DaylightingDevice:LightWell";
5430 62 : TotLightWells = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
5431 62 : if (TotLightWells == 0) return;
5432 :
5433 3 : for (loop = 1; loop <= TotLightWells; ++loop) {
5434 :
5435 14 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
5436 : cCurrentModuleObject,
5437 : loop,
5438 2 : state.dataIPShortCut->cAlphaArgs,
5439 : NumAlpha,
5440 2 : state.dataIPShortCut->rNumericArgs,
5441 : NumProp,
5442 : IOStat,
5443 2 : state.dataIPShortCut->lNumericFieldBlanks,
5444 2 : state.dataIPShortCut->lAlphaFieldBlanks,
5445 2 : state.dataIPShortCut->cAlphaFieldNames,
5446 2 : state.dataIPShortCut->cNumericFieldNames);
5447 :
5448 2 : SurfNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(1), state.dataSurface->Surface);
5449 2 : if (SurfNum == 0) {
5450 0 : ShowSevereError(state,
5451 0 : cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" +
5452 0 : state.dataIPShortCut->cAlphaArgs(1) + "\" not found.");
5453 : }
5454 :
5455 : // Check that associated surface is an exterior window
5456 2 : WrongSurfaceType = false;
5457 2 : if (SurfNum != 0) {
5458 2 : if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Window &&
5459 0 : state.dataSurface->Surface(SurfNum).ExtBoundCond != ExternalEnvironment)
5460 0 : WrongSurfaceType = true;
5461 2 : if (WrongSurfaceType) {
5462 0 : ShowSevereError(state,
5463 0 : cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" +
5464 0 : state.dataIPShortCut->cAlphaArgs(1) + "\" - not an exterior window.");
5465 0 : ErrorsFound = true;
5466 : }
5467 : }
5468 :
5469 2 : if (!ErrorsFound) {
5470 :
5471 : // Associated surface is an exterior window; calculate light well efficiency.
5472 :
5473 2 : state.dataSurface->SurfWinLightWellEff(SurfNum) = 1.0;
5474 2 : HeightWell = state.dataIPShortCut->rNumericArgs(1);
5475 2 : PerimWell = state.dataIPShortCut->rNumericArgs(2);
5476 2 : AreaWell = state.dataIPShortCut->rNumericArgs(3);
5477 2 : VisReflWell = state.dataIPShortCut->rNumericArgs(4);
5478 :
5479 : // Warning if light well area is less than window area
5480 2 : if (AreaWell < (state.dataSurface->Surface(SurfNum).Area + state.dataSurface->SurfWinDividerArea(SurfNum) - 0.1)) {
5481 0 : ShowSevereError(state,
5482 0 : cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" +
5483 0 : state.dataIPShortCut->cAlphaArgs(1) + "\" - Areas.");
5484 0 : ShowContinueError(state,
5485 0 : format("has Area of Bottom of Well={:.1R} that is less than window area={:.1R}",
5486 0 : state.dataSurface->Surface(SurfNum).Area,
5487 0 : AreaWell));
5488 : }
5489 :
5490 2 : if (HeightWell >= 0.0 && PerimWell > 0.0 && AreaWell > 0.0) {
5491 2 : WellCavRatio = 2.5 * HeightWell * PerimWell / AreaWell;
5492 2 : state.dataSurface->SurfWinLightWellEff(SurfNum) = std::exp(-WellCavRatio * (0.16368 - 0.14467 * VisReflWell));
5493 : }
5494 : }
5495 :
5496 : } // End of loop over light well objects
5497 : }
5498 :
5499 3963536 : inline int findWinShadingStatus(EnergyPlusData &state, int const IWin)
5500 : {
5501 : // Return the window shading status, 1=unshaded, 2=shaded
5502 3963536 : int WinShadingIndex = 1;
5503 3963536 : bool WinShadedNoGlareControl = IS_SHADED_NO_GLARE_CTRL(state.dataSurface->SurfWinShadingFlag(IWin));
5504 4207417 : if ((state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF) &&
5505 3714223 : (WinShadedNoGlareControl || state.dataSurface->SurfWinSolarDiffusing(IWin))) {
5506 243881 : WinShadingIndex = 2;
5507 : }
5508 3963536 : return WinShadingIndex;
5509 : }
5510 :
5511 972795 : void DayltgGlare(EnergyPlusData &state,
5512 : int &IL, // Reference point index: 1=first ref pt, 2=second ref pt
5513 : Real64 &BLUM, // Window background (surround) luminance (cd/m2)
5514 : Real64 &GLINDX, // Glare index
5515 : int const daylightCtrlNum // Current daylighting control number
5516 : )
5517 : {
5518 :
5519 : // SUBROUTINE INFORMATION:
5520 : // AUTHOR Fred Winkelmann
5521 : // DATE WRITTEN July 1997
5522 :
5523 : // PURPOSE OF THIS SUBROUTINE:
5524 : // CALCULATE GLARE INDEX.
5525 :
5526 : // METHODOLOGY EMPLOYED:
5527 : // Called from DayltgInteriorIllum. Finds glare index at reference
5528 : // point no. IL in a space using the Cornell/BRS large source
5529 : // glare formula. BLUM is the background luminance (cd/m**2).
5530 : // TH comment 1/21/2010: The SurfaceWindow(IWin)%ShadingFlag has to be set
5531 : // before calling this subroutine. For switchable glazings this is tricky
5532 : // because the ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop)
5533 : // may change every time step to represent intermediate switched state.
5534 :
5535 : // REFERENCES:
5536 : // Based on DOE-2.1E subroutine DGLARE.
5537 :
5538 972795 : Real64 GTOT = 0.0; // Glare constant
5539 :
5540 : // Loop over exterior windows associated with zone
5541 972795 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
5542 972795 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(thisDaylightControl.enclIndex);
5543 3531695 : for (int loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
5544 2558900 : int IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
5545 2558900 : int WinShadingIndex = findWinShadingStatus(state, IWin);
5546 : // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor
5547 : // below, which is (0.2936)**0.6
5548 2558900 : Real64 GTOT1 = 0.4794 * (std::pow(thisDaylightControl.SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL), 1.6)) *
5549 2558900 : std::pow(thisDaylightControl.SolidAngAtRefPtWtd(loop, IL), 0.8);
5550 5117800 : Real64 GTOT2 = BLUM + 0.07 * (std::sqrt(thisDaylightControl.SolidAngAtRefPt(loop, IL))) *
5551 5117800 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL);
5552 2558900 : GTOT += GTOT1 / (GTOT2 + 0.000001);
5553 : }
5554 :
5555 : // Glare index (adding 0.000001 prevents LOG10 (0))
5556 972795 : GLINDX = 10.0 * std::log10(GTOT + 0.000001);
5557 : // Set glare index to zero for GTOT < 1
5558 972795 : GLINDX = max(0.0, GLINDX);
5559 972795 : }
5560 :
5561 1015 : void DayltgGlareWithIntWins(EnergyPlusData &state,
5562 : Array1D<Real64> &GLINDX, // Glare index
5563 : int const daylightCtrlNum // Current daylighting control number
5564 : )
5565 : {
5566 :
5567 : // SUBROUTINE INFORMATION:
5568 : // AUTHOR Fred Winkelmann
5569 : // DATE WRITTEN March 2004
5570 :
5571 : // PURPOSE OF THIS SUBROUTINE:
5572 : // Calculate daylighting glare index for zones with interior windows.
5573 :
5574 : // METHODOLOGY EMPLOYED:
5575 : // Finds glare index at reference point IL in a daylit zone using the Cornell/BRS large source
5576 : // glare formula. Takes into account inter-reflected illuminance from light entering
5577 : // the zone through interior windows
5578 :
5579 : // REFERENCES:
5580 : // Based on subroutine DayltgGlare.
5581 :
5582 1015 : Real64 GTOT = 0.0; // Glare constant(?)
5583 :
5584 : // Calculate background luminance including effect of inter-reflected illuminance from light
5585 : // entering zone through its interior windows
5586 :
5587 1015 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
5588 1015 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(thisDaylightControl.enclIndex);
5589 1015 : int RefPoints = thisDaylightControl.TotalDaylRefPoints; // Number of daylighting reference points in zone
5590 2030 : for (int IL = 1; IL <= RefPoints; ++IL) {
5591 : Real64 BackgroundLum =
5592 1015 : thisDaylightControl.BacLum(IL) + thisEnclDaylight.InterReflIllFrIntWins * thisEnclDaylight.aveVisDiffReflect / DataGlobalConstants::Pi;
5593 1015 : BackgroundLum = max(thisDaylightControl.IllumSetPoint(IL) * thisEnclDaylight.aveVisDiffReflect / DataGlobalConstants::Pi, BackgroundLum);
5594 :
5595 : // Loop over exterior windows associated with zone
5596 2030 : for (int loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
5597 1015 : int IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
5598 1015 : int WinShadingIndex = findWinShadingStatus(state, IWin);
5599 : // Conversion from ft-L to cd/m2, with cd/m2 = 0.2936 ft-L, gives the 0.4794 factor
5600 : // below, which is (0.2936)**0.6
5601 1015 : Real64 GTOT1 = 0.4794 * (std::pow(thisDaylightControl.SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL), 1.6)) *
5602 1015 : std::pow(thisDaylightControl.SolidAngAtRefPtWtd(loop, IL), 0.8);
5603 2030 : Real64 GTOT2 = BackgroundLum + 0.07 * (std::sqrt(thisDaylightControl.SolidAngAtRefPt(loop, IL))) *
5604 2030 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, WinShadingIndex, IL);
5605 1015 : GTOT += GTOT1 / (GTOT2 + 0.000001);
5606 : }
5607 :
5608 : // Glare index
5609 1015 : GLINDX(IL) = 10.0 * std::log10(GTOT + 0.000001);
5610 : // Set glare index to zero for GTOT < 1
5611 1015 : GLINDX(IL) = max(0.0, GLINDX(IL));
5612 : }
5613 1015 : }
5614 :
5615 4338 : void DayltgExtHorizIllum(EnergyPlusData &state,
5616 : Array1A<Real64> HISK, // Horizontal illuminance from sky for different sky types
5617 : Real64 &HISU // Horizontal illuminance from sun for unit beam normal
5618 : )
5619 : {
5620 :
5621 : // SUBROUTINE INFORMATION:
5622 : // AUTHOR Fred Winkelmann
5623 : // DATE WRITTEN July 1997
5624 : // MODIFIED na
5625 : // RE-ENGINEERED na
5626 :
5627 : // PURPOSE OF THIS SUBROUTINE:
5628 : // Calculates exterior daylight illuminance.
5629 :
5630 : // METHODOLOGY EMPLOYED:
5631 : // Called by CalcDayltgCoefficients. Calculates illuminance
5632 : // on unobstructed horizontal surface by integrating
5633 : // over the luminance distribution of standard CIE skies.
5634 : // Calculates horizontal beam illuminance.
5635 : // REFERENCES:
5636 : // Based on DOE-2.1E subroutine DHILL.
5637 :
5638 : // Argument array dimensioning
5639 4338 : HISK.dim(4);
5640 :
5641 : // SUBROUTINE PARAMETER DEFINITIONS:
5642 4338 : Real64 const DTH((2.0 * DataGlobalConstants::Pi) / double(NTH)); // Sky integration azimuth stepsize (radians)
5643 4338 : Real64 const DPH(DataGlobalConstants::PiOvr2 / double(NPH)); // Sky integration altitude stepsize (radians)
5644 :
5645 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5646 : int IPH; // Altitude index for sky integration
5647 : int ITH; // Azimuth index for sky integration
5648 4338 : auto &PH = state.dataDaylightingManager->PH;
5649 4338 : auto &TH = state.dataDaylightingManager->TH;
5650 4338 : auto &SPHCPH = state.dataDaylightingManager->SPHCPH;
5651 : int ISky; // Sky type index
5652 :
5653 : // Integrate to obtain illuminance from sky.
5654 : // The contribution in lumens/m2 from a patch of sky at altitude PH and azimuth TH
5655 : // is L(TH,PH)*SIN(PH)*COS(PH)*DTH*DPH, where L(TH,PH) is the luminance
5656 : // of the patch in cd/m2.
5657 : // Init
5658 4338 : if (state.dataDaylightingManager->DayltgExtHorizIllum_firstTime) {
5659 558 : for (IPH = 1; IPH <= NPH; ++IPH) {
5660 496 : PH(IPH) = (IPH - 0.5) * DPH;
5661 496 : SPHCPH(IPH) = std::sin(PH(IPH)) * std::cos(PH(IPH)); // DA = COS(PH)*DTH*DPH
5662 : }
5663 1178 : for (ITH = 1; ITH <= NTH; ++ITH) {
5664 1116 : TH(ITH) = (ITH - 0.5) * DTH;
5665 : }
5666 62 : state.dataDaylightingManager->DayltgExtHorizIllum_firstTime = false;
5667 : }
5668 :
5669 4338 : HISK = 0.0;
5670 :
5671 : // Sky integration
5672 39042 : for (IPH = 1; IPH <= NPH; ++IPH) {
5673 34704 : Real64 const PH_IPH(PH(IPH));
5674 34704 : Real64 const SPHCPH_IPH(SPHCPH(IPH));
5675 659376 : for (ITH = 1; ITH <= NTH; ++ITH) {
5676 624672 : Real64 const TH_ITH(TH(ITH));
5677 3123360 : for (ISky = 1; ISky <= 4; ++ISky) {
5678 2498688 : HISK(ISky) += DayltgSkyLuminance(state, ISky, TH_ITH, PH_IPH) * SPHCPH_IPH;
5679 : }
5680 : }
5681 : }
5682 :
5683 21690 : for (ISky = 1; ISky <= 4; ++ISky) {
5684 17352 : HISK(ISky) *= DTH * DPH;
5685 : }
5686 :
5687 : // Direct solar horizontal illum (for unit direct normal illuminance)
5688 4338 : HISU = state.dataDaylightingManager->SPHSUN * 1.0;
5689 4338 : }
5690 :
5691 6749023 : void DayltgHitObstruction(EnergyPlusData &state,
5692 : int const IHOUR, // Hour number
5693 : int const IWin, // Window index
5694 : Vector3<Real64> const &R1, // Origin of ray (m)
5695 : Vector3<Real64> const &RN, // Unit vector along ray
5696 : Real64 &ObTrans // Product of solar transmittances of exterior obstructions
5697 : )
5698 : {
5699 :
5700 : // SUBROUTINE INFORMATION:
5701 : // AUTHOR Fred Winkelmann
5702 : // DATE WRITTEN July 1997
5703 : // MODIFIED FCW, May 2003: update list of surface classes that qualify as obstructions;
5704 : // add interior surfaces as possible obstructors;
5705 : // return from DO loop over surfaces as soon as any obstruction is hit;
5706 : // FCW, July 2003: change from returning whether an obstruction is hit or not
5707 : // to product of solar transmittances of hit obstructions.
5708 : // FCW, Nov 2003: remove interior surfaces as possible obstructors since there
5709 : // is now a separate check for interior obstructions; exclude windows and
5710 : // doors as obstructors since if they are obstructors their base surfaces will
5711 : // also be obstructors
5712 : // RE-ENGINEERED Sept 2015. Stuart Mentzer. Octree for performance.
5713 :
5714 : // PURPOSE OF THIS SUBROUTINE:
5715 : // Determines the product of the solar transmittances of the obstructions hit by a ray
5716 : // from R1 in the direction of vector RN.
5717 :
5718 : // REFERENCES:
5719 : // Based on DOE-2.1E subroutine DHITSH.
5720 :
5721 : // Using/Aliasing
5722 : using ScheduleManager::LookUpScheduleValue;
5723 :
5724 : // Local declarations
5725 : SurfaceClass IType; // Surface type/class: mirror surfaces of shading surfaces
5726 6749023 : auto &DayltgHitObstructionHP = state.dataDaylightingManager->DayltgHitObstructionHP;
5727 : bool hit; // True iff a particular obstruction is hit
5728 :
5729 6749023 : ObTrans = 1.0;
5730 :
5731 6749023 : auto const &window(state.dataSurface->Surface(IWin));
5732 6749023 : auto const window_iBaseSurf(window.BaseSurf);
5733 :
5734 : // Loop over potentially obstructing surfaces, which can be building elements, like walls, or shadowing surfaces, like overhangs
5735 : // Building elements are assumed to be opaque
5736 : // A shadowing surface is opaque unless its transmittance schedule value is non-zero
5737 6749023 : if (state.dataSurface->TotSurfaces < octreeCrossover) { // Linear search through surfaces
5738 :
5739 56394959 : for (int ISurf : state.dataSurface->AllShadowPossObstrSurfaceList) {
5740 51868280 : auto const &surface(state.dataSurface->Surface(ISurf));
5741 51868280 : IType = surface.Class;
5742 51868280 : if ((IType == SurfaceClass::Wall || IType == SurfaceClass::Roof || IType == SurfaceClass::Floor) && (ISurf != window_iBaseSurf)) {
5743 : PierceSurface(state, ISurf, R1, RN, DayltgHitObstructionHP, hit);
5744 93669802 : if (hit) { // Building element is hit (assumed opaque)
5745 45108 : ObTrans = 0.0;
5746 45108 : break;
5747 : }
5748 5010825 : } else if (surface.IsShadowing) {
5749 : PierceSurface(state, ISurf, R1, RN, DayltgHitObstructionHP, hit);
5750 439172 : if (hit) { // Shading surface is hit
5751 : // Get solar transmittance of the shading surface
5752 57538 : Real64 const Trans(surface.SchedShadowSurfIndex > 0 ? LookUpScheduleValue(state, surface.SchedShadowSurfIndex, IHOUR, 1) : 0.0);
5753 57538 : if (Trans < 1.e-6) {
5754 57538 : ObTrans = 0.0;
5755 57538 : break;
5756 : } else {
5757 0 : ObTrans *= Trans;
5758 : }
5759 : }
5760 : }
5761 : }
5762 :
5763 : } else { // Surface octree search
5764 :
5765 2119698 : auto const &window_base(window_iBaseSurf > 0 ? state.dataSurface->Surface(window_iBaseSurf) : window);
5766 2119698 : auto const window_base_p(&window_base);
5767 :
5768 : // Lambda function for the octree to test for surface hit and update transmittance if hit
5769 494081565 : auto solarTransmittance = [=, &state, &R1, &RN, &hit, &ObTrans](SurfaceData const &surface) -> bool {
5770 299776131 : if (!surface.IsShadowPossibleObstruction) return false; // Do Consider separate octree without filtered surfaces
5771 66829301 : auto const sClass(surface.Class);
5772 66829301 : if ((sClass == SurfaceClass::Wall || sClass == SurfaceClass::Roof || sClass == SurfaceClass::Floor) && (&surface != window_base_p)) {
5773 64697724 : PierceSurface(surface, R1, RN, state.dataDaylightingManager->DayltgHitObstructionHP, hit);
5774 129323145 : if (hit) { // Building element is hit (assumed opaque)
5775 72303 : ObTrans = 0.0;
5776 72303 : return true;
5777 : }
5778 2131577 : } else if (surface.IsShadowing) {
5779 46653 : PierceSurface(surface, R1, RN, state.dataDaylightingManager->DayltgHitObstructionHP, hit);
5780 46653 : if (hit) { // Shading surface is hit
5781 : // Get solar transmittance of the shading surface
5782 0 : Real64 const Trans(surface.SchedShadowSurfIndex > 0 ? LookUpScheduleValue(state, surface.SchedShadowSurfIndex, IHOUR, 1) : 0.0);
5783 0 : if (Trans < 1.e-6) {
5784 0 : ObTrans = 0.0;
5785 0 : return true;
5786 : } else {
5787 0 : ObTrans *= Trans;
5788 0 : return ObTrans == 0.0;
5789 : }
5790 : }
5791 : }
5792 66756998 : return false;
5793 2119698 : };
5794 :
5795 : // Check octree surface candidates for hits: short circuits if zero transmittance reached
5796 4239396 : Vector3<Real64> const RN_inv(SurfaceOctreeCube::safe_inverse(RN));
5797 2119698 : state.dataHeatBalMgr->surfaceOctree.processSomeSurfaceRayIntersectsCube(state, R1, RN, RN_inv, solarTransmittance);
5798 : }
5799 6749023 : }
5800 :
5801 2742823 : void DayltgHitInteriorObstruction(EnergyPlusData &state,
5802 : int const IWin, // Window index
5803 : Vector3<Real64> const &R1, // Origin of ray (m)
5804 : Vector3<Real64> const &R2, // Destination of ray (m)
5805 : bool &hit // True iff ray hits an obstruction
5806 : )
5807 : {
5808 :
5809 : // SUBROUTINE INFORMATION:
5810 : // AUTHOR Fred Winkelmann
5811 : // DATE WRITTEN July 1997
5812 : // MODIFIED na
5813 : // RE-ENGINEERED Sept 2015. Stuart Mentzer. Octree for performance.
5814 :
5815 : // PURPOSE OF THIS SUBROUTINE:
5816 : // This subroutine checks for interior obstructions between reference point and window element.
5817 :
5818 : // Preconditions
5819 2742823 : assert(magnitude(R2 - R1) > 0.0); // Protect normalize() from divide by zero
5820 :
5821 : // Local declarations
5822 : SurfaceClass IType; // Surface type/class
5823 : auto &DayltgHitInteriorObstructionHP =
5824 2742823 : state.dataDaylightingManager->DayltgHitInteriorObstructionHP; // Hit coordinates, if ray hits an obstruction
5825 2742823 : auto &RN = state.dataDaylightingManager->RN; // Unit vector along ray
5826 :
5827 2742823 : hit = false;
5828 2742823 : RN = (R2 - R1).normalize(); // Make unit vector
5829 2742823 : Real64 const d12(distance(R1, R2)); // Distance between R1 and R2
5830 :
5831 2742823 : auto const &window(state.dataSurface->Surface(IWin));
5832 2742823 : auto const window_Enclosure(window.SolarEnclIndex);
5833 2742823 : auto const window_iBaseSurf(window.BaseSurf);
5834 2742823 : auto const &window_base(window_iBaseSurf > 0 ? state.dataSurface->Surface(window_iBaseSurf) : window);
5835 2742823 : auto const window_base_iExtBoundCond(window_base.ExtBoundCond);
5836 :
5837 : // Loop over potentially obstructing surfaces, which can be building elements, like walls, or shadowing surfaces, like overhangs
5838 2742823 : if (state.dataSurface->TotSurfaces < octreeCrossover) { // Linear search through surfaces
5839 :
5840 70119371 : for (int ISurf = 1; ISurf <= state.dataSurface->TotSurfaces; ++ISurf) {
5841 67918288 : auto const &surface(state.dataSurface->Surface(ISurf));
5842 67918288 : IType = surface.Class;
5843 135507570 : if ((surface.IsShadowing) || // Shadowing surface
5844 101381759 : ((surface.SolarEnclIndex == window_Enclosure) && // Wall/ceiling/floor is in same zone as window
5845 24794251 : (IType == SurfaceClass::Wall || IType == SurfaceClass::Roof || IType == SurfaceClass::Floor) && (ISurf != window_iBaseSurf) &&
5846 : (ISurf != window_base_iExtBoundCond))) // Exclude window's base or base-adjacent surfaces
5847 : {
5848 : PierceSurface(state, ISurf, R1, RN, d12, DayltgHitInteriorObstructionHP, hit); // Check if R2-R1 segment pierces surface
5849 11500623 : if (hit) break; // Segment pierces surface: Don't check the rest
5850 : }
5851 : }
5852 :
5853 : } else { // Surface octree search
5854 :
5855 510418 : auto const window_base_p(&window_base);
5856 510418 : auto const &window_base_adjacent(window_base_iExtBoundCond > 0 ? state.dataSurface->Surface(window_base_iExtBoundCond) : window_base);
5857 510418 : auto const window_base_adjacent_p(&window_base_adjacent);
5858 :
5859 : // Lambda function for the octree to test for surface hit
5860 84495391 : auto surfaceHit = [=, &R1, &hit, &state](SurfaceData const &surface) -> bool {
5861 76735020 : auto const sClass(surface.Class);
5862 153463134 : if ((surface.IsShadowing) || // Shadowing surface
5863 81531100 : ((surface.SolarEnclIndex == window_Enclosure) && // Surface is in same zone as window
5864 5817126 : (sClass == SurfaceClass::Wall || sClass == SurfaceClass::Roof || sClass == SurfaceClass::Floor) && // Wall, ceiling/roof, or floor
5865 5329908 : (&surface != window_base_p) && (&surface != window_base_adjacent_p))) // Exclude window's base or base-adjacent surfaces
5866 : {
5867 4833302 : PierceSurface(surface,
5868 : R1,
5869 : RN,
5870 2416651 : d12,
5871 2416651 : state.dataDaylightingManager->DayltgHitInteriorObstructionHP,
5872 : hit); // Check if R2-R1 segment pierces surface
5873 2416651 : return hit;
5874 : } else {
5875 74318369 : return false;
5876 : }
5877 1020836 : };
5878 :
5879 : // Check octree surface candidates until a hit is found, if any
5880 510418 : state.dataHeatBalMgr->surfaceOctree.hasSurfaceSegmentIntersectsCube(R1, R2, surfaceHit);
5881 : }
5882 2742823 : }
5883 :
5884 20412 : void DayltgHitBetWinObstruction(EnergyPlusData &state,
5885 : int const IWin1, // Surface number of origin window
5886 : int const IWin2, // Surface number of destination window
5887 : Vector3<Real64> const &R1, // Origin of ray (on IWin1) (m)
5888 : Vector3<Real64> const &R2, // Destination of ray (on IWin2) (m)
5889 : bool &hit // True iff ray hits an obstruction
5890 : )
5891 : {
5892 :
5893 : // SUBROUTINE INFORMATION:
5894 : // AUTHOR Fred Winkelmann
5895 : // DATE WRITTEN Feb 2004
5896 : // MODIFIED na
5897 : // RE-ENGINEERED Sept 2015. Stuart Mentzer. Octree for performance.
5898 :
5899 : // PURPOSE OF THIS SUBROUTINE:
5900 : // Determines if a ray from point R1 on window IWin1 to point R2
5901 : // on window IWin2 hits an obstruction
5902 :
5903 : // Preconditions
5904 20412 : assert(magnitude(R2 - R1) > 0.0); // Protect normalize() from divide by zero
5905 :
5906 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5907 : SurfaceClass IType; // Surface type/class
5908 20412 : auto &DayltgHitBetWinObstructionHP = state.dataDaylightingManager->DayltgHitBetWinObstructionHP;
5909 20412 : auto &DayltgHitBetWinObstructionRN = state.dataDaylightingManager->DayltgHitBetWinObstructionRN;
5910 :
5911 20412 : hit = false;
5912 20412 : DayltgHitBetWinObstructionRN = (R2 - R1).normalize(); // Unit vector
5913 20412 : Real64 const d12(distance(R1, R2)); // Distance between R1 and R2 (m)
5914 :
5915 20412 : auto const &window1(state.dataSurface->Surface(IWin1));
5916 20412 : auto const window1_iBaseSurf(window1.BaseSurf);
5917 20412 : auto const &window1_base(window1_iBaseSurf > 0 ? state.dataSurface->Surface(window1_iBaseSurf) : window1);
5918 20412 : auto const window1_base_iExtBoundCond(window1_base.ExtBoundCond);
5919 :
5920 20412 : auto const &window2(state.dataSurface->Surface(IWin2));
5921 20412 : auto const window2_Enclosure(window2.SolarEnclIndex);
5922 20412 : auto const window2_iBaseSurf(window2.BaseSurf);
5923 20412 : auto const &window2_base(window2_iBaseSurf > 0 ? state.dataSurface->Surface(window2_iBaseSurf) : window2);
5924 20412 : auto const window2_base_iExtBoundCond(window2_base.ExtBoundCond);
5925 :
5926 : // Preconditions
5927 : // assert( window1.Zone == window2_Zone ); //? This is violated in PurchAirWithDoubleFacadeDaylighting so then why the asymmetry
5928 : // of only checking for wall/roof/floor for window2 zone below?
5929 :
5930 : // Loop over potentially obstructing surfaces, which can be building elements, like walls, or shadowing surfaces, like overhangs
5931 20412 : if (state.dataSurface->TotSurfaces < octreeCrossover) { // Linear search through surfaces
5932 :
5933 612360 : for (int ISurf = 1; ISurf <= state.dataSurface->TotSurfaces; ++ISurf) {
5934 591948 : auto const &surface(state.dataSurface->Surface(ISurf));
5935 591948 : IType = surface.Class;
5936 1183896 : if ((surface.IsShadowing) || // Shadowing surface
5937 755244 : ((surface.SolarEnclIndex == window2_Enclosure) && // Wall/ceiling/floor is in same zone as windows
5938 81648 : (IType == SurfaceClass::Wall || IType == SurfaceClass::Roof || IType == SurfaceClass::Floor) && // Wall, ceiling/roof, or floor
5939 122472 : (ISurf != window1_iBaseSurf) && (ISurf != window2_iBaseSurf) && // Exclude windows' base surfaces
5940 81648 : (ISurf != window1_base_iExtBoundCond) && (ISurf != window2_base_iExtBoundCond))) // Exclude windows' base-adjacent surfaces
5941 : {
5942 : PierceSurface(
5943 : state, ISurf, R1, DayltgHitBetWinObstructionRN, d12, DayltgHitBetWinObstructionHP, hit); // Check if R2-R1 segment pierces surface
5944 81648 : if (hit) break; // Segment pierces surface: Don't check the rest
5945 : }
5946 : }
5947 :
5948 : } else { // Surface octree search
5949 :
5950 0 : auto const window1_base_p(&window1_base);
5951 0 : auto const &window1_base_adjacent(window1_base_iExtBoundCond > 0 ? state.dataSurface->Surface(window1_base_iExtBoundCond) : window1_base);
5952 0 : auto const window1_base_adjacent_p(&window1_base_adjacent);
5953 :
5954 0 : auto const window2_base_p(&window2_base);
5955 0 : auto const &window2_base_adjacent(window2_base_iExtBoundCond > 0 ? state.dataSurface->Surface(window2_base_iExtBoundCond) : window2_base);
5956 0 : auto const window2_base_adjacent_p(&window2_base_adjacent);
5957 :
5958 : // Lambda function for the octree to test for surface hit
5959 0 : auto surfaceHit = [=, &R1, &hit, &state](SurfaceData const &surface) -> bool {
5960 0 : auto const sClass(surface.Class);
5961 0 : if ((surface.IsShadowing) || // Shadowing surface
5962 0 : ((surface.SolarEnclIndex == window2_Enclosure) && // Surface is in same zone as window
5963 0 : (sClass == SurfaceClass::Wall || sClass == SurfaceClass::Roof || sClass == SurfaceClass::Floor) && // Wall, ceiling/roof, or floor
5964 0 : (&surface != window1_base_p) && (&surface != window2_base_p) && // Exclude windows' base surfaces
5965 0 : (&surface != window1_base_adjacent_p) && (&surface != window2_base_adjacent_p))) // Exclude windows' base-adjacent surfaces
5966 : {
5967 0 : PierceSurface(surface,
5968 : R1,
5969 0 : state.dataDaylightingManager->DayltgHitBetWinObstructionRN,
5970 0 : d12,
5971 0 : state.dataDaylightingManager->DayltgHitBetWinObstructionHP,
5972 : hit); // Check if R2-R1 segment pierces surface
5973 0 : return hit;
5974 : } else {
5975 0 : return false;
5976 : }
5977 0 : };
5978 :
5979 : // Check octree surface candidates until a hit is found, if any
5980 0 : state.dataHeatBalMgr->surfaceOctree.hasSurfaceSegmentIntersectsCube(R1, R2, surfaceHit);
5981 : }
5982 20412 : }
5983 :
5984 2568509 : void initDaylighting(EnergyPlusData &state, bool const initSurfaceHeatBalancefirstTime)
5985 : {
5986 : // For daylit zones, calculate interior daylight illuminance at reference points and
5987 : // simulate lighting control system to get overhead electric lighting reduction
5988 : // factor due to daylighting.
5989 24548537 : for (int SurfNum : state.dataSurface->AllExtSolWindowSurfaceList) {
5990 21980028 : state.dataSurface->SurfaceWindow(SurfNum).IllumFromWinAtRefPtRep = 0.0;
5991 21980028 : state.dataSurface->SurfaceWindow(SurfNum).LumWinFromRefPtRep = 0.0;
5992 : }
5993 :
5994 : // Reset space power reduction factors
5995 21031250 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
5996 18462741 : state.dataDaylightingData->spacePowerReductionFactor(spaceNum) = 1.0;
5997 : }
5998 3983633 : for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
5999 1415124 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
6000 1415124 : thisDaylightControl.PowerReductionFactor = 1.0;
6001 1415124 : if (state.dataEnvrn->PreviousSolRadPositive) {
6002 : // Reset to zero only if there was solar in the previous timestep, otherwise these are already zero
6003 409689 : thisDaylightControl.DaylIllumAtRefPt = 0.0;
6004 409689 : thisDaylightControl.GlareIndexAtRefPt = 0.0;
6005 409689 : state.dataDaylightingData->enclDaylight(thisDaylightControl.enclIndex).InterReflIllFrIntWins =
6006 : 0.0; // inter-reflected illuminance from interior windows
6007 949063 : for (int refPtNum = 1; refPtNum <= thisDaylightControl.TotalDaylRefPoints; ++refPtNum) {
6008 539374 : thisDaylightControl.TimeExceedingGlareIndexSPAtRefPt(refPtNum) = 0.0;
6009 539374 : thisDaylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt(refPtNum) = 0.0;
6010 : }
6011 : }
6012 :
6013 1415124 : if (state.dataEnvrn->SunIsUp && thisDaylightControl.TotalDaylRefPoints != 0) {
6014 701021 : if (initSurfaceHeatBalancefirstTime) DisplayString(state, "Computing Interior Daylighting Illumination");
6015 701021 : DayltgInteriorIllum(state, daylightCtrlNum);
6016 : }
6017 : }
6018 :
6019 : // The following report variables are valid only for daylit zones/enclosures without interior windows
6020 2568509 : if (state.dataEnvrn->SunIsUp) {
6021 10548703 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
6022 9959597 : if ((state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints > 0) &&
6023 698984 : (!state.dataViewFactor->EnclSolInfo(enclNum).HasInterZoneWindow)) {
6024 697969 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
6025 2082804 : for (int extWinNum = 1; extWinNum <= thisEnclDaylight.NumOfDayltgExtWins; ++extWinNum) {
6026 1384835 : int IWin = thisEnclDaylight.DayltgExtWinSurfNums(extWinNum);
6027 1384835 : int IS = 1;
6028 2839720 : if (state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF &&
6029 2691472 : (IS_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) || state.dataSurface->SurfWinSolarDiffusing(IWin))) {
6030 72766 : IS = 2;
6031 : }
6032 1384835 : int refPtCount = 0;
6033 2775781 : for (int controlNum : state.dataDaylightingData->enclDaylight(enclNum).daylightControlIndexes) {
6034 1390946 : auto &thisControl = state.dataDaylightingData->daylightControl(controlNum);
6035 1390946 : if (thisControl.DaylightMethod == DataDaylighting::DaylightingMethod::SplitFlux) {
6036 3539911 : for (int refPtNum = 1; refPtNum <= thisControl.TotalDaylRefPoints; ++refPtNum) {
6037 2148965 : ++refPtCount; // Count reference points across each daylighting control in the same enclosure
6038 2148965 : state.dataSurface->SurfaceWindow(IWin).IllumFromWinAtRefPtRep(refPtCount) =
6039 2148965 : thisControl.IllumFromWinAtRefPt(extWinNum, IS, refPtNum);
6040 2148965 : state.dataSurface->SurfaceWindow(IWin).LumWinFromRefPtRep(refPtCount) =
6041 2148965 : thisControl.SourceLumFromWinAtRefPt(extWinNum, IS, refPtNum);
6042 : }
6043 : }
6044 : }
6045 : }
6046 : }
6047 : }
6048 : }
6049 :
6050 2568509 : if (state.dataEnvrn->SunIsUp && (int)state.dataDaylightingDevicesData->TDDPipe.size() > 0) {
6051 1015 : if (initSurfaceHeatBalancefirstTime) DisplayString(state, "Computing Interior Daylighting Illumination for TDD pipes");
6052 1015 : DayltgInteriorTDDIllum(state);
6053 : }
6054 :
6055 3983633 : for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
6056 1415124 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
6057 :
6058 : // RJH DElight Modification Begin - Call to DElight electric lighting control subroutine
6059 : // Check if the sun is up and the current Thermal Zone hosts a Daylighting:DElight object
6060 2116145 : if (state.dataEnvrn->SunIsUp && thisDaylightControl.TotalDaylRefPoints != 0 &&
6061 701021 : (thisDaylightControl.DaylightMethod == DataDaylighting::DaylightingMethod::DElight)) {
6062 2037 : int zoneNum = thisDaylightControl.zoneIndex;
6063 : // Call DElight interior illuminance and electric lighting control subroutine
6064 2037 : Real64 dPowerReducFac = 1.0; // Return value Electric Lighting Power Reduction Factor for current Zone and Timestep
6065 2037 : Real64 dHISKFFC = state.dataEnvrn->HISKF * DataDElight::LUX2FC;
6066 2037 : Real64 dHISUNFFC = state.dataEnvrn->HISUNF * DataDElight::LUX2FC;
6067 2037 : Real64 dSOLCOS1 = state.dataEnvrn->SOLCOS(1);
6068 2037 : Real64 dSOLCOS2 = state.dataEnvrn->SOLCOS(2);
6069 2037 : Real64 dSOLCOS3 = state.dataEnvrn->SOLCOS(3);
6070 2037 : Real64 dLatitude = state.dataEnvrn->Latitude;
6071 2037 : Real64 dCloudFraction = state.dataEnvrn->CloudFraction;
6072 : // Init Error Flag to 0 (no Warnings or Errors) (returned from DElight)
6073 2037 : int iErrorFlag = 0;
6074 : bool elOpened;
6075 :
6076 : int iReadStatus; // Error File Read Status
6077 4074 : std::string cErrorMsg; // Each DElight Error Message can be up to 200 characters long
6078 : bool bEndofErrFile; // End of Error File flag
6079 :
6080 2037 : DElightManagerF::DElightElecLtgCtrl(len(state.dataHeatBal->Zone(zoneNum).Name),
6081 2037 : state.dataHeatBal->Zone(zoneNum).Name,
6082 : dLatitude,
6083 : dHISKFFC,
6084 : dHISUNFFC,
6085 : dCloudFraction,
6086 : dSOLCOS1,
6087 : dSOLCOS2,
6088 : dSOLCOS3,
6089 : dPowerReducFac,
6090 : iErrorFlag);
6091 : // Check Error Flag for Warnings or Errors returning from DElight
6092 : // RJH 2008-03-07: If no warnings/errors then read refpt illuminances for standard output reporting
6093 2037 : if (iErrorFlag != 0) {
6094 : // Open DElight Electric Lighting Error File for reading
6095 0 : auto iDElightErrorFile = state.files.outputDelightDfdmpFilePath.try_open(state.files.outputControl.delightdfdmp);
6096 0 : elOpened = iDElightErrorFile.good();
6097 :
6098 : // Sequentially read lines in DElight Electric Lighting Error File
6099 : // and process them using standard EPlus warning/error handling calls
6100 0 : bEndofErrFile = false;
6101 0 : iReadStatus = 0;
6102 0 : while (!bEndofErrFile && elOpened) {
6103 0 : auto cErrorLine = iDElightErrorFile.readLine();
6104 0 : if (cErrorLine.eof) {
6105 0 : bEndofErrFile = true;
6106 0 : continue;
6107 : }
6108 :
6109 : // Is the current line a Warning message?
6110 0 : if (has_prefix(cErrorLine.data, "WARNING: ")) {
6111 0 : cErrorMsg = cErrorLine.data.substr(9);
6112 0 : ShowWarningError(state, cErrorMsg);
6113 : }
6114 : // Is the current line an Error message?
6115 0 : if (has_prefix(cErrorLine.data, "ERROR: ")) {
6116 0 : cErrorMsg = cErrorLine.data.substr(7);
6117 0 : ShowSevereError(state, cErrorMsg);
6118 0 : iErrorFlag = 1;
6119 : }
6120 : }
6121 :
6122 : // Close DElight Error File and delete
6123 :
6124 0 : if (elOpened) {
6125 0 : iDElightErrorFile.close();
6126 0 : FileSystem::removeFile(iDElightErrorFile.filePath);
6127 : }
6128 : // If any DElight Error occurred then ShowFatalError to terminate
6129 0 : if (iErrorFlag > 0) {
6130 0 : ShowFatalError(state, "End of DElight Error Messages");
6131 : }
6132 : } else { // RJH 2008-03-07: No errors
6133 : // extract reference point illuminance values from DElight Electric Lighting dump file for reporting
6134 : // Open DElight Electric Lighting Dump File for reading
6135 4074 : auto iDElightErrorFile = state.files.outputDelightEldmpFilePath.try_open(state.files.outputControl.delighteldmp);
6136 2037 : if (iDElightErrorFile.is_open()) {
6137 2037 : elOpened = true;
6138 : } else {
6139 0 : elOpened = false;
6140 : }
6141 :
6142 : // Sequentially read lines in DElight Electric Lighting Dump File
6143 : // and extract refpt illuminances for standard EPlus output handling
6144 2037 : bEndofErrFile = false;
6145 2037 : int iDElightRefPt = 0; // Reference Point number for reading DElight Dump File (eplusout.delighteldmp)
6146 2037 : iReadStatus = 0;
6147 14259 : while (!bEndofErrFile && elOpened) {
6148 6111 : auto line = iDElightErrorFile.read<Real64>();
6149 6111 : Real64 dRefPtIllum = line.data; // tmp var for reading RefPt illuminance
6150 8148 : if (line.eof) {
6151 2037 : bEndofErrFile = true;
6152 2037 : continue;
6153 : }
6154 : // Increment refpt counter
6155 4074 : ++iDElightRefPt;
6156 : // Assure refpt index does not exceed number of refpts in this zone
6157 4074 : if (iDElightRefPt <= thisDaylightControl.TotalDaylRefPoints) {
6158 4074 : thisDaylightControl.DaylIllumAtRefPt(iDElightRefPt) = dRefPtIllum;
6159 : }
6160 : }
6161 :
6162 : // Close DElight Electric Lighting Dump File and delete
6163 2037 : if (elOpened) {
6164 2037 : iDElightErrorFile.close();
6165 2037 : FileSystem::removeFile(iDElightErrorFile.filePath);
6166 : };
6167 : }
6168 : // Store the calculated total zone Power Reduction Factor due to DElight daylighting
6169 : // in the ZoneDaylight structure for later use
6170 2037 : thisDaylightControl.PowerReductionFactor = dPowerReducFac;
6171 : }
6172 : // RJH DElight Modification End - Call to DElight electric lighting control subroutine
6173 : }
6174 :
6175 2568509 : if (state.dataEnvrn->SunIsUp && !state.dataGlobal->DoingSizing) {
6176 894397 : DayltgInteriorMapIllum(state);
6177 : }
6178 21015074 : for (int zoneNum = 1; zoneNum <= state.dataGlobal->NumOfZones; ++zoneNum) {
6179 36909306 : for (int spaceNum : state.dataHeatBal->Zone(zoneNum).spaceIndexes) {
6180 18462741 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
6181 40474011 : for (int SurfNum = thisSpace.WindowSurfaceFirst; SurfNum <= thisSpace.WindowSurfaceLast; ++SurfNum) {
6182 22011270 : state.dataSurface->SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0;
6183 22011270 : if (IS_SHADED(state.dataSurface->SurfWinShadingFlag(SurfNum))) {
6184 171656 : state.dataSurface->SurfWinFracTimeShadingDeviceOn(SurfNum) = 1.0;
6185 : } else {
6186 21839614 : state.dataSurface->SurfWinFracTimeShadingDeviceOn(SurfNum) = 0.0;
6187 : }
6188 : }
6189 : }
6190 : }
6191 2568509 : }
6192 :
6193 2568509 : void manageDaylighting(EnergyPlusData &state)
6194 : {
6195 2568509 : if (state.dataEnvrn->SunIsUp && (state.dataEnvrn->BeamSolarRad + state.dataEnvrn->GndSolarRad + state.dataEnvrn->DifSolarRad > 0.0)) {
6196 6666610 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
6197 5844507 : if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints > 0) {
6198 408450 : if (state.dataViewFactor->EnclSolInfo(enclNum).HasInterZoneWindow) {
6199 1015 : DayltgInterReflIllFrIntWins(state, enclNum);
6200 2030 : for (int daylightCtrlNum : state.dataDaylightingData->enclDaylight(enclNum).daylightControlIndexes) {
6201 1015 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
6202 1015 : DayltgGlareWithIntWins(state, thisDaylightControl.GlareIndexAtRefPt, enclNum);
6203 : }
6204 : }
6205 : }
6206 : }
6207 822103 : DayltgElecLightingControl(state);
6208 1746406 : } else if (state.dataDaylightingData->mapResultsToReport && state.dataGlobal->TimeStep == state.dataGlobal->NumOfTimeStepInHour) {
6209 38 : for (int MapNum = 1; MapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++MapNum) {
6210 20 : ReportIllumMap(state, MapNum);
6211 : }
6212 18 : state.dataDaylightingData->mapResultsToReport = false;
6213 : }
6214 2568509 : }
6215 :
6216 701021 : void DayltgInteriorIllum(EnergyPlusData &state,
6217 : int const daylightCtrlNum) // Daylighting:Controls number
6218 : {
6219 :
6220 : // SUBROUTINE INFORMATION:
6221 : // AUTHOR Fred Winkelmann
6222 : // DATE WRITTEN July 1997
6223 : // MODIFIED March 2000, FCW: interpolate clear-sky daylight factors using
6224 : // HourOfDay/WeightNow and NextHour/WeightNextHour. Previously
6225 : // only HourOfDay was used
6226 : // Jan 2001, FCW: interpolate in slat angle for windows with blinds
6227 : // that have movable slats
6228 : // Oct 2002, LKL: changed interpolation steps to HourOfDay/WeightNow
6229 : // LastHour/WeightPreviousHour
6230 : // Aug 2003, FCW: fix bug that prevented shadingControlType =
6231 : // MEETDAYLIGHTILLUMINANCESETPOINT from working
6232 : // Mar 2004, FCW: fix bug in calc of illuminance setpoint contribution
6233 : // to background luminance: now it is divided by pi to give cd/m2
6234 : // Mar 2004, FCW: modify to handle daylighting through interior windows
6235 : // June 2009, TH: modified for thermochromic windows
6236 : // Jan 2010, TH (CR 7984): added iterations for switchable windows with shading
6237 : // control of MeetDaylightIlluminanceSetpoint and glare control is active
6238 : // Also corrected bugs (CR 7988) for switchable glazings not related to CR 7984
6239 :
6240 : // PURPOSE OF THIS SUBROUTINE:
6241 : // Using daylighting factors and exterior illuminance, determine
6242 : // the current-hour interior daylight illuminance and glare index
6243 : // at each reference point in a space. Deploy window shading window by window
6244 : // if glare control is active for window and if the acceptable glare index
6245 : // is exceeded at both reference points.
6246 :
6247 : // Called by InitSurfaceHeatBalance.
6248 :
6249 : // REFERENCES:
6250 : // Based on DOE-2.1E subroutine DINTIL.
6251 :
6252 701021 : Real64 constexpr tmpSWIterStep(0.05); // step of switching factor, assuming maximum of 20 switching states
6253 :
6254 : int NREFPT; // Number of daylighting reference points
6255 : int ISky; // Sky type index
6256 : int ISky1; // Sky type index values for averaging two sky types
6257 : int ISky2;
6258 701021 : auto &DFSUHR = state.dataDaylightingManager->DFSUHR; // Sun daylight factor for bare/shaded window
6259 701021 : auto &BFSUHR = state.dataDaylightingManager->BFSUHR; // Sun background luminance factor for bare/shaded window
6260 701021 : auto &SFSUHR = state.dataDaylightingManager->SFSUHR; // Sun source luminance factor for bare/shaded window
6261 701021 : auto &HorIllSky = state.dataDaylightingManager->HorIllSky; // Horizontal illuminance for different sky types
6262 701021 : auto &SetPnt = state.dataDaylightingManager->SetPnt; // Illuminance setpoint at reference points (lux)
6263 701021 : auto &GLRNDX = state.dataDaylightingManager->GLRNDX; // Glare index at reference point
6264 701021 : auto &GLRNEW = state.dataDaylightingManager->GLRNEW; // New glare index at reference point
6265 701021 : auto &SFSKHR = state.dataDaylightingManager->SFSKHR; // Sky source luminance factor for sky type (second index), bare/shaded window (first index)
6266 701021 : auto &DFSKHR = state.dataDaylightingManager->DFSKHR; // Sky daylight factor for sky type (second index), bare/shaded window (first index)
6267 : auto &BFSKHR =
6268 701021 : state.dataDaylightingManager->BFSKHR; // Sky background luminance factor for sky type (second index), bare/shaded window (first index)
6269 :
6270 701021 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
6271 701021 : int enclNum = thisDaylightControl.enclIndex;
6272 701021 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
6273 : int ISWFLG; // Switchable glazing flag: =1 if one or more windows in a zone
6274 : // has switchable glazing that adjusts visible transmittance to just meet
6275 : // daylighting setpoint; =0 otherwise.
6276 : int ICtrl; // Window shading control pointer
6277 : Real64 VTRAT; // Ratio between switched and unswitched visible transmittance at normal incidence
6278 : Real64 BACL; // Window background (surround) luminance for glare calc (cd/m2)
6279 : Real64 SkyWeight; // Weighting factor used to average two different sky types
6280 : Real64 HorIllSkyFac; // Ratio between horizontal illuminance from sky horizontal irradiance and
6281 : // luminous efficacy and horizontal illuminance from averaged sky
6282 : bool GlareFlag; // True if maximum glare is exceeded
6283 :
6284 : Real64 VTRatio; // VT (visible transmittance) ratio = VTNow / VTMaster
6285 : Real64 VTNow; // VT of the time step actual TC window
6286 : Real64 VTMaster; // VT of the base/master TC window
6287 :
6288 : // Added variables for glare iterations for switchable glazings
6289 701021 : auto &tmpSWSL1 = state.dataDaylightingManager->tmpSWSL1;
6290 701021 : auto &tmpSWSL2 = state.dataDaylightingManager->tmpSWSL2;
6291 701021 : auto &tmpSWFactor = state.dataDaylightingManager->tmpSWFactor;
6292 701021 : auto &tmpMult = state.dataDaylightingManager->tmpMult;
6293 701021 : auto &GlareOK = state.dataDaylightingManager->GlareOK;
6294 701021 : auto &tmpIllumFromWinAtRefPt = state.dataDaylightingManager->tmpIllumFromWinAtRefPt;
6295 701021 : auto &tmpBackLumFromWinAtRefPt = state.dataDaylightingManager->tmpBackLumFromWinAtRefPt;
6296 701021 : auto &tmpSourceLumFromWinAtRefPt = state.dataDaylightingManager->tmpSourceLumFromWinAtRefPt;
6297 701021 : auto &blnCycle = state.dataDaylightingManager->blnCycle;
6298 :
6299 701021 : bool breakOuterLoop(false);
6300 701021 : bool continueOuterLoop(false);
6301 :
6302 701021 : if (thisDaylightControl.DaylightMethod != DataDaylighting::DaylightingMethod::SplitFlux) return;
6303 :
6304 698984 : NREFPT = thisDaylightControl.TotalDaylRefPoints;
6305 :
6306 : // Three arrays to save original clear and dark (fully switched) states'
6307 : // zone/window daylighting properties.
6308 698984 : if (state.dataDaylightingManager->DayltgInteriorIllum_firstTime) {
6309 62 : int const d1(max(maxval(state.dataHeatBal->Zone, &ZoneData::NumSubSurfaces),
6310 124 : maxval(state.dataDaylightingData->enclDaylight, &DataDaylighting::EnclDaylightCalc::NumOfDayltgExtWins)));
6311 62 : tmpIllumFromWinAtRefPt.allocate(d1, 2, state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
6312 62 : tmpBackLumFromWinAtRefPt.allocate(d1, 2, state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
6313 62 : tmpSourceLumFromWinAtRefPt.allocate(d1, 2, state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
6314 :
6315 62 : SetPnt.allocate(state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
6316 62 : state.dataDaylightingManager->DaylIllum.allocate(state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
6317 62 : GLRNDX.allocate(state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
6318 62 : GLRNEW.allocate(state.dataDaylightingManager->maxNumRefPtInAnyDaylCtrl);
6319 :
6320 62 : state.dataDaylightingManager->DayltgInteriorIllum_firstTime = false;
6321 : }
6322 698984 : tmpIllumFromWinAtRefPt = 0.0;
6323 698984 : tmpBackLumFromWinAtRefPt = 0.0;
6324 698984 : tmpSourceLumFromWinAtRefPt = 0.0;
6325 :
6326 : // Initialize reference point illuminance and window background luminance
6327 1618116 : for (int IL = 1; IL <= NREFPT; ++IL) {
6328 919132 : SetPnt(IL) = thisDaylightControl.IllumSetPoint(IL);
6329 919132 : state.dataDaylightingManager->DaylIllum(IL) = 0.0;
6330 919132 : thisDaylightControl.BacLum(IL) = 0.0;
6331 : }
6332 :
6333 698984 : if (state.dataEnvrn->SkyClearness > 3.0) { // Sky is average of clear and clear turbid
6334 331604 : SkyWeight = min(1.0, (state.dataEnvrn->SkyClearness - 3.0) / 3.0);
6335 331604 : ISky1 = 1;
6336 331604 : ISky2 = 2;
6337 367380 : } else if (state.dataEnvrn->SkyClearness > 1.2) { // Sky is average of clear turbid and intermediate
6338 71209 : SkyWeight = (state.dataEnvrn->SkyClearness - 1.2) / 1.8;
6339 71209 : ISky1 = 2;
6340 71209 : ISky2 = 3;
6341 : } else { // Sky is average of intermediate and overcast
6342 296171 : SkyWeight = min(1.0, max(0.0, (state.dataEnvrn->SkyClearness - 1.0) / 0.2, (state.dataEnvrn->SkyBrightness - 0.05) / 0.4));
6343 296171 : ISky1 = 3;
6344 296171 : ISky2 = 4;
6345 : }
6346 :
6347 : // First loop over exterior windows associated with this zone. The window may be an exterior window in
6348 : // the zone or an exterior window in an adjacent zone that shares an interior window with the zone.
6349 : // Find contribution of each window to the daylight illum and to the glare numerator at each reference point.
6350 : // Use shading flags set in WindowShadingManager.
6351 2090945 : for (int loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
6352 1391961 : int IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
6353 :
6354 : // Added TH 6/29/2009 for thermochromic windows
6355 1391961 : VTRatio = 1.0;
6356 1391961 : if (NREFPT > 0) {
6357 1391961 : int const IConst = state.dataSurface->Surface(IWin).Construction;
6358 1391961 : if (state.dataConstruction->Construct(IConst).TCFlag == 1) {
6359 : // For thermochromic windows, daylight and glare factors are always calculated
6360 : // based on the master construction. They need to be adjusted by the VTRatio, including:
6361 : // ZoneDaylight()%DaylIllFacSky, DaylIllFacSun, DaylIllFacSunDisk; DaylBackFacSky,
6362 : // DaylBackFacSun, DaylBackFacSunDisk, DaylSourceFacSky, DaylSourceFacSun, DaylSourceFacSunDisk
6363 0 : VTNow = General::POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef);
6364 0 : VTMaster =
6365 0 : General::POLYF(1.0, state.dataConstruction->Construct(state.dataConstruction->Construct(IConst).TCMasterConst).TransVisBeamCoef);
6366 0 : VTRatio = VTNow / VTMaster;
6367 : }
6368 : }
6369 :
6370 2871465 : bool ShadedOrDiffusingGlassWin = state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF &&
6371 4080192 : (IS_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) || state.dataSurface->SurfWinSolarDiffusing(IWin));
6372 :
6373 : // Loop over reference points
6374 3541941 : for (int IL = 1; IL <= NREFPT; ++IL) {
6375 :
6376 : // Daylight factors for current sun position
6377 10749900 : for (ISky = 1; ISky <= 4; ++ISky) {
6378 :
6379 : // ===Bare window===
6380 8599920 : DFSKHR(1, ISky) =
6381 8599920 : VTRatio *
6382 17199840 : (state.dataGlobal->WeightNow * thisDaylightControl.DaylIllFacSky(state.dataGlobal->HourOfDay, 1, ISky, IL, loop) +
6383 8599920 : state.dataGlobal->WeightPreviousHour * thisDaylightControl.DaylIllFacSky(state.dataGlobal->PreviousHour, 1, ISky, IL, loop));
6384 :
6385 8599920 : if (ISky == 1)
6386 2149980 : DFSUHR(1) =
6387 2149980 : VTRatio *
6388 4299960 : (state.dataGlobal->WeightNow * (thisDaylightControl.DaylIllFacSun(state.dataGlobal->HourOfDay, 1, IL, loop) +
6389 4299960 : thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, 1, IL, loop)) +
6390 4299960 : state.dataGlobal->WeightPreviousHour * (thisDaylightControl.DaylIllFacSun(state.dataGlobal->PreviousHour, 1, IL, loop) +
6391 2149980 : thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, 1, IL, loop)));
6392 :
6393 8599920 : BFSKHR(1, ISky) =
6394 8599920 : VTRatio *
6395 17199840 : (state.dataGlobal->WeightNow * thisDaylightControl.DaylBackFacSky(state.dataGlobal->HourOfDay, 1, ISky, IL, loop) +
6396 8599920 : state.dataGlobal->WeightPreviousHour * thisDaylightControl.DaylBackFacSky(state.dataGlobal->PreviousHour, 1, ISky, IL, loop));
6397 :
6398 8599920 : if (ISky == 1)
6399 2149980 : BFSUHR(1) =
6400 6449940 : VTRatio * (state.dataGlobal->WeightNow * (thisDaylightControl.DaylBackFacSun(state.dataGlobal->HourOfDay, 1, IL, loop) +
6401 4299960 : thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->HourOfDay, 1, IL, loop)) +
6402 4299960 : state.dataGlobal->WeightPreviousHour *
6403 4299960 : (thisDaylightControl.DaylBackFacSun(state.dataGlobal->PreviousHour, 1, IL, loop) +
6404 2149980 : thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->PreviousHour, 1, IL, loop)));
6405 :
6406 8599920 : SFSKHR(1, ISky) =
6407 8599920 : VTRatio *
6408 17199840 : (state.dataGlobal->WeightNow * thisDaylightControl.DaylSourceFacSky(state.dataGlobal->HourOfDay, 1, ISky, IL, loop) +
6409 8599920 : state.dataGlobal->WeightPreviousHour * thisDaylightControl.DaylSourceFacSky(state.dataGlobal->PreviousHour, 1, ISky, IL, loop));
6410 :
6411 8599920 : if (ISky == 1)
6412 2149980 : SFSUHR(1) = VTRatio *
6413 4299960 : (state.dataGlobal->WeightNow * (thisDaylightControl.DaylSourceFacSun(state.dataGlobal->HourOfDay, 1, IL, loop) +
6414 4299960 : thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->HourOfDay, 1, IL, loop)) +
6415 4299960 : state.dataGlobal->WeightPreviousHour *
6416 4299960 : (thisDaylightControl.DaylSourceFacSun(state.dataGlobal->PreviousHour, 1, IL, loop) +
6417 2149980 : thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->PreviousHour, 1, IL, loop)));
6418 :
6419 8599920 : if (ShadedOrDiffusingGlassWin) {
6420 :
6421 : // ===Shaded window or window with diffusing glass===
6422 376996 : if (!state.dataSurface->SurfWinMovableSlats(IWin)) {
6423 : // Shade, screen, blind with fixed slats, or diffusing glass
6424 1130988 : DFSKHR(2, ISky) = VTRatio * (state.dataGlobal->WeightNow *
6425 753992 : thisDaylightControl.DaylIllFacSky(state.dataGlobal->HourOfDay, 2, ISky, IL, loop) +
6426 753992 : state.dataGlobal->WeightPreviousHour *
6427 376996 : thisDaylightControl.DaylIllFacSky(state.dataGlobal->PreviousHour, 2, ISky, IL, loop));
6428 :
6429 376996 : if (ISky == 1) {
6430 94249 : DFSUHR(2) =
6431 188498 : VTRatio * (state.dataGlobal->WeightNow * thisDaylightControl.DaylIllFacSun(state.dataGlobal->HourOfDay, 2, IL, loop) +
6432 188498 : state.dataGlobal->WeightPreviousHour *
6433 94249 : thisDaylightControl.DaylIllFacSun(state.dataGlobal->PreviousHour, 2, IL, loop));
6434 :
6435 94249 : if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin))
6436 282747 : DFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow *
6437 188498 : thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, 2, IL, loop) +
6438 188498 : state.dataGlobal->WeightPreviousHour *
6439 94249 : thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, 2, IL, loop));
6440 : }
6441 :
6442 1130988 : BFSKHR(2, ISky) = VTRatio * (state.dataGlobal->WeightNow *
6443 753992 : thisDaylightControl.DaylBackFacSky(state.dataGlobal->HourOfDay, 2, ISky, IL, loop) +
6444 753992 : state.dataGlobal->WeightPreviousHour *
6445 376996 : thisDaylightControl.DaylBackFacSky(state.dataGlobal->PreviousHour, 2, ISky, IL, loop));
6446 :
6447 376996 : if (ISky == 1) {
6448 94249 : BFSUHR(2) = VTRatio *
6449 188498 : (state.dataGlobal->WeightNow * thisDaylightControl.DaylBackFacSun(state.dataGlobal->HourOfDay, 2, IL, loop) +
6450 188498 : state.dataGlobal->WeightPreviousHour *
6451 94249 : thisDaylightControl.DaylBackFacSun(state.dataGlobal->PreviousHour, 2, IL, loop));
6452 94249 : if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin))
6453 282747 : BFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow *
6454 188498 : thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->HourOfDay, 2, IL, loop) +
6455 188498 : state.dataGlobal->WeightPreviousHour *
6456 94249 : thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->PreviousHour, 2, IL, loop));
6457 : }
6458 :
6459 1130988 : SFSKHR(2, ISky) = VTRatio * (state.dataGlobal->WeightNow *
6460 753992 : thisDaylightControl.DaylSourceFacSky(state.dataGlobal->HourOfDay, 2, ISky, IL, loop) +
6461 753992 : state.dataGlobal->WeightPreviousHour *
6462 376996 : thisDaylightControl.DaylSourceFacSky(state.dataGlobal->PreviousHour, 2, ISky, IL, loop));
6463 :
6464 376996 : if (ISky == 1) {
6465 282747 : SFSUHR(2) = VTRatio * (state.dataGlobal->WeightNow *
6466 188498 : thisDaylightControl.DaylSourceFacSun(state.dataGlobal->HourOfDay, 2, IL, loop) +
6467 188498 : state.dataGlobal->WeightPreviousHour *
6468 94249 : thisDaylightControl.DaylSourceFacSun(state.dataGlobal->PreviousHour, 2, IL, loop));
6469 94249 : if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin))
6470 282747 : SFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow *
6471 188498 : thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->HourOfDay, 2, IL, loop) +
6472 188498 : state.dataGlobal->WeightPreviousHour *
6473 94249 : thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->PreviousHour, 2, IL, loop));
6474 : }
6475 :
6476 : } else { // Blind with movable slats
6477 0 : int SurfWinSlatsAngIndex = state.dataSurface->SurfWinSlatsAngIndex(IWin);
6478 0 : Real64 SurfWinSlatsAngInterpFac = state.dataSurface->SurfWinSlatsAngInterpFac(IWin);
6479 0 : Real64 DaylIllFacSkyNow = General::InterpGeneral(
6480 0 : thisDaylightControl.DaylIllFacSky(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
6481 : thisDaylightControl.DaylIllFacSky(
6482 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
6483 0 : SurfWinSlatsAngInterpFac);
6484 0 : Real64 DaylBackFacSkyNow = General::InterpGeneral(
6485 0 : thisDaylightControl.DaylBackFacSky(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
6486 : thisDaylightControl.DaylBackFacSky(
6487 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
6488 0 : SurfWinSlatsAngInterpFac);
6489 0 : Real64 DaylSourceFacSkyNow = General::InterpGeneral(
6490 0 : thisDaylightControl.DaylSourceFacSky(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
6491 : thisDaylightControl.DaylSourceFacSky(
6492 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
6493 0 : SurfWinSlatsAngInterpFac);
6494 0 : Real64 DaylIllFacSkyPrev = General::InterpGeneral(
6495 0 : thisDaylightControl.DaylIllFacSky(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
6496 : thisDaylightControl.DaylIllFacSky(
6497 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
6498 0 : SurfWinSlatsAngInterpFac);
6499 0 : Real64 DaylBackFacSkyPrev = General::InterpGeneral(
6500 0 : thisDaylightControl.DaylBackFacSky(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
6501 : thisDaylightControl.DaylBackFacSky(
6502 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
6503 0 : SurfWinSlatsAngInterpFac);
6504 0 : Real64 DaylSourceFacSkyPrev = General::InterpGeneral(
6505 0 : thisDaylightControl.DaylSourceFacSky(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ISky, IL, loop),
6506 : thisDaylightControl.DaylSourceFacSky(
6507 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, IL, loop),
6508 0 : SurfWinSlatsAngInterpFac);
6509 :
6510 0 : DFSKHR(2, ISky) =
6511 0 : VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSkyNow + state.dataGlobal->WeightPreviousHour * DaylIllFacSkyPrev);
6512 0 : BFSKHR(2, ISky) =
6513 0 : VTRatio * (state.dataGlobal->WeightNow * DaylBackFacSkyNow + state.dataGlobal->WeightPreviousHour * DaylBackFacSkyPrev);
6514 0 : SFSKHR(2, ISky) = VTRatio * (state.dataGlobal->WeightNow * DaylSourceFacSkyNow +
6515 0 : state.dataGlobal->WeightPreviousHour * DaylSourceFacSkyPrev);
6516 :
6517 0 : if (ISky == 1) {
6518 0 : Real64 DaylIllFacSunNow = General::InterpGeneral(
6519 0 : thisDaylightControl.DaylIllFacSun(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
6520 : thisDaylightControl.DaylIllFacSun(
6521 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6522 0 : SurfWinSlatsAngInterpFac);
6523 0 : Real64 DaylBackFacSunNow = General::InterpGeneral(
6524 0 : thisDaylightControl.DaylBackFacSun(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
6525 : thisDaylightControl.DaylBackFacSun(
6526 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6527 0 : SurfWinSlatsAngInterpFac);
6528 0 : Real64 DaylSourceFacSunNow = General::InterpGeneral(
6529 0 : thisDaylightControl.DaylSourceFacSun(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
6530 : thisDaylightControl.DaylSourceFacSun(
6531 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6532 0 : SurfWinSlatsAngInterpFac);
6533 0 : Real64 DaylIllFacSunPrev = General::InterpGeneral(
6534 0 : thisDaylightControl.DaylIllFacSun(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
6535 : thisDaylightControl.DaylIllFacSun(
6536 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6537 0 : SurfWinSlatsAngInterpFac);
6538 0 : Real64 DaylBackFacSunPrev = General::InterpGeneral(
6539 0 : thisDaylightControl.DaylBackFacSun(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
6540 : thisDaylightControl.DaylBackFacSun(
6541 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6542 0 : SurfWinSlatsAngInterpFac);
6543 0 : Real64 DaylSourceFacSunPrev = General::InterpGeneral(
6544 0 : thisDaylightControl.DaylSourceFacSun(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
6545 : thisDaylightControl.DaylSourceFacSun(
6546 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6547 0 : SurfWinSlatsAngInterpFac);
6548 0 : DFSUHR(2) =
6549 0 : VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSunNow + state.dataGlobal->WeightPreviousHour * DaylIllFacSunPrev);
6550 0 : BFSUHR(2) = VTRatio *
6551 0 : (state.dataGlobal->WeightNow * DaylBackFacSunNow + state.dataGlobal->WeightPreviousHour * DaylBackFacSunPrev);
6552 0 : SFSUHR(2) = VTRatio * (state.dataGlobal->WeightNow * DaylSourceFacSunNow +
6553 0 : state.dataGlobal->WeightPreviousHour * DaylSourceFacSunPrev);
6554 :
6555 : // We add the contribution from the solar disk if slats do not block beam solar
6556 : // TH CR 8010, DaylIllFacSunDisk needs to be interpolated
6557 0 : if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin)) {
6558 0 : Real64 DaylIllFacSunDiskNow = General::InterpGeneral(
6559 0 : thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
6560 : thisDaylightControl.DaylIllFacSunDisk(
6561 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6562 0 : SurfWinSlatsAngInterpFac);
6563 0 : Real64 DaylBackFacSunDiskNow = General::InterpGeneral(
6564 0 : thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
6565 : thisDaylightControl.DaylBackFacSunDisk(
6566 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6567 0 : SurfWinSlatsAngInterpFac);
6568 0 : Real64 DaylSourceFacSunDiskNow = General::InterpGeneral(
6569 0 : thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, IL, loop),
6570 : thisDaylightControl.DaylSourceFacSunDisk(
6571 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6572 0 : SurfWinSlatsAngInterpFac);
6573 0 : Real64 DaylIllFacSunDiskPrev = General::InterpGeneral(
6574 0 : thisDaylightControl.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
6575 : thisDaylightControl.DaylIllFacSunDisk(
6576 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6577 0 : SurfWinSlatsAngInterpFac);
6578 0 : Real64 DaylBackFacSunDiskPrev = General::InterpGeneral(
6579 0 : thisDaylightControl.DaylBackFacSunDisk(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
6580 : thisDaylightControl.DaylBackFacSunDisk(
6581 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6582 0 : SurfWinSlatsAngInterpFac);
6583 0 : Real64 DaylSourceFacSunDiskPrev = General::InterpGeneral(
6584 0 : thisDaylightControl.DaylSourceFacSunDisk(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, IL, loop),
6585 : thisDaylightControl.DaylSourceFacSunDisk(
6586 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), IL, loop),
6587 0 : SurfWinSlatsAngInterpFac);
6588 0 : DFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSunDiskNow +
6589 0 : state.dataGlobal->WeightPreviousHour * DaylIllFacSunDiskPrev);
6590 0 : BFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow * DaylBackFacSunDiskNow +
6591 0 : state.dataGlobal->WeightPreviousHour * DaylBackFacSunDiskPrev);
6592 0 : SFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow * DaylSourceFacSunDiskNow +
6593 0 : state.dataGlobal->WeightPreviousHour * DaylSourceFacSunDiskPrev);
6594 : }
6595 : }
6596 : } // End of check if window has blind with movable slats
6597 : } // End of check if window is shaded or has diffusing glass
6598 : } // End of sky type loop, ISky
6599 :
6600 : // Get illuminance at ref point from bare and shaded window by
6601 : // multiplying daylight factors by exterior horizontal illuminance
6602 :
6603 : // Adding 0.001 in the following prevents zero HorIllSky in early morning or late evening when sun
6604 : // is up in the present time step but GILSK(ISky,HourOfDay) and GILSK(ISky,NextHour) are both zero.
6605 10749900 : for (ISky = 1; ISky <= 4; ++ISky) {
6606 : // HorIllSky(ISky) = WeightNow * GILSK(ISky,HourOfDay) + WeightNextHour * GILSK(ISky,NextHour) + 0.001
6607 25799760 : HorIllSky(ISky) = state.dataGlobal->WeightNow * state.dataDaylightingManager->GILSK(state.dataGlobal->HourOfDay, ISky) +
6608 17199840 : state.dataGlobal->WeightPreviousHour * state.dataDaylightingManager->GILSK(state.dataGlobal->PreviousHour, ISky) +
6609 : 0.001;
6610 : }
6611 :
6612 : // HISKF is current time step horizontal illuminance from sky, calculated in DayltgLuminousEfficacy,
6613 : // which is called in WeatherManager. HISUNF is current time step horizontal illuminance from sun,
6614 : // also calculated in DayltgLuminousEfficacy.
6615 :
6616 2149980 : HorIllSkyFac = state.dataEnvrn->HISKF / ((1 - SkyWeight) * HorIllSky(ISky2) + SkyWeight * HorIllSky(ISky1));
6617 :
6618 4394209 : for (int IS = 1; IS <= 2; ++IS) {
6619 4299960 : if (IS == 2 && !ShadedOrDiffusingGlassWin) break;
6620 :
6621 2244229 : thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL) =
6622 4488458 : DFSUHR(IS) * state.dataEnvrn->HISUNF +
6623 2244229 : HorIllSkyFac * (DFSKHR(IS, ISky1) * SkyWeight * HorIllSky(ISky1) + DFSKHR(IS, ISky2) * (1.0 - SkyWeight) * HorIllSky(ISky2));
6624 2244229 : thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL) =
6625 4488458 : BFSUHR(IS) * state.dataEnvrn->HISUNF +
6626 2244229 : HorIllSkyFac * (BFSKHR(IS, ISky1) * SkyWeight * HorIllSky(ISky1) + BFSKHR(IS, ISky2) * (1.0 - SkyWeight) * HorIllSky(ISky2));
6627 :
6628 2244229 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, IS, IL) =
6629 4488458 : SFSUHR(IS) * state.dataEnvrn->HISUNF +
6630 2244229 : HorIllSkyFac * (SFSKHR(IS, ISky1) * SkyWeight * HorIllSky(ISky1) + SFSKHR(IS, ISky2) * (1.0 - SkyWeight) * HorIllSky(ISky2));
6631 :
6632 2244229 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, IS, IL) = max(thisDaylightControl.SourceLumFromWinAtRefPt(loop, IS, IL), 0.0);
6633 :
6634 : // Added TH 1/21/2010 - save the original clear and dark (fully switched) states'
6635 : // zone daylighting values, needed for switachable glazings
6636 2244229 : tmpIllumFromWinAtRefPt(loop, IS, IL) = thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL);
6637 2244229 : tmpBackLumFromWinAtRefPt(loop, IS, IL) = thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL);
6638 2244229 : tmpSourceLumFromWinAtRefPt(loop, IS, IL) = thisDaylightControl.SourceLumFromWinAtRefPt(loop, IS, IL);
6639 : } // IS
6640 :
6641 : } // End of reference point loop, IL
6642 : } // End of first loop over exterior windows associated with this zone
6643 :
6644 : // Initialize flag that one or more windows has switchable glazing
6645 : // control that adjusts visible transmittance to just meet dayltg setpoint
6646 : // (and the window has not already been switched)
6647 698984 : ISWFLG = 0;
6648 :
6649 : // Second loop over windows. Find total daylight illuminance and background luminance
6650 : // for each ref pt from all exterior windows associated with the zone. Use shading flags.
6651 : // This illuminance excludes contribution of inter-reflected illuminance produced by solar
6652 : // entering the zone through interior windows (which is calculated in DayltgInterReflIllFrIntWins.
6653 :
6654 2090945 : for (int loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
6655 1391961 : int IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
6656 1391961 : ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
6657 1391961 : if (state.dataSurface->Surface(IWin).HasShadeControl && ISWFLG == 0) {
6658 88929 : if (state.dataSurface->WindowShadingControl(ICtrl).shadingControlType == WindowShadingControlType::MeetDaylIlumSetp &&
6659 665 : state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::GlassConditionallyLightened)
6660 665 : ISWFLG = 1;
6661 : }
6662 :
6663 : // Determine if illuminance contribution is from bare or shaded window
6664 : // For switchable glazings with shading control type of WSCT_MeetDaylIlumSetp,
6665 : // the shading flag is initialized at GlassConditionallyLightened (20), and
6666 : // the window is initialized at clear state: IS = 1
6667 : // For other windows with glare control, the shading flag is initialized at >10, to be determined
6668 1391961 : int IS = findWinShadingStatus(state, IWin);
6669 :
6670 3541941 : for (int IL = 1; IL <= NREFPT; ++IL) {
6671 2149980 : state.dataDaylightingManager->DaylIllum(IL) += thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL);
6672 2149980 : thisDaylightControl.BacLum(IL) += thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL);
6673 : }
6674 : } // End of second window loop over exterior windows associated with this zone
6675 :
6676 : // Optical switching control (e.g. electrochromic glass) to adjust
6677 : // window's vis trans downward so daylight level equals or is as
6678 : // close as possible to the illuminance setpoint at first reference point.
6679 : // Assumes vis trans in the fully switched state is less than that in the
6680 : // unswitched state. Assumes some windows in a space may have this control and
6681 : // others not.
6682 :
6683 698984 : auto &DILLSW = state.dataDaylightingManager->DILLSW;
6684 698984 : auto &DILLUN = state.dataDaylightingManager->DILLUN;
6685 698984 : auto &previously_shaded = state.dataDaylightingManager->previously_shaded;
6686 :
6687 : // If daylight illuminance is above setpoint, allow switching
6688 698984 : if (ISWFLG != 0 && state.dataDaylightingManager->DaylIllum(1) > SetPnt(1)) {
6689 :
6690 : // Third loop over windows. Get illuminance at ref pt 1 from
6691 : // windows that can be switched (DILLSW) with a group and those that can't (DILLUN).
6692 : // Windows that can be switched are initially in the unswitched state. For subsequent
6693 : // groups the windows in previous groups are fully switched.
6694 385 : DILLSW = 0.0;
6695 385 : DILLUN = 0.0;
6696 385 : previously_shaded = false;
6697 :
6698 385 : int count = 0;
6699 1155 : for (std::size_t igroup = 1; igroup <= thisDaylightControl.ShadeDeployOrderExtWins.size(); igroup++) {
6700 770 : std::vector<int> const &listOfExtWin = thisDaylightControl.ShadeDeployOrderExtWins[igroup - 1];
6701 2310 : for (const auto IWin : listOfExtWin) {
6702 1540 : ++count;
6703 : // need to map back to the original order of the "loop" to not change all the other data structures
6704 1540 : int loop = thisDaylightControl.MapShdOrdToLoopNum(count);
6705 1540 : if (loop > 0) {
6706 1540 : ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
6707 1540 : int IS = findWinShadingStatus(state, IWin);
6708 1540 : if (state.dataSurface->Surface(IWin).HasShadeControl) {
6709 3850 : if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::GlassConditionallyLightened &&
6710 2310 : state.dataSurface->WindowShadingControl(ICtrl).shadingControlType == WindowShadingControlType::MeetDaylIlumSetp &&
6711 770 : !previously_shaded(loop)) {
6712 770 : DILLSW(igroup) += thisDaylightControl.IllumFromWinAtRefPt(loop, IS, 1);
6713 770 : previously_shaded(loop) = true;
6714 : } else {
6715 770 : if (!previously_shaded(loop)) {
6716 770 : DILLUN(igroup) += thisDaylightControl.IllumFromWinAtRefPt(loop, IS, 1);
6717 : } else {
6718 0 : DILLUN(igroup) += thisDaylightControl.IllumFromWinAtRefPt(loop, 2, 1); // use the shaded state if previously shaded
6719 : }
6720 : }
6721 : }
6722 : }
6723 : }
6724 : } // End of third window loop, IWin
6725 :
6726 : // Transmittance multiplier
6727 1155 : for (std::size_t igroup = 1; igroup <= thisDaylightControl.ShadeDeployOrderExtWins.size(); igroup++) {
6728 770 : state.dataDaylightingManager->ASETIL(igroup) = (SetPnt(1) - DILLUN(igroup)) / (DILLSW(igroup) + 0.00001);
6729 : }
6730 :
6731 : // ASETIL < 1 means there's enough light, so check for switching
6732 :
6733 : // Fourth loop over windows to determine which to switch
6734 : // iterate in the order that the shades are specified in WindowShadeControl
6735 385 : count = 0;
6736 385 : breakOuterLoop = false;
6737 385 : continueOuterLoop = false;
6738 1155 : for (std::size_t igroup = 1; igroup <= thisDaylightControl.ShadeDeployOrderExtWins.size(); igroup++) {
6739 :
6740 770 : std::vector<int> const &listOfExtWin = thisDaylightControl.ShadeDeployOrderExtWins[igroup - 1];
6741 770 : auto &thisTVIS1 = state.dataDaylightingManager->TVIS1(igroup);
6742 770 : auto &thisTVIS2 = state.dataDaylightingManager->TVIS2(igroup);
6743 770 : auto &thisASETIL = state.dataDaylightingManager->ASETIL(igroup);
6744 :
6745 2310 : for (const auto IWin : listOfExtWin) {
6746 1540 : ++count;
6747 : // need to map back to the original order of the "loop" to not change all the other data structures
6748 1540 : int loop = thisDaylightControl.MapShdOrdToLoopNum(count);
6749 1540 : if (loop > 0) {
6750 1540 : if (thisASETIL < 1.0) {
6751 :
6752 1022 : ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
6753 1022 : if (!state.dataSurface->Surface(IWin).HasShadeControl) {
6754 0 : continueOuterLoop = true;
6755 0 : continue;
6756 : }
6757 2044 : if (state.dataSurface->SurfWinShadingFlag(IWin) != WinShadingType::GlassConditionallyLightened ||
6758 742 : state.dataSurface->WindowShadingControl(ICtrl).shadingControlType != WindowShadingControlType::MeetDaylIlumSetp) {
6759 280 : continueOuterLoop = true;
6760 280 : continue;
6761 : }
6762 :
6763 742 : int const IConst = state.dataSurface->SurfActiveConstruction(IWin);
6764 : // Vis trans at normal incidence of unswitched glass
6765 1484 : thisTVIS1 = General::POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef) *
6766 742 : state.dataSurface->SurfWinGlazedFrac(IWin);
6767 :
6768 : // Vis trans at normal incidence of fully switched glass
6769 742 : int const IConstShaded = state.dataSurface->Surface(IWin).activeShadedConstruction;
6770 1484 : thisTVIS2 = General::POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) *
6771 742 : state.dataSurface->SurfWinGlazedFrac(IWin);
6772 :
6773 : // Reset shading flag to indicate that window is shaded by being partially or fully switched
6774 742 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::SwitchableGlazing;
6775 :
6776 : // ASETIL < 0 means illuminance from non-daylight-switchable windows exceeds setpoint,
6777 : // so completely switch all daylight-switchable windows to minimize solar gain
6778 742 : if (thisASETIL <= 0.0) {
6779 0 : state.dataSurface->SurfWinSwitchingFactor(IWin) = 1.0;
6780 0 : state.dataSurface->SurfWinVisTransSelected(IWin) = thisTVIS2;
6781 : } else {
6782 : // Case where 0 < ASETIL < 1: darken glass in all
6783 : // daylight-switchable windows to just meet illuminance setpoint
6784 : // From this equation: SETPNT(1) = DILLUN + DILLSW/TVIS1 * VisTransSelected
6785 742 : state.dataSurface->SurfWinVisTransSelected(IWin) = max(thisTVIS2, thisASETIL * thisTVIS1) + 0.000001;
6786 742 : state.dataSurface->SurfWinSwitchingFactor(IWin) =
6787 742 : (thisTVIS1 - state.dataSurface->SurfWinVisTransSelected(IWin)) / (thisTVIS1 - thisTVIS2 + 0.000001);
6788 : // bound switching factor between 0 and 1
6789 742 : state.dataSurface->SurfWinSwitchingFactor(IWin) = min(1.0, state.dataSurface->SurfWinSwitchingFactor(IWin));
6790 742 : state.dataSurface->SurfWinSwitchingFactor(IWin) = max(0.0, state.dataSurface->SurfWinSwitchingFactor(IWin));
6791 : }
6792 :
6793 : // Adjust daylight quantities based on ratio between switched and unswitched visible transmittance
6794 1484 : for (int IL = 1; IL <= NREFPT; ++IL) {
6795 : // DaylIllum(IL) and BacLum(IL) were calculated at the clear state: IS = 1,
6796 : // and need to adjusted for intermediate switched state at VisTransSelected: IS = 2
6797 742 : int IS = 1;
6798 742 : VTRAT = state.dataSurface->SurfWinVisTransSelected(IWin) / (thisTVIS1 + 0.000001);
6799 742 : state.dataDaylightingManager->DaylIllum(IL) += (VTRAT - 1.0) * thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL);
6800 742 : thisDaylightControl.BacLum(IL) += (VTRAT - 1.0) * thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL);
6801 :
6802 : // Adjust illum, background illum and source luminance for this window in intermediate switched state
6803 : // for later use in the DayltgGlare calc because SurfaceWindow(IWin)%ShadingFlag = WinShadingType::SwitchableGlazing = 2
6804 742 : IS = 2;
6805 742 : VTRAT = state.dataSurface->SurfWinVisTransSelected(IWin) / (thisTVIS2 + 0.000001);
6806 742 : thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL) = VTRAT * tmpIllumFromWinAtRefPt(loop, IS, IL);
6807 742 : thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL) = VTRAT * tmpBackLumFromWinAtRefPt(loop, IS, IL);
6808 742 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, IS, IL) = VTRAT * tmpSourceLumFromWinAtRefPt(loop, IS, IL);
6809 : } // IL
6810 : } // ASETIL < 1
6811 : }
6812 : // If new daylight does not exceed the illuminance setpoint, done, no more checking other groups of switchable glazings
6813 1260 : if (state.dataDaylightingManager->DaylIllum(1) <= SetPnt(1)) {
6814 0 : breakOuterLoop = true;
6815 0 : break;
6816 : }
6817 : }
6818 770 : if (breakOuterLoop) break;
6819 770 : if (continueOuterLoop) continue;
6820 : } // End of fourth window loop
6821 :
6822 : } // ISWFLG /= 0 .AND. DaylIllum(1) > SETPNT(1)
6823 :
6824 : // loop over windows to do luminance based control
6825 698984 : int count = 0;
6826 769706 : for (std::size_t igroup = 1; igroup <= thisDaylightControl.ShadeDeployOrderExtWins.size(); igroup++) {
6827 160981 : for (int const IWin : thisDaylightControl.ShadeDeployOrderExtWins[igroup - 1]) {
6828 90259 : ++count;
6829 90259 : ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
6830 90259 : WindowShadingControlType shCtrlType = state.dataSurface->WindowShadingControl(ICtrl).shadingControlType;
6831 90259 : if (!((shCtrlType == WindowShadingControlType::HiSolar_HiLumin_OffMidNight) ||
6832 : (shCtrlType == WindowShadingControlType::HiSolar_HiLumin_OffSunset) ||
6833 : (shCtrlType == WindowShadingControlType::HiSolar_HiLumin_OffNextMorning)))
6834 88929 : continue;
6835 : // need to map back to the original order of the "loop" to not change all the other data structures
6836 1330 : int loop = thisDaylightControl.MapShdOrdToLoopNum(count);
6837 1330 : if (loop > 0) {
6838 1330 : WinShadingType currentFlag = state.dataSurface->SurfWinShadingFlag(IWin);
6839 1330 : WinShadingType ShType = state.dataSurface->WindowShadingControl(ICtrl).ShadingType;
6840 1330 : if ((currentFlag == WinShadingType::IntShadeConditionallyOff) || (currentFlag == WinShadingType::GlassConditionallyLightened) ||
6841 714 : (currentFlag == WinShadingType::ExtShadeConditionallyOff) || (currentFlag == WinShadingType::IntBlindConditionallyOff) ||
6842 714 : (currentFlag == WinShadingType::ExtBlindConditionallyOff) || (currentFlag == WinShadingType::BGShadeConditionallyOff) ||
6843 : (currentFlag == WinShadingType::BGBlindConditionallyOff)) {
6844 616 : if (thisDaylightControl.SourceLumFromWinAtRefPt(loop, 1, 1) > state.dataSurface->WindowShadingControl(ICtrl).SetPoint2) {
6845 : // shade on if luminance of this window is above setpoint
6846 0 : state.dataSurface->SurfWinShadingFlag(IWin) = ShType;
6847 : // update total illuminance and background luminance
6848 0 : for (int IL = 1; IL <= NREFPT; ++IL) {
6849 0 : state.dataDaylightingManager->DaylIllum(IL) +=
6850 0 : thisDaylightControl.IllumFromWinAtRefPt(loop, 2, IL) - thisDaylightControl.IllumFromWinAtRefPt(loop, 1, IL);
6851 0 : thisDaylightControl.BacLum(IL) +=
6852 0 : thisDaylightControl.BackLumFromWinAtRefPt(loop, 2, IL) - thisDaylightControl.BackLumFromWinAtRefPt(loop, 1, IL);
6853 : }
6854 : } else {
6855 : // shade off if luminance is below setpoint
6856 616 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::ShadeOff;
6857 : }
6858 : }
6859 : }
6860 : }
6861 : }
6862 :
6863 : // Calculate glare index at each reference point assuming the daylight illuminance setpoint is
6864 : // met at both reference points, either by daylight or electric lights
6865 1618116 : for (int IL = 1; IL <= NREFPT; ++IL) {
6866 919132 : BACL = max(SetPnt(IL) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect / DataGlobalConstants::Pi,
6867 919132 : thisDaylightControl.BacLum(IL));
6868 : // DayltgGlare uses ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,1,loop) for unshaded windows, and
6869 : // ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for shaded windows
6870 919132 : DayltgGlare(state, IL, BACL, GLRNDX(IL), daylightCtrlNum);
6871 : }
6872 :
6873 : // Check if glare level is less than maximum allowed at each ref pt. If maximum
6874 : // is exceeded at either ref pt, attempt to reduce glare to acceptable level by closing
6875 : // shading device on windows that have shades that have not already been closed.
6876 698984 : GlareFlag = false;
6877 1476557 : for (int IL = 1; IL <= NREFPT; ++IL) {
6878 888728 : if (GLRNDX(IL) > thisDaylightControl.MaxGlareallowed) {
6879 111155 : GlareFlag = true;
6880 111155 : break;
6881 : }
6882 : }
6883 :
6884 698984 : auto &WDAYIL = state.dataDaylightingManager->WDAYIL;
6885 698984 : auto &WBACLU = state.dataDaylightingManager->WBACLU;
6886 698984 : auto &RDAYIL = state.dataDaylightingManager->RDAYIL;
6887 698984 : auto &RBACLU = state.dataDaylightingManager->RBACLU;
6888 698984 : if (GlareFlag) {
6889 : // Glare is too high at a ref pt. Loop through windows.
6890 111155 : int count = 0;
6891 :
6892 111155 : continueOuterLoop = false;
6893 151011 : for (std::size_t igroup = 1; igroup <= thisDaylightControl.ShadeDeployOrderExtWins.size(); igroup++) {
6894 :
6895 53663 : std::vector<int> const &listOfExtWin = thisDaylightControl.ShadeDeployOrderExtWins[igroup - 1];
6896 53663 : auto &thisTVIS1 = state.dataDaylightingManager->TVIS1(igroup);
6897 53663 : auto &thisTVIS2 = state.dataDaylightingManager->TVIS1(igroup);
6898 :
6899 53663 : int countBeforeListOfExtWinLoop = count;
6900 53663 : bool atLeastOneGlareControlIsActive = false;
6901 :
6902 124175 : for (const auto IWin : listOfExtWin) {
6903 70512 : ++count;
6904 : // need to map back to the original order of the "loop" to not change all the other data structures
6905 70512 : int loop = thisDaylightControl.MapShdOrdToLoopNum(count);
6906 70512 : if (loop > 0) {
6907 : // Check if window is eligible for glare control
6908 : // TH 1/21/2010. Switchable glazings already in partially switched state
6909 : // should be allowed to further dim to control glare
6910 : // if (SurfWinShadingFlag(IWin) <= BGBlind && SurfWinShadingFlag(IWin) != SwitchableGlazing) {
6911 141024 : if (NOT_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) || ANY_SHADE_SCREEN(state.dataSurface->SurfWinShadingFlag(IWin)) ||
6912 70512 : ANY_BLIND(state.dataSurface->SurfWinShadingFlag(IWin))) {
6913 0 : continueOuterLoop = false;
6914 0 : continue;
6915 : }
6916 70512 : ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
6917 70512 : if (!state.dataSurface->Surface(IWin).HasShadeControl) {
6918 0 : continueOuterLoop = false;
6919 0 : continue;
6920 : }
6921 70512 : if (state.dataSurface->WindowShadingControl(ICtrl).GlareControlIsActive) {
6922 70512 : atLeastOneGlareControlIsActive = true;
6923 :
6924 : // Illuminance (WDAYIL) and background luminance (WBACLU) contribution from this
6925 : // window without shading (IS=1) and with shading (IS=2) for each ref pt
6926 : // For switchable windows, this may be partially switched rather than fully dark
6927 141024 : for (int IL = 1; IL <= NREFPT; ++IL) {
6928 211536 : for (int IS = 1; IS <= 2; ++IS) {
6929 141024 : WDAYIL(IS, IL, igroup) = thisDaylightControl.IllumFromWinAtRefPt(loop, IS, IL);
6930 141024 : WBACLU(IS, IL, igroup) = thisDaylightControl.BackLumFromWinAtRefPt(loop, IS, IL);
6931 : }
6932 : }
6933 :
6934 : // Recalculate illuminance and glare with shading on this window.
6935 : // For switchable glazings, this is the fully switched (dark) state
6936 141024 : for (int IL = 1; IL <= NREFPT; ++IL) {
6937 70512 : if (state.dataSurface->SurfWinShadingFlag(IWin) != WinShadingType::SwitchableGlazing) {
6938 : // for non switchable glazings or switchable glazings not switched yet (still in clear state)
6939 : // SurfaceWindow(IWin)%ShadingFlag = WinShadingFlag::GlassConditionallyLightened
6940 70512 : RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) - WDAYIL(1, IL, igroup) + WDAYIL(2, IL, igroup);
6941 70512 : RBACLU(IL, igroup) = thisDaylightControl.BacLum(IL) - WBACLU(1, IL, igroup) + WBACLU(2, IL, igroup);
6942 : } else {
6943 : // switchable glazings already in partially switched state when calc the RDAYIL(IL) & RBACLU(IL)
6944 0 : RDAYIL(IL, igroup) =
6945 0 : state.dataDaylightingManager->DaylIllum(IL) - WDAYIL(2, IL, igroup) + tmpIllumFromWinAtRefPt(loop, 2, IL);
6946 0 : RBACLU(IL, igroup) = thisDaylightControl.BacLum(IL) - WBACLU(2, IL, igroup) + tmpBackLumFromWinAtRefPt(loop, 2, IL);
6947 : }
6948 : }
6949 :
6950 70512 : if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::GlassConditionallyLightened)
6951 70512 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::SwitchableGlazing;
6952 0 : else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::IntShadeConditionallyOff)
6953 0 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::IntShade;
6954 0 : else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::ExtShadeConditionallyOff)
6955 0 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::ExtShade;
6956 0 : else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::IntBlindConditionallyOff)
6957 0 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::IntBlind;
6958 0 : else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::ExtBlindConditionallyOff)
6959 0 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::ExtBlind;
6960 0 : else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::BGShadeConditionallyOff)
6961 0 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::BGShade;
6962 0 : else if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::BGBlindConditionallyOff)
6963 0 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::BGBlind;
6964 :
6965 : // For switchable glazings, it is switched to fully dark state,
6966 : // update ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for use in DayltgGlare
6967 70512 : if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) {
6968 141024 : for (int IL = 1; IL <= NREFPT; ++IL) {
6969 70512 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSourceLumFromWinAtRefPt(loop, 2, IL);
6970 70512 : thisDaylightControl.IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL);
6971 70512 : thisDaylightControl.BackLumFromWinAtRefPt(loop, 2, IL) = tmpBackLumFromWinAtRefPt(loop, 2, IL);
6972 : }
6973 :
6974 70512 : int const IConst = state.dataSurface->SurfActiveConstruction(IWin);
6975 : // Vis trans at normal incidence of unswitched glass
6976 141024 : thisTVIS1 = General::POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef) *
6977 70512 : state.dataSurface->SurfWinGlazedFrac(IWin);
6978 :
6979 : // Vis trans at normal incidence of fully switched glass
6980 70512 : int const IConstShaded = state.dataSurface->Surface(IWin).activeShadedConstruction;
6981 141024 : thisTVIS2 = General::POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) *
6982 70512 : state.dataSurface->SurfWinGlazedFrac(IWin);
6983 : }
6984 : }
6985 : }
6986 : }
6987 53663 : if (continueOuterLoop) continue;
6988 :
6989 53663 : if (atLeastOneGlareControlIsActive) {
6990 :
6991 : // Re-calc daylight and glare at shaded state. For switchable glazings, it is the fully dark state.
6992 107326 : for (int IL = 1; IL <= NREFPT; ++IL) {
6993 53663 : BACL = max(SetPnt(IL) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect / DataGlobalConstants::Pi,
6994 53663 : RBACLU(IL, igroup));
6995 : // DayltgGlare uses ZoneDaylight(ZoneNum)%SourceLumFromWinAtRefPt(IL,2,loop) for shaded state
6996 53663 : DayltgGlare(state, IL, BACL, GLRNEW(IL), daylightCtrlNum);
6997 : }
6998 :
6999 : // Check if the shading did not improve the glare conditions
7000 : //
7001 : // blnCycle when true resets the specific window to its non-shaded condition. A later comment says
7002 : // Shading this window has not improved the glare situation.
7003 : // Reset shading flag to no shading condition, go to next window.
7004 : //
7005 : // If the original glare was too high at all reference points and the new glare is lower at all reference points it is good, don't
7006 : // reset it. For each reference point, if the original glare was too high but ok at other reference points and the glare gets
7007 : // lower at the reference and stays ok at the other reference points it is good, don't reset it.
7008 : //
7009 : // The old comments when there were only two reference points were:
7010 : // One ref pt; go to next window if glare has increased.
7011 : // Two ref pts. There are three cases depending on glare values.
7012 : // (1) Initial glare too high at both ref pts. Deploy shading on
7013 : // this window if this decreases glare at both ref pts.
7014 : // (2) Initial glare too high only at first ref pt. Deploy shading
7015 : // on this window if glare at first ref pt decreases and
7016 : // glare at second ref pt stays below max.
7017 : // (3) Initial glare too high at second ref pt. Deploy shading if glare
7018 : // at second ref pt decreases and glare at first ref pt stays below max.
7019 : //
7020 : // The approach taken is just to count the number of reference points that fulfill the individual requirements and see if it
7021 : // covers all the reference points.
7022 53663 : int numRefPtOldAboveMaxNewBelowOld = 0;
7023 53663 : int numRefPtOldBelowMaxNewBelowMax = 0;
7024 107326 : for (int IL = 1; IL <= NREFPT; ++IL) {
7025 53663 : if (GLRNDX(IL) > thisDaylightControl.MaxGlareallowed && GLRNEW(IL) <= GLRNDX(IL)) ++numRefPtOldAboveMaxNewBelowOld;
7026 53663 : if (GLRNDX(IL) <= thisDaylightControl.MaxGlareallowed && GLRNEW(IL) <= thisDaylightControl.MaxGlareallowed)
7027 0 : ++numRefPtOldBelowMaxNewBelowMax;
7028 : }
7029 53663 : blnCycle = true;
7030 53663 : if ((numRefPtOldAboveMaxNewBelowOld + numRefPtOldBelowMaxNewBelowMax) == NREFPT) blnCycle = false;
7031 : }
7032 :
7033 : // restore the count to the value prior to the last loop through the group of exterior windows
7034 53663 : count = countBeforeListOfExtWinLoop;
7035 53663 : breakOuterLoop = false;
7036 :
7037 108954 : for (const auto IWin : listOfExtWin) {
7038 69098 : ++count;
7039 : // need to map back to the original order of the "loop" to not change all the other data structures
7040 69098 : int loop = thisDaylightControl.MapShdOrdToLoopNum(count);
7041 69098 : if (loop > 0) {
7042 : // if (SurfWinShadingFlag(IWin) <= BGBlind && SurfWinShadingFlag(IWin) != SwitchableGlazing) {
7043 138196 : if (NOT_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) || ANY_SHADE_SCREEN(state.dataSurface->SurfWinShadingFlag(IWin)) ||
7044 69098 : ANY_BLIND(state.dataSurface->SurfWinShadingFlag(IWin)))
7045 0 : continue;
7046 :
7047 69098 : ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
7048 69098 : if (!state.dataSurface->Surface(IWin).HasShadeControl) continue;
7049 69098 : if (state.dataSurface->WindowShadingControl(ICtrl).GlareControlIsActive) {
7050 :
7051 : // Shading this window has not improved the glare situation.
7052 : // Reset shading flag to no shading condition, go to next window.
7053 69098 : if (blnCycle) {
7054 : // for switchable glazings, reset properties to clear state or partial switched state?
7055 0 : if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) {
7056 0 : state.dataSurface->SurfWinSwitchingFactor(IWin) = 0.0;
7057 0 : state.dataSurface->SurfWinVisTransSelected(IWin) = thisTVIS1;
7058 :
7059 : // RESET properties for fully dark state
7060 0 : for (int IL = 1; IL <= NREFPT; ++IL) {
7061 0 : thisDaylightControl.IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL);
7062 0 : thisDaylightControl.BackLumFromWinAtRefPt(loop, 2, IL) = tmpBackLumFromWinAtRefPt(loop, 2, IL);
7063 0 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSourceLumFromWinAtRefPt(loop, 2, IL);
7064 : }
7065 : }
7066 :
7067 0 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::ShadeOff;
7068 0 : continue;
7069 : }
7070 :
7071 : // Shading this window has improved the glare situation.
7072 : // Reset background luminance, glare index, and daylight illuminance at each ref pt.
7073 : // For switchable glazings, this is fully switched, dark state
7074 138196 : for (int IL = 1; IL <= NREFPT; ++IL) {
7075 69098 : thisDaylightControl.BacLum(IL) = RBACLU(IL, igroup);
7076 69098 : GLRNDX(IL) = GLRNEW(IL);
7077 69098 : state.dataDaylightingManager->DaylIllum(IL) = RDAYIL(IL, igroup);
7078 : }
7079 :
7080 : // TH comments (5/22/2009): seems for EC windows, if the calculated glare exceeds the max setpoint,
7081 : // the EC windows will be reset to fully dark state which significantly reduces the available daylight.
7082 : // A better way is to dim the EC windows as necessary just to meet the glare index, which will still
7083 : // provide more daylight while not exceeding the max glare! The question is then how to set the
7084 : // SwitchingFactor to just meet the glare index.
7085 : // This was addressed in CR 7984 for E+ 5.0. 1/19/2010
7086 :
7087 : // If switchable glazing, set switching factor to 1: fully switched.
7088 69098 : if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) {
7089 : // tmpSWFactor0 = SurfaceWindow( IWin ).SwitchingFactor; // save original
7090 : // switching factor
7091 : ////Unused Set but never used
7092 69098 : state.dataSurface->SurfWinSwitchingFactor(IWin) = 1.0;
7093 69098 : state.dataSurface->SurfWinVisTransSelected(IWin) = thisTVIS2;
7094 :
7095 : // restore fully dark values
7096 138196 : for (int IL = 1; IL <= NREFPT; ++IL) {
7097 69098 : WDAYIL(2, IL, igroup) = tmpIllumFromWinAtRefPt(loop, 2, IL);
7098 69098 : WBACLU(2, IL, igroup) = tmpBackLumFromWinAtRefPt(loop, 2, IL);
7099 69098 : thisDaylightControl.IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL);
7100 69098 : thisDaylightControl.BackLumFromWinAtRefPt(loop, 2, IL) = tmpBackLumFromWinAtRefPt(loop, 2, IL);
7101 69098 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSourceLumFromWinAtRefPt(loop, 2, IL);
7102 : }
7103 : }
7104 :
7105 : // Check if glare now acceptable at each ref pt.
7106 69098 : GlareOK = false;
7107 69098 : if (NREFPT == 1) {
7108 69098 : if (GLRNDX(1) <= thisDaylightControl.MaxGlareallowed) GlareOK = true;
7109 0 : } else if (NREFPT > 1) {
7110 0 : if (GLRNDX(1) <= thisDaylightControl.MaxGlareallowed && GLRNDX(2) <= thisDaylightControl.MaxGlareallowed) GlareOK = true;
7111 : }
7112 :
7113 69098 : if (GlareOK) {
7114 27614 : if (state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing &&
7115 13807 : state.dataSurface->WindowShadingControl(ICtrl).shadingControlType == WindowShadingControlType::MeetDaylIlumSetp) {
7116 : // Added TH 1/14/2010
7117 : // Only for switchable glazings with MeetDaylightIlluminanceSetpoint control
7118 : // The glazing is in fully dark state, it might lighten a bit to provide more daylight
7119 : // while meeting maximum discomfort glare index
7120 : // Iteration to find the right switching factor meeting the glare index
7121 :
7122 : // get fully dark state values
7123 0 : tmpSWSL1 = tmpSourceLumFromWinAtRefPt(loop, 2, 1);
7124 0 : if (NREFPT > 1) tmpSWSL2 = tmpSourceLumFromWinAtRefPt(loop, 2, 2);
7125 :
7126 : // use simple fixed step search in iteraction, can be improved in future
7127 0 : tmpSWFactor = 1.0 - tmpSWIterStep;
7128 0 : while (tmpSWFactor > 0) {
7129 : // calc new glare at new switching state
7130 0 : for (int IL = 1; IL <= NREFPT; ++IL) {
7131 0 : RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) +
7132 0 : (WDAYIL(1, IL, igroup) - WDAYIL(2, IL, igroup)) * (1.0 - tmpSWFactor);
7133 0 : RBACLU(IL, igroup) =
7134 0 : thisDaylightControl.BacLum(IL) + (WBACLU(1, IL, igroup) - WBACLU(2, IL, igroup)) * (1.0 - tmpSWFactor);
7135 0 : BACL = max(SetPnt(IL) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect /
7136 : DataGlobalConstants::Pi,
7137 0 : RBACLU(IL, igroup));
7138 : // needs to update SourceLumFromWinAtRefPt(IL,2,loop) before re-calc DayltgGlare
7139 0 : tmpMult = (thisTVIS1 - (thisTVIS1 - thisTVIS2) * tmpSWFactor) / thisTVIS2;
7140 0 : if (IL == 1) {
7141 0 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSWSL1 * tmpMult;
7142 : } else {
7143 0 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, IL) = tmpSWSL2 * tmpMult;
7144 : }
7145 : // Calc new glare
7146 0 : DayltgGlare(state, IL, BACL, GLRNEW(IL), daylightCtrlNum);
7147 : }
7148 :
7149 : // Check whether new glare is OK
7150 0 : GlareOK = false;
7151 0 : if (NREFPT == 1) {
7152 0 : if (GLRNEW(1) <= thisDaylightControl.MaxGlareallowed) GlareOK = true;
7153 0 : } else if (NREFPT > 1) {
7154 0 : if (GLRNEW(1) <= thisDaylightControl.MaxGlareallowed && GLRNEW(2) <= thisDaylightControl.MaxGlareallowed)
7155 0 : GlareOK = true;
7156 : }
7157 :
7158 0 : if (GlareOK) {
7159 0 : if (tmpSWFactor >= tmpSWIterStep) {
7160 : // Continue to lighten the glazing
7161 0 : tmpSWFactor -= tmpSWIterStep;
7162 0 : continue;
7163 : } else {
7164 : // Glare still OK but glazing already in clear state, no more lighten
7165 0 : breakOuterLoop = true;
7166 0 : break;
7167 : }
7168 : } else {
7169 : // Glare too high, exit and use previous switching state
7170 0 : tmpSWFactor += tmpSWIterStep;
7171 0 : breakOuterLoop = true;
7172 0 : break;
7173 : }
7174 : }
7175 :
7176 : // Final re-calculation if needed
7177 0 : if (!GlareOK) {
7178 : // Glare too high, use previous state and re-calc
7179 0 : for (int IL = 1; IL <= NREFPT; ++IL) {
7180 0 : RDAYIL(IL, igroup) = state.dataDaylightingManager->DaylIllum(IL) +
7181 0 : (WDAYIL(1, IL, igroup) - WDAYIL(2, IL, igroup)) * (1.0 - tmpSWFactor);
7182 0 : RBACLU(IL, igroup) =
7183 0 : thisDaylightControl.BacLum(IL) + (WBACLU(1, IL, igroup) - WBACLU(2, IL, igroup)) * (1.0 - tmpSWFactor);
7184 0 : BACL = max(SetPnt(IL) * state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect /
7185 : DataGlobalConstants::Pi,
7186 0 : RBACLU(IL, igroup));
7187 :
7188 : // needs to update SourceLumFromWinAtRefPt(IL,2,IWin) before re-calc DayltgGlare
7189 0 : tmpMult = (thisTVIS1 - (thisTVIS1 - thisTVIS2) * tmpSWFactor) / thisTVIS2;
7190 0 : if (IL == 1) {
7191 0 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, 1) = tmpSWSL1 * tmpMult;
7192 : } else {
7193 0 : thisDaylightControl.SourceLumFromWinAtRefPt(loop, 2, 2) = tmpSWSL2 * tmpMult;
7194 : }
7195 0 : DayltgGlare(state, IL, BACL, GLRNEW(IL), daylightCtrlNum);
7196 : }
7197 : }
7198 :
7199 : // Update final results
7200 0 : for (int IL = 1; IL <= NREFPT; ++IL) {
7201 0 : thisDaylightControl.BacLum(IL) = RBACLU(IL, igroup);
7202 0 : GLRNDX(IL) = GLRNEW(IL);
7203 0 : state.dataDaylightingManager->DaylIllum(IL) = RDAYIL(IL, igroup);
7204 :
7205 0 : tmpMult = (thisTVIS1 - (thisTVIS1 - thisTVIS2) * tmpSWFactor) / thisTVIS2;
7206 : // update report variables
7207 0 : thisDaylightControl.IllumFromWinAtRefPt(loop, 2, IL) = tmpIllumFromWinAtRefPt(loop, 2, IL) * tmpMult;
7208 0 : thisDaylightControl.BackLumFromWinAtRefPt(loop, 2, IL) = tmpBackLumFromWinAtRefPt(loop, 2, IL) * tmpMult;
7209 : }
7210 0 : state.dataSurface->SurfWinSwitchingFactor(IWin) = tmpSWFactor;
7211 0 : state.dataSurface->SurfWinVisTransSelected(IWin) = thisTVIS1 - (thisTVIS1 - thisTVIS2) * tmpSWFactor;
7212 :
7213 : } else {
7214 : // For un-switchable glazing or switchable glazing but not MeetDaylightIlluminaceSetpoint control,
7215 : // it is in shaded state and glare is ok - job is done, exit the window loop - IWin
7216 13807 : breakOuterLoop = true;
7217 13807 : break;
7218 : }
7219 : }
7220 : } // End of check if window glare control is active
7221 : }
7222 : } // end of for(auto IWin : listOfExtWin)
7223 53663 : if (breakOuterLoop) break;
7224 : } // for group
7225 : } // GlareFlag
7226 :
7227 : // Loop again over windows and reset remaining shading flags that
7228 : // are 10 or higher (i.e., conditionally off) to off
7229 1397968 : for (int spaceNum : state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).spaceIndexes) {
7230 698984 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
7231 2082797 : for (int IWin = thisSpace.WindowSurfaceFirst; IWin <= thisSpace.WindowSurfaceLast; ++IWin) {
7232 1383813 : if (state.dataSurface->Surface(IWin).ExtBoundCond != ExternalEnvironment) continue;
7233 1382798 : bool anyGlareControl = BITF_TEST_ANY(BITF(state.dataSurface->SurfWinShadingFlag(IWin)),
7234 : BITF(WinShadingType::IntShadeConditionallyOff) | BITF(WinShadingType::GlassConditionallyLightened) |
7235 : BITF(WinShadingType::ExtShadeConditionallyOff) | BITF(WinShadingType::IntBlindConditionallyOff) |
7236 : BITF(WinShadingType::ExtBlindConditionallyOff));
7237 1382798 : if (anyGlareControl) {
7238 16877 : state.dataSurface->SurfWinShadingFlag(IWin) = WinShadingType::ShadeOff;
7239 : }
7240 : }
7241 : }
7242 :
7243 : // Variables for reporting
7244 1618116 : for (int IL = 1; IL <= NREFPT; ++IL) {
7245 919132 : thisDaylightControl.DaylIllumAtRefPt(IL) = state.dataDaylightingManager->DaylIllum(IL);
7246 919132 : thisDaylightControl.GlareIndexAtRefPt(IL) = GLRNDX(IL);
7247 :
7248 : // added TH 12/2/2008
7249 919132 : if (GLRNDX(IL) > thisDaylightControl.MaxGlareallowed) {
7250 120428 : thisDaylightControl.TimeExceedingGlareIndexSPAtRefPt(IL) = state.dataGlobal->TimeStepZone; // fraction of hours
7251 : } else {
7252 798704 : thisDaylightControl.TimeExceedingGlareIndexSPAtRefPt(IL) = 0.0;
7253 : }
7254 :
7255 : // added TH 7/6/2009
7256 919132 : if (state.dataDaylightingManager->DaylIllum(IL) > thisDaylightControl.IllumSetPoint(IL)) {
7257 414949 : thisDaylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt(IL) = state.dataGlobal->TimeStepZone; // fraction of hours
7258 : } else {
7259 504183 : thisDaylightControl.TimeExceedingDaylightIlluminanceSPAtRefPt(IL) = 0.0;
7260 : }
7261 : }
7262 : }
7263 :
7264 1015 : void DayltgInteriorTDDIllum(EnergyPlusData &state)
7265 : {
7266 :
7267 : // SUBROUTINE INFORMATION:
7268 : // AUTHOR Linda Lawrie
7269 : // DATE WRITTEN October 2006
7270 : // MODIFIED na
7271 : // RE-ENGINEERED na
7272 :
7273 : // PURPOSE OF THIS SUBROUTINE:
7274 : // Calculate the TDD Pipe illuminance values
7275 :
7276 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7277 : int PipeNum; // TDD pipe object number
7278 : Real64 TDDTransVisDiffNow; // TDD diffuse visible transmittance at the current hour
7279 : Real64 TDDTransVisDiffPrev; // TDD diffuse visible transmittance at the previous hour
7280 1015 : auto &TDDTransVisDiff = state.dataDaylightingManager->TDDTransVisDiff;
7281 : int ISky; // Sky type index
7282 : int ISky1; // Sky type index values for averaging two sky types
7283 : int ISky2;
7284 : Real64 SkyWeight; // Weighting factor used to average two different sky types
7285 :
7286 1015 : if (state.dataEnvrn->SkyClearness > 3.0) { // Sky is average of clear and clear turbid
7287 518 : SkyWeight = min(1.0, (state.dataEnvrn->SkyClearness - 3.0) / 3.0);
7288 518 : ISky1 = 1;
7289 518 : ISky2 = 2;
7290 497 : } else if (state.dataEnvrn->SkyClearness > 1.2) { // Sky is average of clear turbid and intermediate
7291 91 : SkyWeight = (state.dataEnvrn->SkyClearness - 1.2) / 1.8;
7292 91 : ISky1 = 2;
7293 91 : ISky2 = 3;
7294 : } else { // Sky is average of intermediate and overcast
7295 406 : SkyWeight = min(1.0, max(0.0, (state.dataEnvrn->SkyClearness - 1.0) / 0.2, (state.dataEnvrn->SkyBrightness - 0.05) / 0.4));
7296 406 : ISky1 = 3;
7297 406 : ISky2 = 4;
7298 : }
7299 :
7300 : // Calculate and report TDD visible transmittances
7301 3045 : for (PipeNum = 1; PipeNum <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++PipeNum) {
7302 :
7303 2030 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransVisBeam =
7304 4060 : state.dataGlobal->WeightNow * state.dataDaylightingManager->TDDTransVisBeam(state.dataGlobal->HourOfDay, PipeNum) +
7305 2030 : state.dataGlobal->WeightPreviousHour * state.dataDaylightingManager->TDDTransVisBeam(state.dataGlobal->PreviousHour, PipeNum);
7306 :
7307 10150 : for (ISky = 1; ISky <= 4; ++ISky) {
7308 8120 : if (state.dataDaylightingManager->TDDFluxInc(state.dataGlobal->HourOfDay, ISky, PipeNum) > 0.0) {
7309 7840 : TDDTransVisDiffNow = state.dataDaylightingManager->TDDFluxTrans(state.dataGlobal->HourOfDay, ISky, PipeNum) /
7310 3920 : state.dataDaylightingManager->TDDFluxInc(state.dataGlobal->HourOfDay, ISky, PipeNum);
7311 : } else {
7312 4200 : TDDTransVisDiffNow = 0.0;
7313 : }
7314 :
7315 8120 : if (state.dataDaylightingManager->TDDFluxInc(state.dataGlobal->PreviousHour, ISky, PipeNum) > 0.0) {
7316 7672 : TDDTransVisDiffPrev = state.dataDaylightingManager->TDDFluxTrans(state.dataGlobal->PreviousHour, ISky, PipeNum) /
7317 3836 : state.dataDaylightingManager->TDDFluxInc(state.dataGlobal->PreviousHour, ISky, PipeNum);
7318 : } else {
7319 4284 : TDDTransVisDiffPrev = 0.0;
7320 : }
7321 :
7322 8120 : TDDTransVisDiff(ISky) = state.dataGlobal->WeightNow * TDDTransVisDiffNow + state.dataGlobal->WeightPreviousHour * TDDTransVisDiffPrev;
7323 : } // ISky
7324 :
7325 2030 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransVisDiff =
7326 2030 : SkyWeight * TDDTransVisDiff(ISky1) + (1.0 - SkyWeight) * TDDTransVisDiff(ISky2);
7327 : } // PipeNum
7328 1015 : }
7329 :
7330 822103 : void DayltgElecLightingControl(EnergyPlusData &state)
7331 : {
7332 :
7333 : // SUBROUTINE INFORMATION:
7334 : // AUTHOR Fred Winkelmann
7335 : // DATE WRITTEN July 1997
7336 : // MODIFIED Mar 2004, FCW: add inter-reflected illuminance from interior windows to DaylIllum
7337 : // Apr 2004, FCW: move CALL ReportIllumMap from DayltgInteriorIllum2 (DayltgInteriorMapIllum)
7338 : // Apr 2010, BG NREL: remove inter-reflected illuminance to stop double counting
7339 : // Aug 2012, BG NREL: added availability schedule logic
7340 :
7341 : // PURPOSE OF THIS SUBROUTINE:
7342 : // For a daylit space, determines lighting power reduction factor due to
7343 : // daylighting for different lighting control systems.
7344 :
7345 : // Called by InitSurfaceHeatBalance.
7346 :
7347 : // REFERENCES:
7348 : // Based on DOE-2.1E subroutine DLTSYS.
7349 :
7350 822103 : if (state.dataDaylightingData->daylightControl.empty()) {
7351 741724 : return;
7352 : }
7353 : // Reset space power reduction factors
7354 901877 : for (int spaceNum = 1; spaceNum <= state.dataGlobal->numSpaces; ++spaceNum) {
7355 821498 : state.dataDaylightingData->spacePowerReductionFactor(spaceNum) = 1.0;
7356 : }
7357 :
7358 490068 : for (auto &thisDaylightControl : state.dataDaylightingData->daylightControl) {
7359 :
7360 409689 : if (thisDaylightControl.DaylightMethod != DataDaylighting::DaylightingMethod::SplitFlux) {
7361 : // Set space power reduction factors
7362 2037 : if (thisDaylightControl.PowerReductionFactor < 1.0) {
7363 2016 : if (thisDaylightControl.spaceIndex > 0) {
7364 : // This is a space-level daylighting control
7365 2016 : state.dataDaylightingData->spacePowerReductionFactor(thisDaylightControl.spaceIndex) = thisDaylightControl.PowerReductionFactor;
7366 : } else {
7367 : // This is a zone-level daylighting control
7368 0 : for (int spaceNum : state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).spaceIndexes) {
7369 0 : state.dataDaylightingData->spacePowerReductionFactor(spaceNum) = thisDaylightControl.PowerReductionFactor;
7370 : }
7371 : }
7372 : }
7373 2037 : continue;
7374 : }
7375 :
7376 : // Electric lighting power reduction factor for a given daylighting control
7377 407652 : Real64 &TotReduction = thisDaylightControl.PowerReductionFactor;
7378 407652 : TotReduction = 0.0;
7379 407652 : Real64 ZFTOT = 0.0;
7380 :
7381 : // check if scheduled to be available
7382 407652 : if (ScheduleManager::GetCurrentScheduleValue(state, thisDaylightControl.AvailSchedNum) > 0.0) {
7383 :
7384 : // Loop over reference points
7385 934692 : for (int IL = 1; IL <= thisDaylightControl.TotalDaylRefPoints; ++IL) {
7386 :
7387 : // Total fraction of zone that is daylit
7388 531170 : ZFTOT += thisDaylightControl.FracZoneDaylit(IL);
7389 :
7390 531170 : state.dataDaylightingManager->DaylIllum(IL) = thisDaylightControl.DaylIllumAtRefPt(IL);
7391 531170 : Real64 FL = 0.0;
7392 531170 : if (state.dataDaylightingManager->DaylIllum(IL) < thisDaylightControl.IllumSetPoint(IL)) {
7393 119567 : FL =
7394 119567 : (thisDaylightControl.IllumSetPoint(IL) - state.dataDaylightingManager->DaylIllum(IL)) / thisDaylightControl.IllumSetPoint(IL);
7395 : }
7396 :
7397 : // BRANCH ON LIGHTING SYSTEM TYPE
7398 531170 : auto LSYSTP = thisDaylightControl.LightControlType;
7399 531170 : Real64 FP = 0.0;
7400 531170 : if (LSYSTP != DataDaylighting::LtgCtrlType::Stepped) {
7401 : // Continuously dimmable system with linear power curve
7402 : // Fractional output power required to meet setpoint
7403 287580 : FP = 1.0;
7404 : // LIGHT-CTRL-TYPE = CONTINUOUS (LSYSTP = 1)
7405 287580 : if (FL <= thisDaylightControl.MinLightFraction) {
7406 218464 : FP = thisDaylightControl.MinPowerFraction;
7407 : }
7408 : // LIGHT-CTRL-TYPE = CONTINUOUS/OFF (LSYSTP = 3)
7409 287580 : if (FL <= thisDaylightControl.MinLightFraction && LSYSTP == DataDaylighting::LtgCtrlType::ContinuousOff) {
7410 201452 : FP = 0.0;
7411 : }
7412 287580 : if (FL > thisDaylightControl.MinLightFraction && FL < 1.0) {
7413 137424 : FP = (FL + (1.0 - FL) * thisDaylightControl.MinPowerFraction - thisDaylightControl.MinLightFraction) /
7414 68712 : (1.0 - thisDaylightControl.MinLightFraction);
7415 : }
7416 :
7417 : } else { // LSYSTP = 2
7418 : // Stepped system
7419 243590 : FP = 0.0;
7420 : // #9060: Use a tolerance, otherwise at very low (< 1e-12) daylighting conditions, you can get a multiplier > 1.0
7421 243590 : if (state.dataDaylightingManager->DaylIllum(IL) < 0.1) {
7422 3508 : FP = 1.0;
7423 240082 : } else if (state.dataDaylightingManager->DaylIllum(IL) < thisDaylightControl.IllumSetPoint(IL)) {
7424 32509 : FP = double(int(thisDaylightControl.LightControlSteps * FL) + 1) / double(thisDaylightControl.LightControlSteps);
7425 : }
7426 :
7427 243590 : if (thisDaylightControl.LightControlProbability < 1.0) {
7428 : // Manual operation. Occupant sets lights one level too high a fraction of the time equal to
7429 : // 1. - ZoneDaylight(ZoneNum)%LightControlProbability. RANDOM_NUMBER returns a random number
7430 : // between 0 and 1.
7431 : Real64 XRAN;
7432 0 : RANDOM_NUMBER(XRAN);
7433 0 : if (XRAN >= thisDaylightControl.LightControlProbability) {
7434 : // Set level one higher
7435 0 : if (FP < 1.0) {
7436 0 : FP += (1.0 / double(thisDaylightControl.LightControlSteps));
7437 : }
7438 : } // XRAN
7439 : } // Light Control Probability < 1
7440 : } // Lighting System Type
7441 :
7442 531170 : thisDaylightControl.RefPtPowerReductionFactor(IL) = FP;
7443 :
7444 : // Accumulate net ltg power reduction factor for entire zone
7445 531170 : TotReduction += thisDaylightControl.RefPtPowerReductionFactor(IL) * thisDaylightControl.FracZoneDaylit(IL);
7446 :
7447 : } // End of loop over reference points, IL
7448 :
7449 : // Correct for fraction of zone (1-ZFTOT) not controlled by
7450 : // the reference points. For this fraction (which is usually zero),
7451 : // the electric lighting is unaffected and the power reduction
7452 : // factor is therefore 1.0.
7453 403522 : TotReduction += (1.0 - ZFTOT);
7454 : } else { // controls not currently available
7455 4130 : TotReduction = 1.0;
7456 : }
7457 :
7458 : // Set space power reduction factors
7459 407652 : if (thisDaylightControl.spaceIndex > 0) {
7460 : // This is a space-level daylighting control
7461 407652 : state.dataDaylightingData->spacePowerReductionFactor(thisDaylightControl.spaceIndex) = TotReduction;
7462 : } else {
7463 : // This is a zone-level daylighting control
7464 0 : for (int spaceNum : state.dataHeatBal->Zone(thisDaylightControl.zoneIndex).spaceIndexes) {
7465 0 : state.dataDaylightingData->spacePowerReductionFactor(spaceNum) = TotReduction;
7466 : }
7467 : }
7468 : } // end daylighting control loop
7469 :
7470 : // IF(DataDaylighting::TotIllumMaps > 0 .and. .not. DoingSizing .and. .not. WarmupFlag .and. .not. KickoffSimulation) THEN
7471 80379 : if ((int)state.dataDaylightingData->IllumMap.size() > 0 && !state.dataGlobal->DoingSizing && !state.dataGlobal->WarmupFlag) {
7472 2842 : for (int mapNum = 1; mapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++mapNum) {
7473 1509 : if (state.dataGlobal->TimeStep == 1) state.dataDaylightingData->mapResultsToReport = false;
7474 139209 : for (int IL = 1; IL <= state.dataDaylightingData->IllumMapCalc(mapNum).TotalMapRefPoints; ++IL) {
7475 137700 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPtHr(IL) +=
7476 137700 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPt(IL) / double(state.dataGlobal->NumOfTimeStepInHour);
7477 137700 : if (state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPtHr(IL) > 0.0) {
7478 137700 : state.dataDaylightingData->mapResultsToReport = true;
7479 137700 : state.dataDaylightingData->mapResultsReported = true;
7480 : }
7481 : }
7482 1509 : ReportIllumMap(state, mapNum);
7483 1509 : if (state.dataGlobal->TimeStep == state.dataGlobal->NumOfTimeStepInHour) {
7484 252 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPtHr = 0.0;
7485 252 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllumAtMapPt = 0.0;
7486 : }
7487 : }
7488 : }
7489 : }
7490 :
7491 533394 : Real64 DayltgGlarePositionFactor(Real64 &X, // Lateral and vertical distance of luminous window element from
7492 : Real64 &Y)
7493 : {
7494 :
7495 : // SUBROUTINE INFORMATION:
7496 : // AUTHOR Fred Winkelmann
7497 : // DATE WRITTEN July 1997
7498 : // MODIFIED na
7499 : // RE-ENGINEERED na
7500 :
7501 : // PURPOSE OF THIS SUBROUTINE:
7502 : // by table interpolation, evaluates the
7503 : // Hopkinson position factor used in glare calculation
7504 : // (Hopkinson, Petherbridge, AND Longmore -- Daylighting,
7505 : // London, 1966, PP 307, 323). X (Y) is the lateral
7506 : // (vertical) distance of luminous window element from
7507 : // horizontal line of vision, divided by horizontal distance
7508 : // from eye of observer. The array PF contains values of
7509 : // the position factor for X = 0, 0.5, 1.0, 1.5, 2.0, 2.5,
7510 : // and 3.0 and Y = 0, 0.5, 1.0, 1.5, 2.0. Called by CalcDayltgCoefficients.
7511 :
7512 : // REFERENCES:
7513 : // Based on DOE-2.1E subroutine DPFAC.
7514 :
7515 : // Return value
7516 : Real64 DayltgGlarePositionFactor; // Position factor
7517 :
7518 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
7519 : int IX; // Lateral and vertical displacement indices
7520 : int IY;
7521 : Real64 X1; // Lateral and vertical displacement ratios
7522 : Real64 Y1;
7523 : Real64 FA; // Intermediate variables
7524 : Real64 FB;
7525 :
7526 : // Position factor array
7527 : static constexpr std::array<std::array<Real64, 7>, 5> PF = {{
7528 : {1.00, 0.492, 0.226, 0.128, 0.081, 0.061, 0.057},
7529 : {0.123, 0.119, 0.065, 0.043, 0.029, 0.026, 0.023},
7530 : {0.019, 0.026, 0.019, 0.016, 0.014, 0.011, 0.011},
7531 : {0.008, 0.008, 0.008, 0.008, 0.008, 0.006, 0.006},
7532 : {0.0, 0.0, 0.003, 0.003, 0.003, 0.003, 0.003},
7533 : }};
7534 :
7535 533394 : DayltgGlarePositionFactor = 0.0;
7536 533394 : if (X < 0.0 || X >= 3.0) return DayltgGlarePositionFactor;
7537 182986 : if (Y < 0.0 || Y >= 2.0) return DayltgGlarePositionFactor;
7538 :
7539 182433 : IX = 1 + int(2.0 * X);
7540 182433 : IY = 1 + int(2.0 * Y);
7541 182433 : X1 = 0.5 * double(IX - 1);
7542 182433 : Y1 = 0.5 * double(IY - 1);
7543 182433 : FA = PF[IY - 1][IX - 1] + 2.0 * (X - X1) * (PF[IY - 1][IX] - PF[IY - 1][IX - 1]);
7544 182433 : FB = PF[IY][IX - 1] + 2.0 * (X - X1) * (PF[IY][IX] - PF[IY][IX - 1]);
7545 182433 : DayltgGlarePositionFactor = FA + 2.0 * (Y - Y1) * (FB - FA);
7546 :
7547 182433 : return DayltgGlarePositionFactor;
7548 : }
7549 :
7550 319816 : void DayltgInterReflectedIllum(EnergyPlusData &state,
7551 : int const ISunPos, // Sun position counter; used to avoid calculating various
7552 : int const IHR, // Hour of day
7553 : int const enclNum, // Daylighting enclosure index
7554 : int const IWin // Window index
7555 : )
7556 : {
7557 :
7558 : // SUBROUTINE INFORMATION:
7559 : // AUTHOR Fred Winkelmann
7560 : // DATE WRITTEN July 1997
7561 : // MODIFIED FCW December 1998
7562 : // FCW June 2001: Add blind calculations
7563 : // FCW Jan 2001: Add blinds with movable slats
7564 : // FCW Jan 2003: Add between-glass blinds
7565 : // FCW Jul 2003: account for transmittance of shading surfaces
7566 : // (previously these were assumed opaque even if transmittance schedule
7567 : // value was non-zero)
7568 : // FCW Aug 2003: modify initialization of WLUMSK from WLUMSK = 0. TO
7569 : // WLUMSK(:,:,IHR) = 0. Otherwise values calculated in previous
7570 : // call are incorrectly zeroed. Result was that window luminance with
7571 : // shade or blind included only contribution from first window element
7572 : // in window element loop in CalcDayltgCoefficients, thus seriously
7573 : // undercalculating window luminance for windows with more than one
7574 : // window element. Similarly, modified initialization of WLUMSU from
7575 : // WLUMSU = 0. to WLUMSU(:,IHR) = 0., and of WLUMSUdisk from
7576 : // WLUMSUdisk = 0. to WLUMSUdisk(:,IHR) = 0.
7577 : // PGE Aug 2003: Add daylighting shelves.
7578 : // FCW Nov 2003: Add beam solar and sky solar reflected from obstructions;
7579 : // add beam solar reflected from ground accounting for obstructions.
7580 : // FCW Nov 2003: increase NPHMAX from 9 to 10 to avoid rays with altitude angle = 0
7581 : // for vertical surfaces.
7582 : // FCW Nov 2003: fix the expression for min and max limits of azimuth; old expression
7583 : // broke down for window normals with negative altitude angle
7584 : // FCW Nov 2003: add specular reflection from exterior obstructions
7585 : // FCW Apr 2004: add light well efficiency multiplying window transmittance
7586 : // FCW Apr 2004: add diffusing glazing
7587 : // RAR (FSEC) May 2006: add exterior window screen
7588 : // B. Griffith NREL April 2010: CR7869 add adjacent zone area if window is not on this zone
7589 : // apply interior window transmission and blocking to beam transmission from ext win
7590 : // RE-ENGINEERED na
7591 :
7592 : // PURPOSE OF THIS SUBROUTINE:
7593 : // Called from CalcDayltgCoefficients for each window and reference point in a daylit
7594 : // space, for each sun position. Calculates illuminance (EINTSK and EINTSU) at reference point due
7595 : // to internally reflected light by integrating to determine the amount of flux from
7596 : // sky and ground (and beam reflected from obstructions) transmitted through
7597 : // the center of the window and then reflecting this
7598 : // light from the inside surfaces of the space. The "split-flux" method is used
7599 : // (Lynes, Principles of Natural Lighting, 1968). EINT is determined for
7600 : // different sky types and for window with and without shades, screens or blinds.
7601 : // Also finds luminance (WLUMSK and WLUMSU) of window with shade or blind, &
7602 : // or with diffusing glass, for different sky types.
7603 :
7604 : // METHODOLOGY EMPLOYED:na
7605 :
7606 : // REFERENCES:
7607 : // Based on DOE-2.1E subroutine DREFLT.
7608 :
7609 : // Using/Aliasing
7610 : using DaylightingDevices::TransTDD;
7611 : using General::InterpProfAng;
7612 : using General::POLYF;
7613 :
7614 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7615 : // In the following I,J arrays:
7616 : // I = sky type;
7617 : // J = 1 for bare window, 2 and above for window with shade or blind.
7618 319816 : auto &ZSK = state.dataDaylightingManager->ZSK;
7619 319816 : auto &U = state.dataDaylightingManager->U;
7620 319816 : auto &DayltgInterReflectedIllumNearestHitPt = state.dataDaylightingManager->DayltgInterReflectedIllumNearestHitPt;
7621 319816 : auto &DayltgInterReflectedIllumObsHitPt = state.dataDaylightingManager->DayltgInterReflectedIllumObsHitPt;
7622 319816 : auto &DayltgInterReflectedIllumGroundHitPt = state.dataDaylightingManager->DayltgInterReflectedIllumGroundHitPt;
7623 319816 : auto &SkyObstructionMult = state.dataDaylightingManager->SkyObstructionMult;
7624 319816 : auto &FLFWSK = state.dataDaylightingManager->FLFWSK;
7625 319816 : auto &FLFWSU = state.dataDaylightingManager->FLFWSU;
7626 319816 : auto &FLFWSUdisk = state.dataDaylightingManager->FLFWSUdisk;
7627 319816 : auto &FLCWSK = state.dataDaylightingManager->FLCWSK;
7628 319816 : auto &FLCWSU = state.dataDaylightingManager->FLCWSU;
7629 319816 : auto &TransMult = state.dataDaylightingManager->TransMult;
7630 319816 : auto &DayltgInterReflectedIllumTransBmBmMult = state.dataDaylightingManager->DayltgInterReflectedIllumTransBmBmMult;
7631 319816 : auto &ObTransM = state.dataDaylightingManager->ObTransM;
7632 :
7633 : int ISky; // Sky type index: 1=clear, 2=clear turbid,
7634 : // 3=intermediate, 4=overcast
7635 : Real64 DPH; // Sky/ground element altitude and azimuth increments (radians)
7636 : Real64 DTH;
7637 : int IPH; // Sky/ground element altitude and azimuth indices
7638 : int ITH;
7639 : Real64 PH; // Sky/ground element altitude and azimuth (radians)
7640 : Real64 TH;
7641 : Real64 SPH; // Sine and cosine of PH
7642 : Real64 CPH;
7643 : Real64 PHMIN; // Limits of altitude integration (radians)
7644 : Real64 PHMAX;
7645 : Real64 ThMin; // Limits of azimuth integration (radians)
7646 : Real64 ThMax;
7647 : Real64 PhWin; // Altitude, azimuth angle of window normal (radians)
7648 : Real64 ThWin;
7649 : Real64 ACosTanTan; // ACOS(-TAN(Ph)*TAN(PhWin))
7650 : Real64 DA; // CPH*DTH*DPH
7651 : Real64 COSB; // Cosine of angle of incidence of light from sky or ground
7652 : Real64 TVISBR; // Transmittance of window without shading at COSB
7653 : // (times light well efficiency, if appropriate)
7654 : Real64 ZSU;
7655 : // element for clear and overcast sky
7656 : Real64 ObTrans; // Product of solar transmittances of obstructions seen by a light ray
7657 : // unused REAL(r64) :: HitPointLumFrClearSky ! Luminance of obstruction from clear sky (cd/m2)
7658 : // unused REAL(r64) :: HitPointLumFrOvercSky ! Luminance of obstruction from overcast sky (cd/m2)
7659 : // unused REAL(r64) :: HitPointLumFrSun ! Luminance of obstruction from sun (cd/m2)
7660 : int ICtrl; // Window control pointer
7661 : int JSH; // Shading index: JSH=1 is bare window, JSH=2 is shaded window
7662 : Real64 COSBSun; // Cosine of angle of incidence of direct sun on window
7663 : Real64 TVISBSun; // Window's visible transmittance at COSBSun
7664 : // (times light well efficiency, if appropriate)
7665 : Real64 ZSU1; // Transmitted direct normal illuminance (lux)
7666 : // CHARACTER(len=32) :: ShType ! Window shading device type
7667 : bool ShadeOn; // True if exterior or interior window shade present
7668 : bool BlindOn; // True if exterior or interior window blind present
7669 : bool ScreenOn; // True if exterior window screen present
7670 : int BlNum; // Blind number
7671 : // int ScNum; // Screen number //Unused Set but never used
7672 : int PipeNum; // TDD pipe object number
7673 : int ShelfNum; // Daylighting shelf object number
7674 : int InShelfSurf; // Inside daylighting shelf surface number
7675 : int OutShelfSurf; // Outside daylighting shelf surface number
7676 : Real64 TransBlBmDiffFront; // Isolated blind vis beam-diffuse front transmittance
7677 : Real64 TransScBmDiffFront; // Isolated screen vis beam-diffuse front transmittance
7678 : Real64 TransScDiffDiffFront; // Isolated screen vis diffuse-diffuse front transmittance
7679 : Real64 ReflGlDiffDiffBack; // Bare glazing system vis diffuse back reflectance
7680 : Real64 ReflGlDiffDiffFront; // Bare glazing system vis diffuse front reflectance
7681 : Real64 ReflBlBmDiffFront; // Isolated blind vis beam-diffuse front reflectance
7682 : Real64 TransBlDiffDiffFront; // Isolated blind vis diffuse-diffuse front transmittance
7683 : Real64 ReflBlDiffDiffFront; // Isolated blind vis diffuse-diffuse front reflectance
7684 : Real64 ReflBlDiffDiffBack; // Isolated blind vis diffuse-diffuse back reflectance
7685 : Real64 ReflScDiffDiffBack; // Isolated screen vis diffuse-diffuse back reflectance
7686 : Real64 ProfAng; // Solar profile angle (radians)
7687 : Real64 SlatAng; // Blind slat angle
7688 : int JB; // Blind slat angle index
7689 : Real64 t1; // Beam-beam vis trans of bare glass layers 1 and 2
7690 : Real64 t2;
7691 : Real64 td2; // Diffuse-diffuse vis trans of bare glass layers 2 and 3
7692 : Real64 td3;
7693 : Real64 rbd1; // Beam-diffuse back vis reflectance of bare glass layers 1 and 2
7694 : Real64 rbd2;
7695 : Real64 rfd2; // Beam-diffuse front vis reflectance of bare glass layers 2 and 3
7696 : Real64 rfd3;
7697 : Real64 tfshBd; // Beam-diffuse front vis trans of bare blind
7698 : Real64 rfshB; // Beam-diffuse front vis reflectance of bare blind
7699 : Real64 tfshd; // Diffuse-diffuse front vis trans of bare blind
7700 : Real64 rbshd; // Diffuse-diffuse back vis reflectance of bare blind
7701 : Real64 ZSUObsRefl; // Illuminance on window from beam solar reflected by an
7702 : // obstruction (for unit beam normal illuminance)
7703 : int NearestHitSurfNum; // Surface number of nearest obstruction
7704 : int NearestHitSurfNumX; // Surface number to use when obstruction is a shadowing surface
7705 : Real64 LumAtHitPtFrSun; // Luminance at hit point on obstruction from solar reflection
7706 : // for unit beam normal illuminance (cd/m2)
7707 : Real64 SunObstructionMult; // = 1 if sun hits a ground point; otherwise = 0
7708 : Real64 Alfa; // Direction angles for ray heading towards the ground (radians)
7709 : Real64 Beta;
7710 : Real64 HorDis; // Distance between ground hit point and proj'n of window center onto ground (m)
7711 : bool hitObs; // True iff obstruction is hit
7712 : Real64 ObsVisRefl; // Visible reflectance of obstruction
7713 : Real64 SkyReflVisLum; // Reflected sky luminance at hit point divided by unobstructed sky
7714 : // diffuse horizontal illuminance [(cd/m2)/lux]
7715 : Real64 dReflObsSky; // Contribution to sky-related illuminance on window due to sky diffuse
7716 : // reflection from an obstruction
7717 : Real64 TVisSunRefl; // Diffuse vis trans of bare window for beam reflection calc
7718 : // (times light well efficiency, if appropriate)
7719 : Real64 ZSU1refl; // Beam normal illuminance times ZSU1refl = illuminance on window
7720 : // due to specular reflection from exterior surfaces
7721 :
7722 : DataDaylighting::ExtWinType ExtWinType; // Exterior window type (InZoneExtWin, AdjZoneExtWin, NotInOrAdjZoneExtWin)
7723 : Real64 EnclInsideSurfArea; // temporary for calculations, total surface area of enclosure surfaces m2
7724 : int IntWinAdjZoneExtWinNum; // the index of the exterior window in IntWinAdjZoneExtWin nested struct
7725 : int AdjExtWinLoop; // loop index for searching IntWinAdjZoneExtWin
7726 : int IntWinLoop; // loop index for searching interior windows
7727 : int IntWinNum; // window index for interior windows associated with exterior windows
7728 : Real64 COSBintWin;
7729 :
7730 : WinShadingType ShType;
7731 :
7732 319816 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
7733 319816 : int const enclNumThisWin = state.dataSurface->Surface(state.dataSurface->Surface(IWin).BaseSurf).SolarEnclIndex;
7734 : // The inside surface area, ZoneDaylight(ZoneNum)%totInsSurfArea was calculated in subr DayltgAveInteriorReflectance
7735 :
7736 319816 : if (enclNumThisWin == enclNum) {
7737 312496 : ExtWinType = DataDaylighting::ExtWinType::InZoneExtWin;
7738 312496 : EnclInsideSurfArea = state.dataDaylightingData->enclDaylight(enclNumThisWin).totInsSurfArea;
7739 312496 : IntWinAdjZoneExtWinNum = 0;
7740 : } else {
7741 7320 : ExtWinType = DataDaylighting::ExtWinType::AdjZoneExtWin;
7742 : // If window is exterior window in adjacent zone, then use areas of both enclosures
7743 7320 : EnclInsideSurfArea =
7744 7320 : state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea + state.dataDaylightingData->enclDaylight(enclNumThisWin).totInsSurfArea;
7745 : // find index in IntWinAdjZoneExtWin
7746 7320 : for (AdjExtWinLoop = 1; AdjExtWinLoop <= thisEnclDaylight.NumOfIntWinAdjEnclExtWins; ++AdjExtWinLoop) {
7747 2424 : if (IWin == thisEnclDaylight.IntWinAdjEnclExtWin(AdjExtWinLoop).SurfNum) { // found it
7748 2424 : IntWinAdjZoneExtWinNum = AdjExtWinLoop;
7749 2424 : break; // added TH 4/13/2010
7750 : }
7751 : }
7752 : }
7753 :
7754 : // Initialize window luminance and fluxes for split-flux calculation
7755 319816 : state.dataDaylightingManager->WLUMSK(IHR, _, _) = 0.0;
7756 319816 : state.dataDaylightingManager->WLUMSU(IHR, _) = 0.0;
7757 319816 : state.dataDaylightingManager->WLUMSUdisk(IHR, _) = 0.0;
7758 319816 : FLFWSK = 0.0;
7759 319816 : FLFWSU = 0.0;
7760 319816 : FLFWSUdisk = 0.0;
7761 319816 : FLCWSK = 0.0;
7762 319816 : FLCWSU = 0.0;
7763 :
7764 319816 : int const IConst = state.dataSurface->SurfActiveConstruction(IWin);
7765 319816 : BlindOn = false;
7766 319816 : ShadeOn = false;
7767 319816 : ScreenOn = false;
7768 :
7769 319816 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
7770 4896 : PipeNum = state.dataSurface->SurfWinTDDPipeNum(IWin);
7771 : }
7772 :
7773 319816 : ShelfNum = state.dataSurface->SurfDaylightingShelfInd(IWin);
7774 319816 : if (ShelfNum > 0) {
7775 2448 : InShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).InSurf; // Inside daylighting shelf present if > 0
7776 2448 : OutShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf; // Outside daylighting shelf present if > 0
7777 : } else {
7778 317368 : InShelfSurf = 0;
7779 317368 : OutShelfSurf = 0;
7780 : }
7781 :
7782 : // Divide sky and ground into elements of altitude PH and
7783 : // azimuth TH, and add the contribution of light coming from each
7784 : // element to the transmitted flux at the center of the window
7785 : // Azimuth ranges over a maximum of 2 Pi radians.
7786 : // Altitude ranges over a maximum of Pi/2 radians between -Pi/2 < PH < +Pi/2, so that elements are not counted twice
7787 : // PH = 0 at the horizon; PH = Pi/2 at the zenith
7788 319816 : PHMIN = max(-DataGlobalConstants::PiOvr2, state.dataSurface->SurfWinPhi(IWin) - DataGlobalConstants::PiOvr2);
7789 319816 : PHMAX = min(DataGlobalConstants::PiOvr2, state.dataSurface->SurfWinPhi(IWin) + DataGlobalConstants::PiOvr2);
7790 319816 : DPH = (PHMAX - PHMIN) / double(NPHMAX);
7791 :
7792 : // Sky/ground element altitude integration
7793 639632 : Vector3<Real64> const SUNCOS_IHR(state.dataSurface->SurfSunCosHourly(IHR));
7794 3517976 : for (IPH = 1; IPH <= NPHMAX; ++IPH) {
7795 3198160 : PH = PHMIN + (double(IPH) - 0.5) * DPH;
7796 :
7797 3198160 : SPH = std::sin(PH);
7798 3198160 : CPH = std::cos(PH);
7799 : // Third component of unit vector in (TH,PH) direction
7800 3198160 : U(3) = SPH;
7801 :
7802 : // Limits of azimuth integration
7803 3198160 : PhWin = state.dataSurface->SurfWinPhi(IWin);
7804 3198160 : ThWin = state.dataSurface->SurfWinTheta(IWin);
7805 3198160 : if (PhWin >= 0.0) {
7806 3198160 : if (PH >= DataGlobalConstants::PiOvr2 - PhWin) {
7807 633828 : ThMin = -DataGlobalConstants::Pi;
7808 633828 : ThMax = DataGlobalConstants::Pi;
7809 : } else {
7810 2564332 : ACosTanTan = std::acos(-std::tan(PH) * std::tan(PhWin));
7811 2564332 : ThMin = ThWin - std::abs(ACosTanTan);
7812 2564332 : ThMax = ThWin + std::abs(ACosTanTan);
7813 : }
7814 :
7815 : } else { // PhiSurf < 0.0
7816 0 : if (PH <= -PhWin - DataGlobalConstants::PiOvr2) {
7817 0 : ThMin = -DataGlobalConstants::Pi;
7818 0 : ThMax = DataGlobalConstants::Pi;
7819 : } else {
7820 0 : ACosTanTan = std::acos(-std::tan(PH) * std::tan(PhWin));
7821 0 : ThMin = ThWin - std::abs(ACosTanTan);
7822 0 : ThMax = ThWin + std::abs(ACosTanTan);
7823 : }
7824 : }
7825 :
7826 3198160 : DTH = (ThMax - ThMin) / double(NTHMAX);
7827 3198160 : DA = CPH * DTH * DPH;
7828 :
7829 : // Sky/ground element azimuth integration
7830 3198160 : Real64 const sin_window_phi(std::sin(state.dataSurface->SurfWinPhi(IWin)));
7831 3198160 : Real64 const cos_window_phi(std::cos(state.dataSurface->SurfWinPhi(IWin)));
7832 54368720 : for (ITH = 1; ITH <= NTHMAX; ++ITH) {
7833 51170560 : TH = ThMin + (double(ITH) - 0.5) * DTH;
7834 51170560 : U(1) = CPH * std::cos(TH);
7835 51170560 : U(2) = CPH * std::sin(TH);
7836 : // Cosine of angle of incidence of light from sky or ground element
7837 51170560 : COSB = SPH * sin_window_phi + CPH * cos_window_phi * std::cos(TH - state.dataSurface->SurfWinTheta(IWin));
7838 51170560 : if (COSB < 0.0) continue; // Sky/ground elements behind window (although there shouldn't be any)
7839 :
7840 : // Initialize illuminance on window for this sky/ground element
7841 51170560 : ZSK = 0.0;
7842 51170560 : ZSU = 0.0;
7843 : // Initialize illuminance on window from beam solar reflection if ray hits an obstruction
7844 51170560 : ZSUObsRefl = 0.0;
7845 :
7846 51170560 : if (ISunPos == 1) { // Intersection calculation has to be done only for first sun position
7847 : // Determine net transmittance of obstructions that the ray hits. ObTrans will be 1.0
7848 : // if no obstructions are hit.
7849 4037440 : DayltgHitObstruction(state, IHR, IWin, state.dataSurface->SurfaceWindow(IWin).WinCenter, U, ObTrans);
7850 4037440 : ObTransM(IPH, ITH) = ObTrans;
7851 : }
7852 :
7853 : // SKY AND GROUND RADIATION ON WINDOW
7854 :
7855 : // Contribution is from sky if PH > 0 (ray goes upward), and from ground if PH < 0 (ray goes downward)
7856 : // (There may also be contributions from reflection from obstructions; see 'BEAM SOLAR AND SKY SOLAR
7857 : // REFLECTED FROM NEAREST OBSTRUCTION,' below.)
7858 :
7859 51170560 : if (ISunPos == 1) SkyObstructionMult(IPH, ITH) = 1.0;
7860 51170560 : if (PH > 0.0) { // Contribution is from sky
7861 153279520 : for (ISky = 1; ISky <= 4; ++ISky) {
7862 122623616 : ZSK(ISky) = DayltgSkyLuminance(state, ISky, TH, PH) * COSB * DA * ObTransM(IPH, ITH);
7863 : }
7864 : } else { // PH <= 0.0; contribution is from ground
7865 20514656 : if (state.dataSurface->CalcSolRefl && ObTransM(IPH, ITH) > 1.e-6 && ISunPos == 1) {
7866 : // Calculate effect of obstructions on shading of sky diffuse reaching the ground point hit
7867 : // by the ray. This effect is given by the ratio SkyObstructionMult =
7868 : // (obstructed sky diffuse at ground point)/(unobstructed sky diffuse at ground point).
7869 : // This ratio is calculated for an isotropic sky.
7870 : // Ground point hit by the ray:
7871 640 : Alfa = std::acos(-U(3));
7872 640 : Beta = std::atan2(U(2), U(1));
7873 640 : HorDis = (state.dataSurface->SurfaceWindow(IWin).WinCenter(3) - state.dataSurface->GroundLevelZ) * std::tan(Alfa);
7874 640 : DayltgInterReflectedIllumGroundHitPt(3) = state.dataSurface->GroundLevelZ;
7875 640 : DayltgInterReflectedIllumGroundHitPt(1) = state.dataSurface->SurfaceWindow(IWin).WinCenter(1) + HorDis * std::cos(Beta);
7876 640 : DayltgInterReflectedIllumGroundHitPt(2) = state.dataSurface->SurfaceWindow(IWin).WinCenter(2) + HorDis * std::sin(Beta);
7877 :
7878 640 : SkyObstructionMult(IPH, ITH) =
7879 640 : CalcObstrMultiplier(state, DayltgInterReflectedIllumGroundHitPt, AltAngStepsForSolReflCalc, AzimAngStepsForSolReflCalc);
7880 : } // End of check if solar reflection calc is in effect
7881 102573280 : for (ISky = 1; ISky <= 4; ++ISky) {
7882 : // Below, luminance of ground in cd/m2 is illuminance on ground in lumens/m2
7883 : // times ground reflectance, divided by pi, times obstruction multiplier.
7884 82058624 : ZSK(ISky) =
7885 82058624 : (state.dataDaylightingManager->GILSK(IHR, ISky) * state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi) * COSB *
7886 82058624 : DA * ObTransM(IPH, ITH) * SkyObstructionMult(IPH, ITH);
7887 : }
7888 : // Determine if sun illuminates the point that ray hits the ground. If the solar reflection
7889 : // calculation has been requested (CalcSolRefl = .TRUE.) shading by obstructions, including
7890 : // the building itself, is considered in determining whether sun hits the ground point.
7891 : // Otherwise this shading is ignored and the sun always hits the ground point.
7892 20514656 : SunObstructionMult = 1.0;
7893 20514656 : if (state.dataSurface->CalcSolRefl && ObTransM(IPH, ITH) > 1.e-6) {
7894 : // Sun reaches ground point if vector from this point to the sun is unobstructed
7895 7680 : hitObs = false;
7896 38134 : for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
7897 : PierceSurface(state, ObsSurfNum, DayltgInterReflectedIllumGroundHitPt, SUNCOS_IHR, DayltgInterReflectedIllumObsHitPt, hitObs);
7898 30712 : if (hitObs) break;
7899 : }
7900 7680 : if (hitObs) SunObstructionMult = 0.0;
7901 : }
7902 41029312 : ZSU = (state.dataDaylightingManager->GILSU(IHR) * state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi) * COSB * DA *
7903 20514656 : ObTransM(IPH, ITH) * SunObstructionMult;
7904 : }
7905 : // BEAM SOLAR AND SKY SOLAR REFLECTED FROM NEAREST OBSTRUCTION
7906 :
7907 51170560 : if (state.dataSurface->CalcSolRefl && ObTransM(IPH, ITH) < 1.0) {
7908 : // Find obstruction whose hit point is closest to the center of the window
7909 3840 : DayltgClosestObstruction(
7910 3840 : state, state.dataSurface->SurfaceWindow(IWin).WinCenter, U, NearestHitSurfNum, DayltgInterReflectedIllumNearestHitPt);
7911 3840 : if (NearestHitSurfNum > 0) {
7912 :
7913 : // Beam solar reflected from nearest obstruction.
7914 3840 : DayltgSurfaceLumFromSun(state, IHR, U, NearestHitSurfNum, DayltgInterReflectedIllumNearestHitPt, LumAtHitPtFrSun);
7915 3840 : ZSUObsRefl = LumAtHitPtFrSun * COSB * DA;
7916 3840 : ZSU += ZSUObsRefl;
7917 :
7918 : // Sky solar reflected from nearest obstruction.
7919 3840 : int const ObsConstrNum = state.dataSurface->Surface(NearestHitSurfNum).Construction;
7920 3840 : if (ObsConstrNum > 0) {
7921 : // Exterior building surface is nearest hit
7922 0 : if (!state.dataConstruction->Construct(ObsConstrNum).TypeIsWindow) {
7923 : // Obstruction is not a window, i.e., is an opaque surface
7924 0 : ObsVisRefl =
7925 0 : 1.0 - state.dataMaterial->Material(state.dataConstruction->Construct(ObsConstrNum).LayerPoint(1)).AbsorpVisible;
7926 : } else {
7927 : // Obstruction is a window; assume it is bare
7928 0 : ObsVisRefl = state.dataConstruction->Construct(ObsConstrNum).ReflectVisDiffFront;
7929 : }
7930 : } else {
7931 : // Shadowing surface is nearest hit
7932 3840 : if (state.dataSurface->SurfDaylightingShelfInd(NearestHitSurfNum) > 0) {
7933 : // Skip daylighting shelves, whose reflection is separately calculated
7934 0 : ObsVisRefl = 0.0;
7935 : } else {
7936 3840 : ObsVisRefl = state.dataSurface->SurfShadowDiffuseVisRefl(NearestHitSurfNum);
7937 3840 : if (state.dataSurface->SurfShadowGlazingConstruct(NearestHitSurfNum) > 0)
7938 0 : ObsVisRefl += state.dataSurface->SurfShadowGlazingFrac(NearestHitSurfNum) *
7939 0 : state.dataConstruction->Construct(state.dataSurface->SurfShadowGlazingConstruct(NearestHitSurfNum))
7940 0 : .ReflectVisDiffFront;
7941 : // Note in the above that ShadowSurfDiffuseVisRefl is the reflectance of opaque part of
7942 : // shadowing surface times (1 - ShadowSurfGlazingFrac)
7943 : }
7944 : }
7945 3840 : NearestHitSurfNumX = NearestHitSurfNum;
7946 : // Each shadowing surface has a "mirror" duplicate surface facing in the opposite direction.
7947 : // The following gets the correct side of a shadowing surface for reflection.
7948 3840 : if (state.dataSurface->Surface(NearestHitSurfNum).IsShadowing) {
7949 3840 : if (dot(U, state.dataSurface->Surface(NearestHitSurfNum).OutNormVec) > 0.0) NearestHitSurfNumX = NearestHitSurfNum + 1;
7950 : }
7951 3840 : if (!state.dataSysVars->DetailedSkyDiffuseAlgorithm || !state.dataSurface->ShadingTransmittanceVaries ||
7952 0 : state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
7953 7680 : SkyReflVisLum = ObsVisRefl * state.dataSurface->Surface(NearestHitSurfNumX).ViewFactorSky *
7954 3840 : state.dataSolarShading->SurfDifShdgRatioIsoSky(NearestHitSurfNumX) / DataGlobalConstants::Pi;
7955 : } else {
7956 0 : SkyReflVisLum = ObsVisRefl * state.dataSurface->Surface(NearestHitSurfNumX).ViewFactorSky *
7957 0 : state.dataSolarShading->SurfDifShdgRatioIsoSkyHRTS(1, IHR, NearestHitSurfNumX) / DataGlobalConstants::Pi;
7958 : }
7959 3840 : dReflObsSky = SkyReflVisLum * COSB * DA;
7960 19200 : for (ISky = 1; ISky <= 4; ++ISky) {
7961 15360 : ZSK(ISky) += state.dataDaylightingManager->GILSK(IHR, ISky) * dReflObsSky;
7962 : }
7963 : }
7964 : } // End of check if exterior solar reflection calculation is active
7965 :
7966 : // ===Bare window (no shade or blind; non-diffusing glass)===
7967 :
7968 : // Increment flux entering space and window luminance (cd/m2).
7969 : // FLCW--(I,J) = part of incoming flux (in lumens) that goes up to ceiling and upper part of walls.
7970 : // FLFW--(I,J) = part that goes down to floor and lower part of walls
7971 :
7972 51170560 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
7973 : // Unshaded visible transmittance of TDD for a single ray from sky/ground element
7974 783360 : TVISBR = TransTDD(state, PipeNum, COSB, DataDaylightingDevices::RadType::VisibleBeam) * state.dataSurface->SurfWinGlazedFrac(IWin);
7975 :
7976 : // Make all transmitted light diffuse for a TDD with a bare diffuser
7977 3916800 : for (ISky = 1; ISky <= 4; ++ISky) {
7978 3133440 : state.dataDaylightingManager->WLUMSK(IHR, 1, ISky) += ZSK(ISky) * TVISBR / DataGlobalConstants::Pi;
7979 3133440 : FLFWSK(1, ISky) += ZSK(ISky) * TVISBR * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
7980 3133440 : FLCWSK(1, ISky) += ZSK(ISky) * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
7981 :
7982 : // For later calculation of diffuse visible transmittance
7983 3133440 : state.dataDaylightingManager->TDDFluxInc(IHR, ISky, PipeNum) += ZSK(ISky);
7984 3133440 : state.dataDaylightingManager->TDDFluxTrans(IHR, ISky, PipeNum) += ZSK(ISky) * TVISBR;
7985 :
7986 3133440 : if (ISky == 1) {
7987 783360 : state.dataDaylightingManager->WLUMSU(IHR, 1) += ZSU * TVISBR / DataGlobalConstants::Pi;
7988 783360 : FLFWSU(1) += ZSU * TVISBR * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
7989 783360 : FLCWSU(1) += ZSU * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
7990 :
7991 : // For later calculation of diffuse visible transmittance
7992 783360 : state.dataDaylightingManager->TDDFluxInc(IHR, ISky, PipeNum) += ZSU;
7993 783360 : state.dataDaylightingManager->TDDFluxTrans(IHR, ISky, PipeNum) += ZSU * TVISBR;
7994 : }
7995 : }
7996 :
7997 : } else { // Bare window
7998 : // Transmittance of bare window for this sky/ground element
7999 100774400 : TVISBR = POLYF(COSB, state.dataConstruction->Construct(IConst).TransVisBeamCoef) * state.dataSurface->SurfWinGlazedFrac(IWin) *
8000 50387200 : state.dataSurface->SurfWinLightWellEff(IWin);
8001 :
8002 50387200 : if (InShelfSurf > 0) { // Inside daylighting shelf
8003 : // Daylighting shelf simplification: All light is diffuse
8004 : // SurfaceWindow(IWin)%FractionUpgoing is already set to 1.0 earlier
8005 1958400 : for (ISky = 1; ISky <= 4; ++ISky) {
8006 1566720 : FLCWSK(1, ISky) += ZSK(ISky) * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
8007 :
8008 1566720 : if (ISky == 1) {
8009 391680 : FLCWSU(1) += ZSU * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
8010 : }
8011 : }
8012 :
8013 : } else { // Normal window
8014 :
8015 : // CR 7869 correct TVISBR if disk beam passes thru interior window
8016 49995520 : if (ExtWinType == DataDaylighting::ExtWinType::AdjZoneExtWin) {
8017 : // modify TVISBR by second window transmission
8018 : // first determine if ray from point passes thru any interior window
8019 387840 : hitObs = false;
8020 387840 : for (IntWinLoop = 1; IntWinLoop <= thisEnclDaylight.IntWinAdjEnclExtWin(IntWinAdjZoneExtWinNum).NumOfIntWindows;
8021 : ++IntWinLoop) {
8022 0 : IntWinNum = thisEnclDaylight.IntWinAdjEnclExtWin(IntWinAdjZoneExtWinNum).IntWinNum(IntWinLoop);
8023 0 : PierceSurface(state,
8024 : IntWinNum,
8025 0 : state.dataSurface->SurfaceWindow(IntWinNum).WinCenter,
8026 : SUNCOS_IHR,
8027 : DayltgInterReflectedIllumObsHitPt,
8028 : hitObs);
8029 0 : if (hitObs) { // disk passes thru
8030 : // cosine of incidence angle of light from sky or ground element for
8031 0 : COSBintWin = SPH * std::sin(state.dataSurface->SurfWinPhi(IntWinNum)) +
8032 0 : CPH * std::cos(state.dataSurface->SurfWinPhi(IntWinNum)) *
8033 0 : std::cos(TH - state.dataSurface->SurfWinTheta(IntWinNum));
8034 0 : TVISBR *=
8035 0 : POLYF(COSBintWin,
8036 0 : state.dataConstruction->Construct(state.dataSurface->Surface(IntWinNum).Construction).TransVisBeamCoef);
8037 0 : break;
8038 : }
8039 : }
8040 387840 : if (!hitObs) { // blocked by opaque parts, beam does not actually pass thru interior window to reach zone
8041 387840 : TVISBR = 0.0;
8042 : }
8043 : }
8044 :
8045 249977600 : for (ISky = 1; ISky <= 4; ++ISky) {
8046 : // IF (PH < 0.0d0) THEN
8047 : // Fixed by FCW, Nov. 2003:
8048 199982080 : if (PH > 0.0) {
8049 119020160 : FLFWSK(1, ISky) += ZSK(ISky) * TVISBR;
8050 119020160 : if (ISky == 1) FLFWSU(1) += ZSU * TVISBR;
8051 : } else {
8052 80961920 : FLCWSK(1, ISky) += ZSK(ISky) * TVISBR;
8053 80961920 : if (ISky == 1) FLCWSU(1) += ZSU * TVISBR;
8054 : }
8055 : }
8056 : } // End of check if window with daylighting shelf or normal window
8057 : } // End of check if TDD:DOME or bare window
8058 :
8059 : // Check if window has shade or blind
8060 51170560 : ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
8061 51170560 : if (state.dataSurface->Surface(IWin).HasShadeControl) {
8062 23781440 : ShType = state.dataSurface->WindowShadingControl(ICtrl).ShadingType;
8063 23781440 : BlNum = state.dataSurface->SurfWinBlindNumber(IWin);
8064 : // ScNum = SurfaceWindow( IWin ).ScreenNumber; //Unused Set but never used
8065 :
8066 23781440 : ShadeOn = ANY_SHADE(ShType);
8067 23781440 : BlindOn = ANY_BLIND(ShType);
8068 23781440 : ScreenOn = (ShType == WinShadingType::ExtScreen);
8069 : }
8070 :
8071 51170560 : if (ShadeOn || BlindOn || ScreenOn || state.dataSurface->SurfWinSolarDiffusing(IWin)) {
8072 :
8073 : // ===Window with interior or exterior shade or blind, exterior screen, or with diffusing glass===
8074 :
8075 : // Increment flux entering space and window luminance. Shades and diffusing glass are
8076 : // assumed to be perfect diffusers, i.e., the transmittance is independent of angle of
8077 : // incidence and the transmitted light is isotropic. The transmittance of a blind is
8078 : // assumed to depend on profile angle and slat angle; the diffuse light entering the room from
8079 : // the slats of the blind is assumed to be isotropic. With blinds, light can also enter
8080 : // the room by passing between the slats without reflection. The beam transmittance of a screen
8081 : // is assumed to depend on sun azimuth and azimuth angle.
8082 :
8083 : // For light from a shade, or from diffusing glass, or from the slats of a blind, a flux fraction,
8084 : // SurfaceWindow(IWin)%FractionUpgoing (determined by window tilt), goes up toward
8085 : // ceiling and upper part of walls, and 1-Surfacewindow(iwin)%FractionUpgoing
8086 : // goes down toward floor and lower part of walls. For a blind, the light passing
8087 : // between the slats goes either up or down depending on the altitude angle of the
8088 : // element from which the light came. For a screen, the light passing
8089 : // between the screen's cylinders goes either up or down depending on the altitude angle of the
8090 : // element from which the light came.
8091 :
8092 23040 : int IConstShaded = state.dataSurface->SurfWinActiveShadedConstruction(IWin);
8093 23040 : if (state.dataSurface->SurfWinSolarDiffusing(IWin)) IConstShaded = state.dataSurface->Surface(IWin).Construction;
8094 :
8095 : // Transmittance of window including shade, screen or blind
8096 23040 : DayltgInterReflectedIllumTransBmBmMult = 0.0;
8097 23040 : TransMult = 0.0;
8098 :
8099 23040 : if (ShadeOn) { // Shade
8100 23040 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
8101 : // Shaded visible transmittance of TDD for a single ray from sky/ground element
8102 0 : TransMult(1) =
8103 0 : TransTDD(state, PipeNum, COSB, DataDaylightingDevices::RadType::VisibleBeam) * state.dataSurface->SurfWinGlazedFrac(IWin);
8104 : } else { // Shade only, no TDD
8105 : // Calculate transmittance of the combined window and shading device for this sky/ground element
8106 69120 : TransMult(1) = POLYF(COSB, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) *
8107 46080 : state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
8108 : }
8109 :
8110 0 : } else if (ScreenOn) { // Screen: get beam-beam, beam-diffuse and diffuse-diffuse vis trans/ref of screen and glazing system
8111 0 : CalcScreenTransmittance(state, IWin, (PH - state.dataSurface->SurfWinPhi(IWin)), (TH - state.dataSurface->SurfWinTheta(IWin)));
8112 0 : ReflGlDiffDiffFront = state.dataConstruction->Construct(IConst).ReflectVisDiffFront;
8113 0 : ReflScDiffDiffBack = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).DifReflectVis;
8114 0 : TransScBmDiffFront = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).BmDifTransVis;
8115 0 : TransMult(1) = TransScBmDiffFront * state.dataSurface->SurfWinGlazedFrac(IWin) *
8116 0 : state.dataConstruction->Construct(IConst).TransDiffVis / (1 - ReflGlDiffDiffFront * ReflScDiffDiffBack) *
8117 0 : state.dataSurface->SurfWinLightWellEff(IWin);
8118 0 : DayltgInterReflectedIllumTransBmBmMult(1) =
8119 0 : state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).BmBmTransVis;
8120 :
8121 0 : } else if (BlindOn) { // Blind: get beam-diffuse and beam-beam vis trans of blind+glazing system
8122 : // PETER: As long as only interior blinds are allowed for TDDs, no need to change TransMult calculation
8123 : // for TDDs because it is based on TVISBR which is correctly calculated for TDDs above.
8124 :
8125 0 : ProfileAngle(state, IWin, U, state.dataHeatBal->Blind(BlNum).SlatOrientation, ProfAng);
8126 :
8127 0 : for (JB = 1; JB <= MaxSlatAngs; ++JB) {
8128 0 : if (!state.dataSurface->SurfWinMovableSlats(IWin) && JB > 1) break;
8129 :
8130 0 : TransBlBmDiffFront = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37}));
8131 :
8132 0 : if (ShType == WinShadingType::IntBlind) { // Interior blind
8133 0 : ReflGlDiffDiffBack = state.dataConstruction->Construct(IConst).ReflectVisDiffBack;
8134 0 : ReflBlBmDiffFront = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37}));
8135 0 : ReflBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffRefl(JB);
8136 0 : TransBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffTrans(JB);
8137 0 : TransMult(JB) = TVISBR * (TransBlBmDiffFront + ReflBlBmDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront /
8138 0 : (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack));
8139 :
8140 0 : } else if (ShType == WinShadingType::ExtBlind) { // Exterior blind
8141 0 : ReflGlDiffDiffFront = state.dataConstruction->Construct(IConst).ReflectVisDiffFront;
8142 0 : ReflBlDiffDiffBack = state.dataHeatBal->Blind(BlNum).VisBackDiffDiffRefl(JB);
8143 0 : TransMult(JB) = TransBlBmDiffFront * state.dataSurface->SurfWinGlazedFrac(IWin) *
8144 0 : state.dataConstruction->Construct(IConst).TransDiffVis /
8145 0 : (1.0 - ReflGlDiffDiffFront * ReflBlDiffDiffBack) * state.dataSurface->SurfWinLightWellEff(IWin);
8146 :
8147 : } else { // Between-glass blind
8148 0 : t1 = POLYF(COSB, state.dataConstruction->Construct(IConst).tBareVisCoef(1));
8149 0 : td2 = state.dataConstruction->Construct(IConst).tBareVisDiff(2);
8150 0 : rbd1 = state.dataConstruction->Construct(IConst).rbBareVisDiff(1);
8151 0 : rfd2 = state.dataConstruction->Construct(IConst).rfBareVisDiff(2);
8152 0 : tfshBd = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37}));
8153 0 : tfshd = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffTrans(JB);
8154 0 : rfshB = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37}));
8155 0 : rbshd = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffRefl(JB);
8156 0 : if (state.dataConstruction->Construct(IConst).TotGlassLayers == 2) { // 2 glass layers
8157 0 : TransMult(JB) =
8158 0 : t1 * (tfshBd * (1.0 + rfd2 * rbshd) + rfshB * rbd1 * tfshd) * td2 * state.dataSurface->SurfWinLightWellEff(IWin);
8159 : } else { // 3 glass layers; blind between layers 2 and 3
8160 0 : t2 = POLYF(COSB, state.dataConstruction->Construct(IConst).tBareVisCoef(2));
8161 0 : td3 = state.dataConstruction->Construct(IConst).tBareVisDiff(3);
8162 0 : rfd3 = state.dataConstruction->Construct(IConst).rfBareVisDiff(3);
8163 0 : rbd2 = state.dataConstruction->Construct(IConst).rbBareVisDiff(2);
8164 0 : TransMult(JB) = t1 * t2 * (tfshBd * (1.0 + rfd3 * rbshd) + rfshB * (rbd2 * tfshd + td2 * rbd1 * td2 * tfshd)) * td3 *
8165 0 : state.dataSurface->SurfWinLightWellEff(IWin);
8166 : }
8167 : }
8168 :
8169 0 : if (state.dataSurface->SurfWinMovableSlats(IWin)) {
8170 0 : SlatAng = (JB - 1) * DataGlobalConstants::Pi / (MaxSlatAngs - 1);
8171 : } else {
8172 0 : SlatAng = state.dataHeatBal->Blind(BlNum).SlatAngle * DataGlobalConstants::DegToRadians;
8173 : }
8174 0 : DayltgInterReflectedIllumTransBmBmMult(JB) =
8175 0 : TVISBR * General::BlindBeamBeamTrans(ProfAng,
8176 : SlatAng,
8177 0 : state.dataHeatBal->Blind(BlNum).SlatWidth,
8178 0 : state.dataHeatBal->Blind(BlNum).SlatSeparation,
8179 0 : state.dataHeatBal->Blind(BlNum).SlatThickness);
8180 : } // End of loop over slat angles
8181 :
8182 : } else { // Diffusing glass
8183 0 : TransMult(1) = POLYF(COSB, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) *
8184 0 : state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
8185 : } // End of check if shade, blind or diffusing glass
8186 :
8187 23040 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
8188 : // No beam is transmitted. This takes care of all types of screens and blinds.
8189 0 : DayltgInterReflectedIllumTransBmBmMult = 0.0;
8190 : }
8191 :
8192 : // Daylighting shelf simplification: No beam makes it past end of shelf, all light is diffuse
8193 23040 : if (InShelfSurf > 0) { // Inside daylighting shelf
8194 0 : DayltgInterReflectedIllumTransBmBmMult = 0.0; // No beam, diffuse only
8195 : }
8196 :
8197 : // DayltgInterReflectedIllumTransBmBmMult is used in the following for windows with blinds or screens to get contribution from light
8198 : // passing directly between slats or between screen material without reflection.
8199 :
8200 115200 : for (ISky = 1; ISky <= 4; ++ISky) {
8201 184320 : for (JB = 1; JB <= MaxSlatAngs; ++JB) {
8202 : // EXIT after first pass if not movable slats or exterior window screen
8203 184320 : if (!state.dataSurface->SurfWinMovableSlats(IWin) && JB > 1) break;
8204 :
8205 92160 : state.dataDaylightingManager->WLUMSK(IHR, JB + 1, ISky) += ZSK(ISky) * TransMult(JB) / DataGlobalConstants::Pi;
8206 92160 : FLFWSK(JB + 1, ISky) += ZSK(ISky) * TransMult(JB) * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
8207 92160 : if (PH > 0.0 && (BlindOn || ScreenOn)) FLFWSK(JB + 1, ISky) += ZSK(ISky) * DayltgInterReflectedIllumTransBmBmMult(JB);
8208 92160 : FLCWSK(JB + 1, ISky) += ZSK(ISky) * TransMult(JB) * state.dataSurface->SurfWinFractionUpgoing(IWin);
8209 92160 : if (PH <= 0.0 && (BlindOn || ScreenOn)) FLCWSK(JB + 1, ISky) += ZSK(ISky) * DayltgInterReflectedIllumTransBmBmMult(JB);
8210 92160 : if (ISky == 1) {
8211 23040 : state.dataDaylightingManager->WLUMSU(IHR, JB + 1) += ZSU * TransMult(JB) / DataGlobalConstants::Pi;
8212 23040 : FLFWSU(JB + 1) += ZSU * TransMult(JB) * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
8213 23040 : if (PH > 0.0 && (BlindOn || ScreenOn)) FLFWSU(JB + 1) += ZSU * DayltgInterReflectedIllumTransBmBmMult(JB);
8214 23040 : FLCWSU(JB + 1) += ZSU * TransMult(JB) * state.dataSurface->SurfWinFractionUpgoing(IWin);
8215 23040 : if (PH <= 0.0 && (BlindOn || ScreenOn)) FLCWSU(JB + 1) += ZSU * DayltgInterReflectedIllumTransBmBmMult(JB);
8216 : }
8217 : }
8218 : }
8219 : } // End of window with shade, screen, blind or diffusing glass
8220 :
8221 : } // End of azimuth integration loop, ITH
8222 : } // End of altitude integration loop, IPH
8223 :
8224 319816 : if (OutShelfSurf > 0) { // Outside daylighting shelf
8225 : // Add exterior diffuse illuminance due to outside shelf
8226 : // Since all of the illuminance is added to the zone as upgoing diffuse, it can be added as a lump sum here
8227 :
8228 2448 : TVISBR = state.dataConstruction->Construct(IConst).TransDiffVis; // Assume diffuse transmittance for shelf illuminance
8229 :
8230 12240 : for (ISky = 1; ISky <= 4; ++ISky) {
8231 : // This is only an estimate because the anisotropic sky view of the shelf is not yet taken into account.
8232 : // SurfAnisoSkyMult would be great to use but it is not available until the heat balance starts up.
8233 19584 : ZSK(ISky) = state.dataDaylightingManager->GILSK(IHR, ISky) * 1.0 * state.dataDaylightingDevicesData->Shelf(ShelfNum).OutReflectVis *
8234 9792 : state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor;
8235 :
8236 : // SurfaceWindow(IWin)%FractionUpgoing is already set to 1.0 earlier
8237 9792 : FLCWSK(1, ISky) += ZSK(ISky) * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
8238 :
8239 9792 : if (ISky == 1) {
8240 7344 : ZSU = state.dataDaylightingManager->GILSU(IHR) * state.dataHeatBal->SurfSunlitFracHR(IHR, OutShelfSurf) *
8241 4896 : state.dataDaylightingDevicesData->Shelf(ShelfNum).OutReflectVis * state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor;
8242 2448 : FLCWSU(1) += ZSU * TVISBR * state.dataSurface->SurfWinFractionUpgoing(IWin);
8243 : }
8244 : } // ISKY
8245 : }
8246 :
8247 : // Sky-related portion of internally reflected illuminance.
8248 : // The inside surface area, ZoneDaylight(ZoneNum)%totInsSurfArea, and ZoneDaylight(ZoneNum)%aveVisDiffReflect,
8249 : // were calculated in subr DayltgAveInteriorReflectance.
8250 :
8251 1599080 : for (ISky = 1; ISky <= 4; ++ISky) {
8252 3837792 : for (JSH = 1; JSH <= MaxSlatAngs + 1; ++JSH) {
8253 3837792 : if (!state.dataSurface->SurfWinMovableSlats(IWin) && JSH > 2) break;
8254 : // Full area of window is used in following since effect of dividers on reducing
8255 : // effective window transmittance has already been accounted for in calc of FLFWSK and FLCWSK.
8256 2558528 : state.dataDaylightingManager->EINTSK(IHR, JSH, ISky) =
8257 5117056 : (FLFWSK(JSH, ISky) * state.dataSurface->SurfWinRhoFloorWall(IWin) +
8258 5117056 : FLCWSK(JSH, ISky) * state.dataSurface->SurfWinRhoCeilingWall(IWin)) *
8259 5117056 : (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
8260 2558528 : (EnclInsideSurfArea * (1.0 - state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect));
8261 : } // JSH
8262 : } // ISKY
8263 :
8264 : // BEAM SOLAR RADIATION ON WINDOW
8265 :
8266 : // Beam reaching window directly (without specular reflection from exterior obstructions)
8267 :
8268 319816 : if (state.dataHeatBal->SurfSunlitFracHR(IHR, IWin) > 0.0) {
8269 : // Cos of angle of incidence
8270 482922 : COSBSun = state.dataDaylightingManager->SPHSUN * std::sin(state.dataSurface->SurfWinPhi(IWin)) +
8271 482922 : state.dataDaylightingManager->CPHSUN * std::cos(state.dataSurface->SurfWinPhi(IWin)) *
8272 241461 : std::cos(state.dataDaylightingManager->THSUN - state.dataSurface->SurfWinTheta(IWin));
8273 :
8274 241461 : if (COSBSun > 0.0) {
8275 : // Multiply direct normal illuminance (normalized to 1.0 lux)
8276 : // by incident angle factor and by fraction of window that is sunlit.
8277 : // Note that in the following SurfSunlitFracHR accounts for possibly non-zero transmittance of
8278 : // shading surfaces.
8279 :
8280 241461 : ZSU1 = COSBSun * state.dataHeatBal->SurfSunlitFracHR(IHR, IWin);
8281 :
8282 : // Contribution to window luminance and downgoing flux
8283 :
8284 : // -- Bare window
8285 :
8286 241461 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
8287 : // Unshaded visible transmittance of TDD for collimated beam from the sun
8288 4488 : TVISBSun =
8289 4488 : TransTDD(state, PipeNum, COSBSun, DataDaylightingDevices::RadType::VisibleBeam) * state.dataSurface->SurfWinGlazedFrac(IWin);
8290 4488 : state.dataDaylightingManager->TDDTransVisBeam(IHR, PipeNum) = TVISBSun;
8291 :
8292 4488 : FLFWSUdisk(1) = 0.0; // Diffuse light only
8293 :
8294 4488 : state.dataDaylightingManager->WLUMSU(IHR, 1) += ZSU1 * TVISBSun / DataGlobalConstants::Pi;
8295 4488 : FLFWSU(1) += ZSU1 * TVISBSun * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
8296 4488 : FLCWSU(1) += ZSU1 * TVISBSun * state.dataSurface->SurfWinFractionUpgoing(IWin);
8297 :
8298 : } else { // Bare window
8299 473946 : TVISBSun = POLYF(COSBSun, state.dataConstruction->Construct(IConst).TransVisBeamCoef) * state.dataSurface->SurfWinGlazedFrac(IWin) *
8300 236973 : state.dataSurface->SurfWinLightWellEff(IWin);
8301 :
8302 : // Daylighting shelf simplification: No beam makes it past end of shelf, all light is diffuse
8303 236973 : if (InShelfSurf > 0) { // Inside daylighting shelf
8304 1836 : FLFWSUdisk(1) = 0.0; // Diffuse light only
8305 :
8306 : // SurfaceWindow(IWin)%FractionUpgoing is already set to 1.0 earlier
8307 : // WLUMSU(1,IHR) = WLUMSU(1,IHR) + ZSU1 * TVISBSun / PI
8308 : // FLFWSU(1) = FLFWSU(1) + ZSU1 * TVISBSun * (1.0 - SurfaceWindow(IWin)%FractionUpgoing)
8309 1836 : FLCWSU(1) += ZSU1 * TVISBSun * state.dataSurface->SurfWinFractionUpgoing(IWin);
8310 : } else { // Normal window
8311 235137 : FLFWSUdisk(1) = ZSU1 * TVISBSun;
8312 : }
8313 : }
8314 :
8315 : // -- Window with shade, screen, blind or diffusing glass
8316 241461 : if (ShadeOn || BlindOn || ScreenOn || state.dataSurface->SurfWinSolarDiffusing(IWin)) {
8317 66 : DayltgInterReflectedIllumTransBmBmMult = 0.0;
8318 66 : TransMult = 0.0;
8319 :
8320 : // TH 7/7/2010 moved from inside the loop: DO JB = 1,MaxSlatAngs
8321 66 : if (BlindOn)
8322 0 : ProfileAngle(state, IWin, state.dataSurface->SurfSunCosHourly(IHR), state.dataHeatBal->Blind(BlNum).SlatOrientation, ProfAng);
8323 :
8324 132 : for (JB = 1; JB <= MaxSlatAngs; ++JB) {
8325 132 : if (!state.dataSurface->SurfWinMovableSlats(IWin) && JB > 1) break;
8326 :
8327 66 : if (ShadeOn || ScreenOn || state.dataSurface->SurfWinSolarDiffusing(IWin)) { // Shade or screen on or diffusing glass
8328 66 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
8329 : // Shaded visible transmittance of TDD for collimated beam from the sun
8330 0 : TransMult(1) = TransTDD(state, PipeNum, COSBSun, DataDaylightingDevices::RadType::VisibleBeam) *
8331 0 : state.dataSurface->SurfWinGlazedFrac(IWin);
8332 : } else {
8333 66 : if (ScreenOn) {
8334 0 : TransMult(1) = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).BmBmTransVis *
8335 0 : state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
8336 : } else {
8337 66 : int IConstShaded = state.dataSurface->SurfWinActiveShadedConstruction(IWin);
8338 66 : if (state.dataSurface->SurfWinSolarDiffusing(IWin)) IConstShaded = state.dataSurface->Surface(IWin).Construction;
8339 198 : TransMult(1) = POLYF(COSBSun, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) *
8340 132 : state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
8341 : }
8342 : }
8343 :
8344 : } else { // Blind on
8345 :
8346 : // As long as only interior blinds are allowed for TDDs, no need to change TransMult calculation
8347 : // for TDDs because it is based on TVISBSun which is correctly calculated for TDDs above.
8348 :
8349 0 : TransBlBmDiffFront = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37}));
8350 :
8351 0 : if (ShType == WinShadingType::IntBlind) { // Interior blind
8352 : // TH CR 8121, 7/7/2010
8353 : // ReflBlBmDiffFront = InterpProfAng(ProfAng,Blind(BlNum)%VisFrontBeamDiffRefl)
8354 0 : ReflBlBmDiffFront = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37}));
8355 :
8356 : // TH added 7/12/2010 for CR 8121
8357 0 : ReflBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffRefl(JB);
8358 0 : TransBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffTrans(JB);
8359 :
8360 0 : TransMult(JB) = TVISBSun * (TransBlBmDiffFront + ReflBlBmDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront /
8361 0 : (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack));
8362 :
8363 0 : } else if (ShType == WinShadingType::ExtBlind) { // Exterior blind
8364 0 : TransMult(JB) = TransBlBmDiffFront *
8365 0 : (state.dataConstruction->Construct(IConst).TransDiffVis /
8366 0 : (1.0 - ReflGlDiffDiffFront * state.dataHeatBal->Blind(BlNum).VisBackDiffDiffRefl(JB))) *
8367 0 : state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
8368 :
8369 : } else { // Between-glass blind
8370 0 : t1 = POLYF(COSBSun, state.dataConstruction->Construct(IConst).tBareVisCoef(1));
8371 0 : tfshBd = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffTrans(JB, {1, 37}));
8372 0 : rfshB = InterpProfAng(ProfAng, state.dataHeatBal->Blind(BlNum).VisFrontBeamDiffRefl(JB, {1, 37}));
8373 0 : if (state.dataConstruction->Construct(IConst).TotGlassLayers == 2) { // 2 glass layers
8374 0 : TransMult(JB) =
8375 0 : t1 * (tfshBd * (1.0 + rfd2 * rbshd) + rfshB * rbd1 * tfshd) * td2 * state.dataSurface->SurfWinLightWellEff(IWin);
8376 : } else { // 3 glass layers; blind between layers 2 and 3
8377 0 : t2 = POLYF(COSBSun, state.dataConstruction->Construct(IConst).tBareVisCoef(2));
8378 0 : TransMult(JB) = t1 * t2 * (tfshBd * (1.0 + rfd3 * rbshd) + rfshB * (rbd2 * tfshd + td2 * rbd1 * td2 * tfshd)) * td3 *
8379 0 : state.dataSurface->SurfWinLightWellEff(IWin);
8380 : }
8381 : }
8382 0 : if (state.dataSurface->SurfWinMovableSlats(IWin)) {
8383 0 : SlatAng = (JB - 1) * DataGlobalConstants::Pi / (MaxSlatAngs - 1);
8384 : } else {
8385 0 : SlatAng = state.dataHeatBal->Blind(BlNum).SlatAngle * DataGlobalConstants::DegToRadians;
8386 : }
8387 0 : DayltgInterReflectedIllumTransBmBmMult(JB) =
8388 0 : TVISBSun * General::BlindBeamBeamTrans(ProfAng,
8389 : SlatAng,
8390 0 : state.dataHeatBal->Blind(BlNum).SlatWidth,
8391 0 : state.dataHeatBal->Blind(BlNum).SlatSeparation,
8392 0 : state.dataHeatBal->Blind(BlNum).SlatThickness);
8393 : } // ShadeOn/ScreenOn/BlindOn/Diffusing glass
8394 :
8395 66 : if (state.dataSurface->SurfWinOriginalClass(IWin) == SurfaceClass::TDD_Dome) {
8396 0 : DayltgInterReflectedIllumTransBmBmMult = 0.0; // No beam, diffuse only
8397 : }
8398 :
8399 : // Daylighting shelf simplification: No beam makes it past end of shelf, all light is diffuse
8400 66 : if (InShelfSurf > 0) { // Inside daylighting shelf
8401 0 : DayltgInterReflectedIllumTransBmBmMult = 0.0; // No beam, diffuse only (Not sure if this really works)
8402 : // SurfaceWindow(IWin)%FractionUpgoing is already set to 1.0 earlier
8403 : }
8404 :
8405 66 : state.dataDaylightingManager->WLUMSU(IHR, JB + 1) += ZSU1 * TransMult(JB) / DataGlobalConstants::Pi;
8406 66 : state.dataDaylightingManager->WLUMSUdisk(IHR, JB + 1) =
8407 66 : ZSU1 * DayltgInterReflectedIllumTransBmBmMult(JB) / DataGlobalConstants::Pi;
8408 66 : FLFWSU(JB + 1) += ZSU1 * TransMult(JB) * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
8409 66 : FLFWSUdisk(JB + 1) = ZSU1 * DayltgInterReflectedIllumTransBmBmMult(JB);
8410 66 : FLCWSU(JB + 1) += ZSU1 * TransMult(JB) * state.dataSurface->SurfWinFractionUpgoing(IWin);
8411 : } // End of loop over slat angles
8412 : } // End of window with shade or blind
8413 : } // COSBSun > 0
8414 : } // SurfSunlitFracHR > 0
8415 :
8416 : // Beam reaching window after specular reflection from exterior obstruction
8417 :
8418 : // In the following, Beam normal illuminance times ZSU1refl = illuminance on window due to
8419 : // specular reflection from exterior surfaces
8420 :
8421 319816 : if (state.dataSurface->CalcSolRefl && state.dataSurface->SurfWinOriginalClass(IWin) != SurfaceClass::TDD_Dome) {
8422 96 : ZSU1refl = state.dataSurface->SurfReflFacBmToBmSolObs(IHR, IWin);
8423 :
8424 96 : if (ZSU1refl > 0.0) {
8425 : // Contribution to window luminance and downgoing flux
8426 :
8427 : // -- Bare window. We use diffuse-diffuse transmittance here rather than beam-beam to avoid
8428 : // complications due to specular reflection from multiple exterior surfaces
8429 :
8430 0 : TVisSunRefl = state.dataConstruction->Construct(IConst).TransDiffVis * state.dataSurface->SurfWinGlazedFrac(IWin) *
8431 0 : state.dataSurface->SurfWinLightWellEff(IWin);
8432 : // In the following it is assumed that all reflected beam is going downward, as it would be in the
8433 : // important case of reflection from a highly glazed facade of a neighboring building. However, in
8434 : // rare cases (such as upward specular reflection from a flat horizontal skylight) it may
8435 : // actually be going upward.
8436 0 : FLFWSUdisk(1) += ZSU1refl * TVisSunRefl;
8437 :
8438 : // -- Window with shade, blind or diffusing glass
8439 :
8440 0 : if (ShadeOn || BlindOn || ScreenOn || state.dataSurface->SurfWinSolarDiffusing(IWin)) {
8441 0 : DayltgInterReflectedIllumTransBmBmMult = 0.0;
8442 0 : TransMult = 0.0;
8443 :
8444 0 : for (JB = 1; JB <= MaxSlatAngs; ++JB) {
8445 0 : if (!state.dataSurface->SurfWinMovableSlats(IWin) && JB > 1) break;
8446 :
8447 0 : if (ShadeOn || state.dataSurface->SurfWinSolarDiffusing(IWin)) { // Shade on or diffusing glass
8448 0 : int IConstShaded = state.dataSurface->SurfWinActiveShadedConstruction(IWin);
8449 0 : if (state.dataSurface->SurfWinSolarDiffusing(IWin)) IConstShaded = state.dataSurface->Surface(IWin).Construction;
8450 0 : TransMult(1) = state.dataConstruction->Construct(IConstShaded).TransDiffVis * state.dataSurface->SurfWinGlazedFrac(IWin) *
8451 0 : state.dataSurface->SurfWinLightWellEff(IWin);
8452 :
8453 0 : } else if (ScreenOn) { // Exterior screen on
8454 0 : TransScDiffDiffFront = state.dataHeatBal->SurfaceScreens(state.dataSurface->SurfWinScreenNumber(IWin)).DifDifTransVis;
8455 0 : TransMult(1) = TransScDiffDiffFront *
8456 0 : (state.dataConstruction->Construct(IConst).TransDiffVis / (1.0 - ReflGlDiffDiffFront * ReflScDiffDiffBack)) *
8457 0 : state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
8458 :
8459 : } else { // Blind on
8460 0 : TransBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffTrans(JB);
8461 0 : if (ShType == WinShadingType::IntBlind) { // Interior blind
8462 0 : ReflBlDiffDiffFront = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffRefl(JB);
8463 0 : TransMult(JB) = TVisSunRefl * (TransBlDiffDiffFront + ReflBlDiffDiffFront * ReflGlDiffDiffBack * TransBlDiffDiffFront /
8464 0 : (1.0 - ReflBlDiffDiffFront * ReflGlDiffDiffBack));
8465 :
8466 0 : } else if (ShType == WinShadingType::ExtBlind) { // Exterior blind
8467 0 : TransMult(JB) = TransBlDiffDiffFront *
8468 0 : (state.dataConstruction->Construct(IConst).TransDiffVis /
8469 0 : (1.0 - ReflGlDiffDiffFront * state.dataHeatBal->Blind(BlNum).VisBackDiffDiffRefl(JB))) *
8470 0 : state.dataSurface->SurfWinGlazedFrac(IWin) * state.dataSurface->SurfWinLightWellEff(IWin);
8471 :
8472 : } else { // Between-glass blind
8473 0 : t1 = state.dataConstruction->Construct(IConst).tBareVisDiff(1);
8474 0 : tfshBd = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffTrans(JB);
8475 0 : rfshB = state.dataHeatBal->Blind(BlNum).VisFrontDiffDiffRefl(JB);
8476 0 : if (state.dataConstruction->Construct(IConst).TotGlassLayers == 2) { // 2 glass layers
8477 0 : TransMult(JB) =
8478 0 : t1 * (tfshBd * (1.0 + rfd2 * rbshd) + rfshB * rbd1 * tfshd) * td2 * state.dataSurface->SurfWinLightWellEff(IWin);
8479 : } else { // 3 glass layers; blind between layers 2 and 3
8480 0 : t2 = state.dataConstruction->Construct(IConst).tBareVisDiff(2);
8481 0 : TransMult(JB) = t1 * t2 * (tfshBd * (1.0 + rfd3 * rbshd) + rfshB * (rbd2 * tfshd + td2 * rbd1 * td2 * tfshd)) * td3 *
8482 0 : state.dataSurface->SurfWinLightWellEff(IWin);
8483 : }
8484 : } // End of check of interior/exterior/between-glass blind
8485 : } // ShadeOn/BlindOn
8486 :
8487 0 : state.dataDaylightingManager->WLUMSU(IHR, JB + 1) += ZSU1refl * TransMult(JB) / DataGlobalConstants::Pi;
8488 0 : FLFWSU(JB + 1) += ZSU1refl * TransMult(JB) * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
8489 0 : FLCWSU(JB + 1) += ZSU1refl * TransMult(JB) * state.dataSurface->SurfWinFractionUpgoing(IWin);
8490 : } // End of loop over slat angles
8491 : } // End of check if window has shade, blind or diffusing glass
8492 : } // End of check if ZSU1refl > 0.0
8493 : } // End of check if solar reflections are in effect
8494 :
8495 : // Sun-related portion of internally reflected illuminance
8496 :
8497 959448 : for (JSH = 1; JSH <= MaxSlatAngs + 1; ++JSH) {
8498 959448 : if (!state.dataSurface->SurfWinMovableSlats(IWin) && JSH > 2) break;
8499 :
8500 : // Full area of window is used in following since effect of dividers on reducing
8501 : // effective window transmittance already accounted for in calc of FLFWSU and FLCWSU
8502 : // CR 7869 added effect of intervening interior windows on transmittance and
8503 : // added inside surface area of adjacent zone
8504 639632 : state.dataDaylightingManager->EINTSU(IHR, JSH) =
8505 1279264 : (FLFWSU(JSH) * state.dataSurface->SurfWinRhoFloorWall(IWin) + FLCWSU(JSH) * state.dataSurface->SurfWinRhoCeilingWall(IWin)) *
8506 1279264 : (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
8507 639632 : (EnclInsideSurfArea * (1.0 - thisEnclDaylight.aveVisDiffReflect));
8508 :
8509 1918896 : state.dataDaylightingManager->EINTSUdisk(IHR, JSH) = FLFWSUdisk(JSH) * state.dataSurface->SurfWinRhoFloorWall(IWin) *
8510 1279264 : (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
8511 639632 : (EnclInsideSurfArea * (1.0 - thisEnclDaylight.aveVisDiffReflect));
8512 : }
8513 319816 : }
8514 :
8515 1674 : void ComplexFenestrationLuminances(EnergyPlusData &state,
8516 : int const IWin,
8517 : int const WinEl,
8518 : int const NBasis,
8519 : int const IHR,
8520 : int const iRefPoint,
8521 : Array2<Real64> &ElementLuminanceSky, // sky related luminance at window element (exterior side)
8522 : Array1D<Real64> &ElementLuminanceSun, // sun related luminance at window element (exterior side),
8523 : Array1D<Real64> &ElementLuminanceSunDisk, // sun related luminance at window element (exterior side),
8524 : DataDaylighting::CalledFor const CalledFrom,
8525 : int const MapNum)
8526 : {
8527 :
8528 : // SUBROUTINE INFORMATION:
8529 : // AUTHOR Simon Vidanovic
8530 : // DATE WRITTEN June 2013
8531 : // MODIFIED na
8532 : // RE-ENGINEERED na
8533 :
8534 : int iIncElem;
8535 : int iSky;
8536 : int SolBmIndex;
8537 : Real64 LambdaInc;
8538 : Real64 Altitude;
8539 : Real64 Azimuth;
8540 : int CurCplxFenState;
8541 : Real64 SunObstrMultiplier; // sun obstruction multiplier used to determine if sun hit the ground point
8542 : Real64 ObstrTrans; // product of all surface transmittances intersecting incoming beam
8543 :
8544 : Real64 BeamObstrMultiplier; // beam obstruction multiplier in case incoming beam is from the ground
8545 : bool hitObs; // True iff obstruction is hit
8546 : auto &ComplexFenestrationLuminancesObsHitPt =
8547 1674 : state.dataDaylightingManager->ComplexFenestrationLuminancesObsHitPt; // Coordinates of hit point on an obstruction (m)
8548 : auto &ComplexFenestrationLuminancesGroundHitPt =
8549 : state.dataDaylightingManager
8550 1674 : ->ComplexFenestrationLuminancesGroundHitPt; // Coordinates of point that ray from window center hits the ground (m)
8551 :
8552 : int NRefl; // number of exterior obstructions
8553 : int iReflElem; // incoming direction blocking surfaces element counter
8554 : int iReflElemIndex; // reflection element index
8555 :
8556 : int NGnd; // number of ground elements
8557 : int iGndElem; // ground elements counter
8558 : int iGndElemIndex; // ground element index
8559 :
8560 1674 : CurCplxFenState = state.dataSurface->SurfaceWindow(IWin).ComplexFen.CurrentState;
8561 :
8562 : // Calculate luminance from sky and sun excluding exterior obstruction transmittances and obstruction multipliers
8563 1674 : SolBmIndex = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).SolBmIndex(IHR, state.dataGlobal->TimeStep);
8564 244404 : for (iIncElem = 1; iIncElem <= NBasis; ++iIncElem) {
8565 242730 : LambdaInc = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).Inc.Lamda(iIncElem);
8566 : // COSB = ComplexWind(IWin)%Geom(CurCplxFenState)%CosInc(iIncElem)
8567 : // DA = ComplexWind(IWin)%Geom(CurCplxFenState)%DAInc(iIncElem)
8568 242730 : Altitude = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).pInc(iIncElem).Altitude;
8569 242730 : Azimuth = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).pInc(iIncElem).Azimuth;
8570 242730 : if (Altitude > 0.0) {
8571 : // Ray from sky element
8572 535680 : for (iSky = 1; iSky <= 4; ++iSky) {
8573 428544 : ElementLuminanceSky(iSky, iIncElem) = DayltgSkyLuminance(state, iSky, Azimuth, Altitude) * LambdaInc;
8574 : }
8575 135594 : } else if (Altitude < 0.0) {
8576 : // Ray from ground element
8577 : // BeamObstrMultiplier = ComplexWind(IWin)%DaylghtGeom(CurCplxFenState)%GndObstrMultiplier(WinEl, iIncElem)
8578 535680 : for (iSky = 1; iSky <= 4; ++iSky) {
8579 428544 : ElementLuminanceSky(iSky, iIncElem) =
8580 428544 : state.dataDaylightingManager->GILSK(IHR, iSky) * state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi * LambdaInc;
8581 : }
8582 107136 : ElementLuminanceSun(iIncElem) =
8583 107136 : state.dataDaylightingManager->GILSU(IHR) * state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi * LambdaInc;
8584 : } else {
8585 : // Ray from the element which is half sky and half ground
8586 142290 : for (iSky = 1; iSky <= 4; ++iSky) {
8587 : // in this case half of the pach is coming from the sky and half from the ground
8588 113832 : ElementLuminanceSky(iSky, iIncElem) = 0.5 * DayltgSkyLuminance(state, iSky, Azimuth, Altitude) * LambdaInc;
8589 341496 : ElementLuminanceSky(iSky, iIncElem) += 0.5 * state.dataDaylightingManager->GILSK(IHR, iSky) *
8590 227664 : state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi * LambdaInc;
8591 : }
8592 28458 : ElementLuminanceSun(iIncElem) =
8593 28458 : 0.5 * state.dataDaylightingManager->GILSU(IHR) * state.dataEnvrn->GndReflectanceForDayltg / DataGlobalConstants::Pi * LambdaInc;
8594 : }
8595 : // Sun beam calculations
8596 242730 : if ((SolBmIndex == iIncElem) && (state.dataHeatBal->SurfSunlitFracHR(IHR, IWin) > 0.0)) {
8597 1008 : ElementLuminanceSunDisk(iIncElem) = 1.0;
8598 : }
8599 : }
8600 :
8601 : // add exterior obstructions transmittances to calculated luminances
8602 1674 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
8603 1674 : NRefl = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).NReflSurf(WinEl);
8604 : } else {
8605 0 : assert(MapNum > 0);
8606 0 : NRefl = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).NReflSurf(WinEl);
8607 : }
8608 1674 : for (iReflElem = 1; iReflElem <= NRefl; ++iReflElem) {
8609 0 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
8610 0 : ObstrTrans = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).TransOutSurf(iReflElem, WinEl);
8611 0 : iReflElemIndex = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).RefSurfIndex(iReflElem, WinEl);
8612 : } else {
8613 0 : ObstrTrans =
8614 0 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).TransOutSurf(iReflElem, WinEl);
8615 0 : iReflElemIndex =
8616 0 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).RefSurfIndex(iReflElem, WinEl);
8617 : }
8618 :
8619 0 : for (iSky = 1; iSky <= 4; ++iSky) {
8620 0 : ElementLuminanceSky(iSky, iReflElemIndex) *= ObstrTrans;
8621 : }
8622 0 : ElementLuminanceSun(iReflElemIndex) *= ObstrTrans;
8623 0 : ElementLuminanceSunDisk(iReflElemIndex) *= ObstrTrans;
8624 : }
8625 :
8626 : // add exterior ground element obstruction multipliers to calculated luminances. For sun reflection, calculate if
8627 : // sun reaches the ground for that point
8628 1674 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
8629 1674 : NGnd = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).NGnd(WinEl);
8630 : } else {
8631 0 : NGnd = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).NGnd(WinEl);
8632 : }
8633 3348 : Vector3<Real64> const SUNCOS_IHR(state.dataSurface->SurfSunCosHourly(IHR));
8634 108810 : for (iGndElem = 1; iGndElem <= NGnd; ++iGndElem) {
8635 : // case for sky elements. Integration is done over upper ground hemisphere to determine how many obstructions
8636 : // were hit in the process
8637 107136 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
8638 107136 : BeamObstrMultiplier =
8639 107136 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).GndObstrMultiplier(iGndElem, WinEl);
8640 107136 : iGndElemIndex = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).GndIndex(iGndElem, WinEl);
8641 : } else {
8642 0 : BeamObstrMultiplier = state.dataBSDFWindow->ComplexWind(IWin)
8643 0 : .DaylghtGeom(CurCplxFenState)
8644 0 : .IlluminanceMap(iRefPoint, MapNum)
8645 0 : .GndObstrMultiplier(iGndElem, WinEl);
8646 0 : iGndElemIndex =
8647 0 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).GndIndex(iGndElem, WinEl);
8648 : }
8649 535680 : for (iSky = 1; iSky <= 4; ++iSky) {
8650 428544 : ElementLuminanceSky(iSky, iGndElemIndex) *= BeamObstrMultiplier;
8651 : }
8652 :
8653 : // direct sun disk reflect off the ground
8654 107136 : SunObstrMultiplier = 1.0;
8655 107136 : if (state.dataSurface->CalcSolRefl) {
8656 : // Sun reaches ground point if vector from this point to the sun is unobstructed
8657 107136 : hitObs = false;
8658 204042 : for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
8659 107136 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
8660 107136 : ComplexFenestrationLuminancesGroundHitPt(1) =
8661 107136 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).GndPt(iGndElem, WinEl).x;
8662 107136 : ComplexFenestrationLuminancesGroundHitPt(2) =
8663 107136 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).GndPt(iGndElem, WinEl).y;
8664 107136 : ComplexFenestrationLuminancesGroundHitPt(3) =
8665 107136 : state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).GndPt(iGndElem, WinEl).z;
8666 : } else {
8667 0 : ComplexFenestrationLuminancesGroundHitPt(1) = state.dataBSDFWindow->ComplexWind(IWin)
8668 0 : .DaylghtGeom(CurCplxFenState)
8669 0 : .IlluminanceMap(iRefPoint, MapNum)
8670 0 : .GndPt(iGndElem, WinEl)
8671 0 : .x;
8672 0 : ComplexFenestrationLuminancesGroundHitPt(2) = state.dataBSDFWindow->ComplexWind(IWin)
8673 0 : .DaylghtGeom(CurCplxFenState)
8674 0 : .IlluminanceMap(iRefPoint, MapNum)
8675 0 : .GndPt(iGndElem, WinEl)
8676 0 : .y;
8677 0 : ComplexFenestrationLuminancesGroundHitPt(3) = state.dataBSDFWindow->ComplexWind(IWin)
8678 0 : .DaylghtGeom(CurCplxFenState)
8679 0 : .IlluminanceMap(iRefPoint, MapNum)
8680 0 : .GndPt(iGndElem, WinEl)
8681 0 : .z;
8682 : }
8683 :
8684 : PierceSurface(state, ObsSurfNum, ComplexFenestrationLuminancesGroundHitPt, SUNCOS_IHR, ComplexFenestrationLuminancesObsHitPt, hitObs);
8685 107136 : if (hitObs) break;
8686 : }
8687 107136 : if (hitObs) SunObstrMultiplier = 0.0;
8688 : }
8689 107136 : ElementLuminanceSun(iGndElemIndex) *= SunObstrMultiplier;
8690 : }
8691 1674 : }
8692 :
8693 186 : void DayltgInterReflectedIllumComplexFenestration(EnergyPlusData &state,
8694 : int const IWin, // Window index
8695 : int const WinEl, // Current window element counter
8696 : int const IHR, // Hour of day
8697 : int const daylightCtrlNum, // Daylighting control number
8698 : int const iRefPoint, // reference point counter
8699 : DataDaylighting::CalledFor const CalledFrom,
8700 : int const MapNum)
8701 : {
8702 :
8703 : // SUBROUTINE INFORMATION:
8704 : // AUTHOR Simon Vidanovic
8705 : // DATE WRITTEN April 2013
8706 : // MODIFIED na
8707 : // RE-ENGINEERED na
8708 :
8709 : // PURPOSE OF THIS SUBROUTINE:
8710 : // Called from CalcDayltgCoefficients for each complex (bsdf) fenestration and reference point in a daylit
8711 : // space, for each sun position. Calculates illuminance (EINTSK and EINTSU) at reference point due
8712 : // to internally reflected light by integrating to determine the amount of flux from
8713 : // sky and ground (and beam reflected from obstructions) transmitted through
8714 : // the center of the window and then reflecting this
8715 : // light from the inside surfaces of the space.
8716 :
8717 372 : Array2D<Real64> FLSK; // Sky related luminous flux
8718 372 : Array1D<Real64> FLSU; // Sun related luminous flux, excluding entering beam
8719 372 : Array1D<Real64> FLSUdisk; // Sun related luminous flux, due to entering beam
8720 :
8721 372 : Array2D<Real64> FirstFluxSK; // Sky related first reflected flux
8722 372 : Array1D<Real64> FirstFluxSU; // Sun related first reflected flux, excluding entering beam
8723 372 : Array1D<Real64> FirstFluxSUdisk; // Sun related first reflected flux, due to entering beam
8724 :
8725 372 : Array2D<Real64> ElementLuminanceSky; // sky related luminance at window element (exterior side)
8726 372 : Array1D<Real64> ElementLuminanceSun; // sun related luminance at window element (exterior side), exluding beam
8727 372 : Array1D<Real64> ElementLuminanceSunDisk; // sun related luminance at window element (exterior side), due to sun beam
8728 : Real64 FLSUTot;
8729 : Real64 FLSUdiskTot;
8730 :
8731 : // Total for first relflected fluxes
8732 186 : auto &FFSKTot = state.dataDaylightingManager->FFSKTot;
8733 : Real64 FFSUTot;
8734 : Real64 FFSUdiskTot;
8735 :
8736 : Real64 COSIncSun; // cosine of sun incidence angle (from basis elements)
8737 :
8738 : int iSky; // Sky type index: 1=clear, 2=clear turbid, 3=intermediate, 4=overcast
8739 : int iConst; // Construction number
8740 :
8741 : int CurCplxFenState;
8742 : int NIncBasis;
8743 : int NTrnBasis;
8744 : int SolBmIndex; // index of current sun position
8745 :
8746 : int iIncElem; // incoming direction counter
8747 : int iBackElem; // outgoing direction counter
8748 :
8749 : Real64 LambdaInc; // current lambda value for incoming direction
8750 : // REAL(r64) :: LambdaTrn ! current lambda value for incoming direction
8751 : Real64 dirTrans; // directional bsdf transmittance
8752 :
8753 186 : CurCplxFenState = state.dataSurface->SurfaceWindow(IWin).ComplexFen.CurrentState;
8754 186 : iConst = state.dataSurface->SurfaceWindow(IWin).ComplexFen.State(CurCplxFenState).Konst;
8755 186 : NTrnBasis = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).Trn.NBasis;
8756 :
8757 186 : if (!allocated(FLSK)) FLSK.allocate(4, NTrnBasis);
8758 186 : FLSK = 0.0;
8759 186 : if (!allocated(FLSU)) FLSU.dimension(NTrnBasis, 0.0);
8760 186 : if (!allocated(FLSUdisk)) FLSUdisk.dimension(NTrnBasis, 0.0);
8761 :
8762 186 : if (!allocated(FirstFluxSK)) FirstFluxSK.allocate(4, NTrnBasis);
8763 186 : FirstFluxSK = 0.0;
8764 186 : if (!allocated(FirstFluxSU)) FirstFluxSU.dimension(NTrnBasis, 0.0);
8765 186 : if (!allocated(FirstFluxSUdisk)) FirstFluxSUdisk.dimension(NTrnBasis, 0.0);
8766 :
8767 186 : NIncBasis = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).Inc.NBasis;
8768 186 : if (!allocated(ElementLuminanceSky)) ElementLuminanceSky.allocate(4, NIncBasis);
8769 186 : ElementLuminanceSky = 0.0;
8770 186 : if (!allocated(ElementLuminanceSun)) ElementLuminanceSun.dimension(NIncBasis, 0.0);
8771 186 : if (!allocated(ElementLuminanceSunDisk)) ElementLuminanceSunDisk.dimension(NIncBasis, 0.0);
8772 :
8773 : // Integration over sky/ground/sun elements is done over window incoming basis element and flux is calculated for each
8774 : // outgoing direction. This is used to calculate first reflected flux
8775 :
8776 186 : ComplexFenestrationLuminances(
8777 : state, IWin, WinEl, NIncBasis, IHR, iRefPoint, ElementLuminanceSky, ElementLuminanceSun, ElementLuminanceSunDisk, CalledFrom, MapNum);
8778 :
8779 : // luminance from sun disk needs to include fraction of sunlit area
8780 186 : SolBmIndex = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).SolBmIndex(IHR, state.dataGlobal->TimeStep);
8781 186 : if (SolBmIndex > 0) {
8782 122 : COSIncSun = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).CosInc(SolBmIndex);
8783 : } else {
8784 64 : COSIncSun = 0.0;
8785 : }
8786 186 : ElementLuminanceSunDisk *= state.dataHeatBal->SurfSunlitFracHR(IHR, IWin) * COSIncSun;
8787 :
8788 : // FLSKTot = 0.0;
8789 186 : FLSUTot = 0.0;
8790 186 : FLSUdiskTot = 0.0;
8791 186 : FFSKTot = 0.0;
8792 186 : FFSUTot = 0.0;
8793 186 : FFSUdiskTot = 0.0;
8794 : // now calculate flux into each outgoing direction by integrating over all incoming directions
8795 27156 : for (iBackElem = 1; iBackElem <= NTrnBasis; ++iBackElem) {
8796 3937620 : for (iIncElem = 1; iIncElem <= NIncBasis; ++iIncElem) {
8797 3910650 : LambdaInc = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).Inc.Lamda(iIncElem);
8798 3910650 : dirTrans = state.dataConstruction->Construct(iConst).BSDFInput.VisFrtTrans(iBackElem, iIncElem);
8799 :
8800 19553250 : for (iSky = 1; iSky <= 4; ++iSky) {
8801 15642600 : FLSK(iSky, iBackElem) += dirTrans * LambdaInc * ElementLuminanceSky(iSky, iIncElem);
8802 : }
8803 :
8804 3910650 : FLSU(iBackElem) += dirTrans * LambdaInc * ElementLuminanceSun(iIncElem);
8805 3910650 : FLSUdisk(iBackElem) += dirTrans * LambdaInc * ElementLuminanceSunDisk(iIncElem);
8806 : }
8807 :
8808 134850 : for (iSky = 1; iSky <= 4; ++iSky) {
8809 107880 : FirstFluxSK(iSky, iBackElem) =
8810 107880 : FLSK(iSky, iBackElem) * state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).AveRhoVisOverlap(iBackElem);
8811 107880 : FFSKTot(iSky) += FirstFluxSK(iSky, iBackElem);
8812 : // FLSKTot( iSky ) += FLSK( iSky, iBackElem );
8813 : }
8814 26970 : FirstFluxSU(iBackElem) = FLSU(iBackElem) * state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).AveRhoVisOverlap(iBackElem);
8815 26970 : FFSUTot += FirstFluxSU(iBackElem);
8816 26970 : FLSUTot += FLSU(iBackElem);
8817 :
8818 26970 : FirstFluxSUdisk(iBackElem) = FLSUdisk(iBackElem) * state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).AveRhoVisOverlap(iBackElem);
8819 26970 : FFSUdiskTot += FirstFluxSUdisk(iBackElem);
8820 26970 : FLSUdiskTot += FLSUdisk(iBackElem);
8821 : }
8822 :
8823 186 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(state.dataDaylightingData->daylightControl(daylightCtrlNum).enclIndex);
8824 186 : Real64 EnclInsideSurfArea = thisEnclDaylight.totInsSurfArea;
8825 930 : for (iSky = 1; iSky <= 4; ++iSky) {
8826 2232 : state.dataDaylightingManager->EINTSK(IHR, 1, iSky) = FFSKTot(iSky) *
8827 1488 : (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
8828 744 : (EnclInsideSurfArea * (1.0 - thisEnclDaylight.aveVisDiffReflect));
8829 : }
8830 372 : state.dataDaylightingManager->EINTSU(IHR, 1) = FFSUTot * (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
8831 186 : (EnclInsideSurfArea * (1.0 - thisEnclDaylight.aveVisDiffReflect));
8832 372 : state.dataDaylightingManager->EINTSUdisk(IHR, 1) = FFSUdiskTot *
8833 372 : (state.dataSurface->Surface(IWin).Area / state.dataSurface->SurfWinGlazedFrac(IWin)) /
8834 186 : (EnclInsideSurfArea * (1.0 - thisEnclDaylight.aveVisDiffReflect));
8835 :
8836 186 : if (allocated(FLSK)) FLSK.deallocate();
8837 186 : if (allocated(FLSU)) FLSU.deallocate();
8838 186 : if (allocated(FLSUdisk)) FLSUdisk.deallocate();
8839 :
8840 186 : if (allocated(FirstFluxSK)) FirstFluxSK.deallocate();
8841 186 : if (allocated(FirstFluxSU)) FirstFluxSU.deallocate();
8842 186 : if (allocated(FirstFluxSUdisk)) FirstFluxSUdisk.deallocate();
8843 :
8844 186 : if (allocated(ElementLuminanceSky)) ElementLuminanceSky.deallocate();
8845 186 : if (allocated(ElementLuminanceSun)) ElementLuminanceSun.deallocate();
8846 186 : if (allocated(ElementLuminanceSunDisk)) ElementLuminanceSunDisk.deallocate();
8847 186 : }
8848 :
8849 1488 : void DayltgDirectIllumComplexFenestration(EnergyPlusData &state,
8850 : int const IWin, // Window index
8851 : int const WinEl, // Current window element counter
8852 : int const IHR, // Hour of day
8853 : int const iRefPoint, // reference point index
8854 : DataDaylighting::CalledFor const CalledFrom,
8855 : int const MapNum)
8856 : {
8857 :
8858 : // SUBROUTINE INFORMATION:
8859 : // AUTHOR Simon Vidanovic
8860 : // DATE WRITTEN June 2013
8861 : // MODIFIED na
8862 : // RE-ENGINEERED na
8863 :
8864 : // Luminances from different sources to the window
8865 2976 : Array2D<Real64> ElementLuminanceSky; // sky related luminance at window element (exterior side)
8866 2976 : Array1D<Real64> ElementLuminanceSun; // sun related luminance at window element (exterior side),
8867 : // exluding beam
8868 2976 : Array1D<Real64> ElementLuminanceSunDisk; // sun related luminance at window element (exterior side),
8869 : // due to sun beam
8870 :
8871 1488 : auto &WinLumSK = state.dataDaylightingManager->WinLumSK; // Sky related window luminance
8872 1488 : auto &EDirSky = state.dataDaylightingManager->EDirSky; // Sky related direct illuminance
8873 : Real64 WinLumSU; // Sun related window luminance, excluding entering beam
8874 : Real64 EDirSun; // Sun related direct illuminance, excluding entering beam
8875 : int CurCplxFenState;
8876 : int NIncBasis;
8877 : int RefPointIndex; // reference point patch number
8878 : int iIncElem;
8879 : int iConst;
8880 : int iSky;
8881 :
8882 : Real64 dirTrans; // directional BSDF transmittance
8883 : Real64 dOmega; // solid view angle of current element
8884 : Real64 zProjection; // z-axe projection of solid view angle (used to calculate amount of light at horizontal surface
8885 : // laying at reference point)
8886 :
8887 1488 : CurCplxFenState = state.dataSurface->SurfaceWindow(IWin).ComplexFen.CurrentState;
8888 1488 : iConst = state.dataSurface->SurfaceWindow(IWin).ComplexFen.State(CurCplxFenState).Konst;
8889 1488 : NIncBasis = state.dataBSDFWindow->ComplexWind(IWin).Geom(CurCplxFenState).Inc.NBasis;
8890 :
8891 1488 : if (!allocated(ElementLuminanceSky)) ElementLuminanceSky.allocate(4, NIncBasis);
8892 1488 : ElementLuminanceSky = 0.0;
8893 1488 : if (!allocated(ElementLuminanceSun)) ElementLuminanceSun.dimension(NIncBasis, 0.0);
8894 1488 : if (!allocated(ElementLuminanceSunDisk)) ElementLuminanceSunDisk.dimension(NIncBasis, 0.0);
8895 :
8896 1488 : ComplexFenestrationLuminances(
8897 : state, IWin, WinEl, NIncBasis, IHR, iRefPoint, ElementLuminanceSky, ElementLuminanceSun, ElementLuminanceSunDisk, CalledFrom, MapNum);
8898 :
8899 : // find number of outgoing basis towards current reference point
8900 1488 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
8901 1488 : RefPointIndex = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).RefPointIndex(WinEl);
8902 1488 : dOmega = state.dataBSDFWindow->ComplexWind(IWin).RefPoint(iRefPoint).SolidAngle(WinEl);
8903 1488 : zProjection = state.dataBSDFWindow->ComplexWind(IWin).RefPoint(iRefPoint).SolidAngleVec(WinEl).z;
8904 0 : } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
8905 0 : assert(MapNum > 0);
8906 0 : RefPointIndex = state.dataBSDFWindow->ComplexWind(IWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).RefPointIndex(WinEl);
8907 0 : dOmega = state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap(iRefPoint, MapNum).SolidAngle(WinEl);
8908 0 : zProjection = state.dataBSDFWindow->ComplexWind(IWin).IlluminanceMap(iRefPoint, MapNum).SolidAngleVec(WinEl).z;
8909 : }
8910 :
8911 1488 : WinLumSK = 0.0;
8912 1488 : WinLumSU = 0.0;
8913 : // WinLumSUdisk = 0.0d0
8914 1488 : EDirSky = 0.0;
8915 1488 : EDirSun = 0.0;
8916 : // EDirSunDisk = 0.0; //Unused Set but never used
8917 :
8918 217248 : for (iIncElem = 1; iIncElem <= NIncBasis; ++iIncElem) {
8919 : // LambdaInc = ComplexWind(IWin)%Geom(CurCplxFenState)%Inc%Lamda(iIncElem)
8920 215760 : dirTrans = state.dataConstruction->Construct(iConst).BSDFInput.VisFrtTrans(RefPointIndex, iIncElem);
8921 :
8922 1078800 : for (iSky = 1; iSky <= 4; ++iSky) {
8923 863040 : WinLumSK(iSky) += dirTrans * ElementLuminanceSky(iSky, iIncElem);
8924 : }
8925 :
8926 215760 : WinLumSU += dirTrans * ElementLuminanceSun(iIncElem);
8927 :
8928 : // For sun disk need to go throug outgoing directions and see which directions actually contain reference point
8929 : }
8930 :
8931 1488 : if (zProjection > 0.0) {
8932 5580 : for (iSky = 1; iSky <= 4; ++iSky) {
8933 4464 : EDirSky(iSky) = WinLumSK(iSky) * dOmega * zProjection;
8934 : }
8935 1116 : EDirSun = WinLumSU * dOmega * zProjection;
8936 : }
8937 :
8938 : // Store solution in global variables
8939 7440 : for (iSky = 1; iSky <= 4; ++iSky) {
8940 5952 : state.dataDaylightingManager->AVWLSK(IHR, 1, iSky) += WinLumSK(iSky);
8941 5952 : state.dataDaylightingManager->EDIRSK(IHR, 1, iSky) += EDirSky(iSky);
8942 : }
8943 :
8944 1488 : state.dataDaylightingManager->AVWLSU(IHR, 1) += WinLumSU;
8945 1488 : state.dataDaylightingManager->EDIRSU(IHR, 1) += EDirSun;
8946 : // AVWLSUdisk(1,IHR) = AVWLSUdisk(1,IHR) + WinLumSUdisk
8947 1488 : }
8948 :
8949 186 : void DayltgDirectSunDiskComplexFenestration(EnergyPlusData &state,
8950 : int const iWin, // Window index
8951 : int const iHour, // Hour of day
8952 : int const iRefPoint,
8953 : int const NumEl, // Total number of window elements
8954 : Real64 const AZVIEW, // Azimuth of view vector in absolute coord system for
8955 : DataDaylighting::CalledFor const CalledFrom, // indicate which type of routine called this routine
8956 : int const MapNum)
8957 : {
8958 :
8959 : // SUBROUTINE INFORMATION:
8960 : // AUTHOR Simon Vidanovic
8961 : // DATE WRITTEN June 2013
8962 : // MODIFIED na
8963 : // RE-ENGINEERED na
8964 :
8965 : // PURPOSE OF THIS SUBROUTINE:
8966 : // Calculate illuminance from sun disk for complex fenestration systems
8967 :
8968 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8969 : int CurCplxFenState;
8970 : int iConst;
8971 : int SolBmIndex;
8972 : int NTrnBasis;
8973 : int iTrnElem;
8974 186 : Real64 WindowSolidAngleDaylightPoint(0.0);
8975 : Real64 XR;
8976 : Real64 YR;
8977 : Real64 PosFac;
8978 : Real64 dirTrans;
8979 : Real64 LambdaTrn;
8980 : Real64 WinLumSunDisk; // window luminance from sun disk
8981 : Real64 ELumSunDisk; // window illuminance from sun disk
8982 : Real64 TransBeam; // transmittance of the beam for given direction
8983 186 : auto &DayltgDirectSunDiskComplexFenestrationV = state.dataDaylightingManager->DayltgDirectSunDiskComplexFenestrationV; // temporary vector
8984 186 : auto &DayltgDirectSunDiskComplexFenestrationRWin = state.dataDaylightingManager->DayltgDirectSunDiskComplexFenestrationRWin; // Window center
8985 : Real64 RayZ; // z component of unit vector for outgoing direction
8986 : bool refPointIntersect;
8987 :
8988 186 : CurCplxFenState = state.dataSurface->SurfaceWindow(iWin).ComplexFen.CurrentState;
8989 186 : iConst = state.dataSurface->SurfaceWindow(iWin).ComplexFen.State(CurCplxFenState).Konst;
8990 186 : SolBmIndex = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).SolBmIndex(iHour, state.dataGlobal->TimeStep);
8991 :
8992 186 : switch (CalledFrom) {
8993 186 : case DataDaylighting::CalledFor::RefPoint: {
8994 186 : WindowSolidAngleDaylightPoint = state.dataSurface->SurfaceWindow(iWin).SolidAngAtRefPtWtd(iRefPoint);
8995 186 : } break;
8996 0 : case DataDaylighting::CalledFor::MapPoint: {
8997 0 : WindowSolidAngleDaylightPoint = 0.0;
8998 0 : } break;
8999 0 : default: {
9000 0 : assert(false); // Bad CalledFrom argument
9001 : } break;
9002 : }
9003 :
9004 186 : if (WindowSolidAngleDaylightPoint < 1e-6) return;
9005 :
9006 0 : WinLumSunDisk = 0.0;
9007 0 : ELumSunDisk = 0.0;
9008 0 : NTrnBasis = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).Trn.NBasis;
9009 0 : for (iTrnElem = 1; iTrnElem <= NTrnBasis; ++iTrnElem) {
9010 : // if ray from any part of the window can reach reference point
9011 0 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
9012 0 : refPointIntersect =
9013 0 : state.dataBSDFWindow->ComplexWind(iWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).RefPointIntersection(iTrnElem);
9014 0 : } else if (CalledFrom == DataDaylighting::CalledFor::MapPoint) {
9015 0 : assert(MapNum > 0);
9016 0 : refPointIntersect =
9017 0 : state.dataBSDFWindow->ComplexWind(iWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).RefPointIntersection(iTrnElem);
9018 : }
9019 0 : if (refPointIntersect) {
9020 0 : if (CalledFrom == DataDaylighting::CalledFor::RefPoint) {
9021 0 : PosFac = state.dataBSDFWindow->ComplexWind(iWin).DaylghtGeom(CurCplxFenState).RefPoint(iRefPoint).RefPtIntPosFac(iTrnElem);
9022 : } else {
9023 0 : PosFac =
9024 0 : state.dataBSDFWindow->ComplexWind(iWin).DaylghtGeom(CurCplxFenState).IlluminanceMap(iRefPoint, MapNum).RefPtIntPosFac(iTrnElem);
9025 : }
9026 0 : RayZ = -state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).sTrn(iTrnElem).z;
9027 :
9028 : // Need to recalculate position factor for dominant direction in case of specular bsdf. Otherwise this will produce
9029 : // very inaccurate results because of position factor of the sun and bsdf pach can vary by lot
9030 0 : if (iTrnElem == SolBmIndex) {
9031 0 : XR = std::tan(std::abs(DataGlobalConstants::PiOvr2 - AZVIEW - state.dataDaylightingManager->THSUN) + 0.001);
9032 0 : YR = std::tan(state.dataDaylightingManager->PHSUN + 0.001);
9033 0 : PosFac = DayltgGlarePositionFactor(XR, YR);
9034 0 : RayZ = state.dataDaylightingManager->SPHSUN;
9035 : }
9036 :
9037 0 : if (PosFac != 0.0) {
9038 0 : if (SolBmIndex > 0) {
9039 0 : dirTrans = state.dataConstruction->Construct(iConst).BSDFInput.VisFrtTrans(iTrnElem, SolBmIndex);
9040 : } else {
9041 0 : dirTrans = 0.0;
9042 : }
9043 0 : LambdaTrn = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).Trn.Lamda(iTrnElem);
9044 :
9045 0 : DayltgDirectSunDiskComplexFenestrationV(1) = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).sTrn(iTrnElem).x;
9046 0 : DayltgDirectSunDiskComplexFenestrationV(2) = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).sTrn(iTrnElem).y;
9047 0 : DayltgDirectSunDiskComplexFenestrationV(3) = state.dataBSDFWindow->ComplexWind(iWin).Geom(CurCplxFenState).sTrn(iTrnElem).z;
9048 0 : DayltgDirectSunDiskComplexFenestrationV = -DayltgDirectSunDiskComplexFenestrationV;
9049 :
9050 0 : DayltgDirectSunDiskComplexFenestrationRWin(1) = state.dataSurface->Surface(iWin).Centroid.x;
9051 0 : DayltgDirectSunDiskComplexFenestrationRWin(2) = state.dataSurface->Surface(iWin).Centroid.y;
9052 0 : DayltgDirectSunDiskComplexFenestrationRWin(3) = state.dataSurface->Surface(iWin).Centroid.z;
9053 :
9054 0 : DayltgHitObstruction(
9055 : state, iHour, iWin, DayltgDirectSunDiskComplexFenestrationRWin, DayltgDirectSunDiskComplexFenestrationV, TransBeam);
9056 :
9057 0 : WinLumSunDisk += (14700.0 * std::sqrt(0.000068 * PosFac) * double(NumEl) / std::pow(WindowSolidAngleDaylightPoint, 0.8)) * dirTrans *
9058 0 : LambdaTrn * TransBeam;
9059 :
9060 0 : ELumSunDisk += RayZ * dirTrans * LambdaTrn * TransBeam;
9061 : }
9062 : }
9063 : }
9064 :
9065 0 : state.dataDaylightingManager->AVWLSUdisk(iHour, 1) = WinLumSunDisk;
9066 0 : state.dataDaylightingManager->EDIRSUdisk(iHour, 1) = ELumSunDisk;
9067 : }
9068 :
9069 249137524 : Real64 DayltgSkyLuminance(EnergyPlusData &state,
9070 : int const ISky, // Sky type: 1=clear, 2=clear turbid, 3=intermediate, 4=overcast
9071 : Real64 const THSKY, // Azimuth and altitude of sky element (radians)
9072 : Real64 const PHSKY)
9073 : {
9074 :
9075 : // SUBROUTINE INFORMATION:
9076 : // AUTHOR Fred Winkelmann
9077 : // DATE WRITTEN July 1997
9078 : // MODIFIED na
9079 : // RE-ENGINEERED na
9080 :
9081 : // PURPOSE OF THIS SUBROUTINE:
9082 : // Called by CalcDayltgCoefficients, DayltgExtHorizIllum AND DayltgInterReflectedIllum. gives
9083 : // luminance in cd/m2 for four different sky types, as described in R.Perez, P.Ineichen,
9084 : // R.Seals, J.Michalsky and R.Stewart, "Modeling daylight availability and irradiance
9085 : // components from direct and global irradiance," Solar Energy 44, 1990, 271-289.
9086 : // The luminance distributions in this routine are normalized such that
9087 : // the zenith luminance is 1.0, i.e., DayltgSkyLuminance =
9088 : // (sky luminance at THSKY, PHSKY)/(zenith luminance), which is dimensionless.
9089 : // The sky types are:
9090 : // 1. Standard CIE clear sky
9091 : // 2. Standard CIE high-turbidity clear sky
9092 : // 3. CIE intermediate sky
9093 : // 4. CIE overcast sky
9094 :
9095 : // METHODOLOGY EMPLOYED:
9096 :
9097 : // REFERENCES:
9098 : // Based on DOE-2.1E subroutine DSKYLU, which did only clear and overcast skies.
9099 :
9100 : // OTHER NOTES:
9101 : // THSKY ranges from 0 to 2Pi starting with 0 directly East and rotating clockwise.
9102 : // PHSKY ranges from 0 to Pi starting with 0 at the horizon and Pi/2 at the zenith.
9103 :
9104 : // USE STATEMENTS: na
9105 :
9106 : // Return value
9107 249137524 : Real64 DayltgSkyLuminance(0.0); // Luminance of sky element divided by zenith luminance
9108 :
9109 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
9110 : Real64 SPHSKY; // Sine of PHSKY
9111 249137524 : Real64 G(0.0); // Angle between sun and element of sky (radians)
9112 249137524 : Real64 COSG(0.0); // Cosine of G
9113 : Real64 Z; // Solar zenith angle (radians)
9114 : Real64 Z1; // Luminance factors (intermediate variables)
9115 : Real64 Z2;
9116 : Real64 Z3;
9117 : Real64 Z4;
9118 :
9119 249137524 : SPHSKY = max(std::sin(PHSKY), 0.01); // Prevent floating point underflows
9120 249137524 : Z = DataGlobalConstants::PiOvr2 - state.dataDaylightingManager->PHSUN;
9121 249137524 : if (ISky >= 1 && ISky <= 3) { // Following not needed for overcast sky
9122 373706286 : COSG = SPHSKY * state.dataDaylightingManager->SPHSUN +
9123 186853143 : std::cos(PHSKY) * state.dataDaylightingManager->CPHSUN * std::cos(THSKY - state.dataDaylightingManager->THSUN);
9124 186853143 : COSG = max(DataPrecisionGlobals::constant_minusone, min(COSG, 1.0)); // Prevent out of range due to roundoff
9125 186853143 : G = std::acos(COSG);
9126 : }
9127 :
9128 249137524 : if (ISky == 1) { // Clear Sky
9129 62284381 : Z1 = 0.910 + 10.0 * std::exp(-3.0 * G) + 0.45 * COSG * COSG;
9130 62284381 : Z2 = 1.0 - std::exp(-0.32 / SPHSKY);
9131 62284381 : Z3 = 0.27385 * (0.91 + 10.0 * std::exp(-3.0 * Z) + 0.45 * state.dataDaylightingManager->SPHSUN * state.dataDaylightingManager->SPHSUN);
9132 62284381 : DayltgSkyLuminance = Z1 * Z2 / Z3;
9133 :
9134 186853143 : } else if (ISky == 2) { // Clear turbid sky
9135 62284381 : Z1 = 0.856 + 16.0 * std::exp(-3.0 * G) + 0.3 * COSG * COSG;
9136 62284381 : Z2 = 1.0 - std::exp(-0.32 / SPHSKY);
9137 62284381 : Z3 = 0.27385 * (0.856 + 16.0 * std::exp(-3.0 * Z) + 0.3 * state.dataDaylightingManager->SPHSUN * state.dataDaylightingManager->SPHSUN);
9138 62284381 : DayltgSkyLuminance = Z1 * Z2 / Z3;
9139 :
9140 124568762 : } else if (ISky == 3) { // Intermediate sky
9141 62284381 : Z1 = (1.35 * (std::sin(3.59 * PHSKY - 0.009) + 2.31) * std::sin(2.6 * state.dataDaylightingManager->PHSUN + 0.316) + PHSKY + 4.799) / 2.326;
9142 62284381 : Z2 = std::exp(-G * 0.563 * ((state.dataDaylightingManager->PHSUN - 0.008) * (PHSKY + 1.059) + 0.812));
9143 62284381 : Z3 = 0.99224 * std::sin(2.6 * state.dataDaylightingManager->PHSUN + 0.316) + 2.73852;
9144 62284381 : Z4 = std::exp(-Z * 0.563 * ((state.dataDaylightingManager->PHSUN - 0.008) * 2.6298 + 0.812));
9145 62284381 : DayltgSkyLuminance = Z1 * Z2 / (Z3 * Z4);
9146 :
9147 62284381 : } else if (ISky == 4) { // Overcast sky
9148 62284381 : DayltgSkyLuminance = (1.0 + 2.0 * SPHSKY) / 3.0;
9149 : }
9150 :
9151 249137524 : return DayltgSkyLuminance;
9152 : }
9153 :
9154 28308 : void ProfileAngle(EnergyPlusData &state,
9155 : int const SurfNum, // Surface number
9156 : Vector3<Real64> const &CosDirSun, // Solar direction cosines
9157 : DataWindowEquivalentLayer::Orientation const HorOrVert, // If HORIZONTAL, calculates ProfileAngHor
9158 : Real64 &ProfileAng // Solar profile angle (radians).
9159 : )
9160 : {
9161 :
9162 : // SUBROUTINE INFORMATION:
9163 : // AUTHOR Fred Winkelmann
9164 : // DATE WRITTEN May 2001
9165 : // MODIFIED na
9166 : // RE-ENGINEERED na
9167 :
9168 : // PURPOSE OF THIS SUBROUTINE:
9169 : // Calculates profile angle for a surface.
9170 :
9171 : // Using/Aliasing
9172 : using namespace DataSurfaces;
9173 :
9174 : // Locals
9175 : // SUBROUTINE ARGUMENT DEFINITIONS:
9176 : // For HorOrVert = HORIZONTAL,
9177 : // this is the incidence angle in a plane that is normal to the window
9178 : // and parallel to the Y-axis of the window (the axis along
9179 : // which the height of the window is measured).
9180 : // For HorOrVert = VERTICAL,
9181 : // this is the incidence angle in a plane that is normal to the window
9182 : // and parallel to the X-axis of the window (the axis along
9183 : // which the width of the window is measured).
9184 : // If VERTICAL, calculates ProfileAngVert
9185 :
9186 : // SUBROUTINE PARAMETER DEFINITIONS: na
9187 : // INTERFACE BLOCK SPECIFICATIONS: na
9188 : // DERIVED TYPE DEFINITIONS: na
9189 :
9190 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9191 : Real64 ElevSun; // Sun elevation; angle between sun and horizontal (radians)
9192 : Real64 ElevWin; // Window elevation: angle between window outward normal and horizontal (radians)
9193 : Real64 AzimWin; // Window azimuth (radians)
9194 : Real64 AzimSun; // Sun azimuth (radians)
9195 : Real64 ThWin; // Azimuth angle of WinNorm
9196 28308 : auto &WinNorm = state.dataDaylightingManager->WinNorm; // Window outward normal unit vector
9197 28308 : auto &SunPrime = state.dataDaylightingManager->SunPrime; // Projection of sun vector onto plane (perpendicular to window plane) determined by
9198 : // WinNorm and vector along baseline of window
9199 28308 : auto &WinNormCrossBase = state.dataDaylightingManager->WinNormCrossBase; // Cross product of WinNorm and vector along window baseline
9200 :
9201 28308 : if (HorOrVert == DataWindowEquivalentLayer::Orientation::Horizontal) { // Profile angle for horizontal structures
9202 28308 : ElevWin = DataGlobalConstants::PiOvr2 - state.dataSurface->Surface(SurfNum).Tilt * DataGlobalConstants::DegToRadians;
9203 28308 : AzimWin = (90.0 - state.dataSurface->Surface(SurfNum).Azimuth) * DataGlobalConstants::DegToRadians;
9204 28308 : ElevSun = std::asin(CosDirSun(3));
9205 28308 : AzimSun = std::atan2(CosDirSun(2), CosDirSun(1));
9206 28308 : ProfileAng = std::atan(std::sin(ElevSun) / std::abs(std::cos(ElevSun) * std::cos(AzimWin - AzimSun))) - ElevWin;
9207 : } else { // Profile angle for vertical structures
9208 0 : ElevWin = DataGlobalConstants::PiOvr2 - state.dataSurface->Surface(SurfNum).Tilt * DataGlobalConstants::DegToRadians;
9209 0 : AzimWin = state.dataSurface->Surface(SurfNum).Azimuth * DataGlobalConstants::DegToRadians; // 7952
9210 0 : AzimSun = std::atan2(CosDirSun(1), CosDirSun(2)); // 7952
9211 0 : if (std::abs(ElevWin) < 0.1) { // Near-vertical window
9212 0 : ProfileAng = AzimWin - AzimSun; // CR7952 allow sign changes.
9213 : } else {
9214 0 : WinNorm = state.dataSurface->Surface(SurfNum).OutNormVec;
9215 0 : ThWin = AzimWin - DataGlobalConstants::PiOvr2;
9216 0 : Real64 const sin_ElevWin(std::sin(ElevWin));
9217 0 : WinNormCrossBase(1) = -sin_ElevWin * std::cos(ThWin);
9218 0 : WinNormCrossBase(2) = sin_ElevWin * std::sin(ThWin);
9219 0 : WinNormCrossBase(3) = std::cos(ElevWin);
9220 0 : SunPrime = CosDirSun - WinNormCrossBase * dot(CosDirSun, WinNormCrossBase);
9221 0 : ProfileAng = std::abs(std::acos(dot(WinNorm, SunPrime) / SunPrime.magnitude()));
9222 : // CR7952 correct sign of result for vertical slats
9223 0 : if ((AzimWin - AzimSun) < 0.0) ProfileAng = -1.0 * ProfileAng;
9224 : }
9225 : // Constrain to 0 to pi
9226 0 : if (ProfileAng > DataGlobalConstants::Pi) ProfileAng = 2.0 * DataGlobalConstants::Pi - ProfileAng;
9227 : }
9228 28308 : }
9229 :
9230 3840 : void DayltgClosestObstruction(EnergyPlusData &state,
9231 : Vector3<Real64> const &RecPt, // Point on window from which ray emanates (m)
9232 : Vector3<Real64> const &RayVec, // Unit vector along ray pointing away from window (m)
9233 : int &NearestHitSurfNum, // Surface number of nearest obstruction that is hit by ray;
9234 : Vector3<Real64> &NearestHitPt // Ray's hit point on nearest obstruction (m)
9235 : )
9236 : {
9237 :
9238 : // SUBROUTINE INFORMATION:
9239 : // AUTHOR Fred Winkelmann
9240 : // DATE WRITTEN November 2003
9241 : // MODIFIED na
9242 : // RE-ENGINEERED na
9243 :
9244 : // PURPOSE OF THIS SUBROUTINE:
9245 : // Determines surface number and hit point of closest exterior obstruction hit
9246 : // by a ray from a window. If no obstruction is hit, NearestHitSurfNum = 0.
9247 :
9248 : // Locals
9249 : // SUBROUTINE ARGUMENT DEFINITIONS:
9250 : // = 0 if no obstruction is hit.
9251 :
9252 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9253 3840 : auto &HitPt = state.dataDaylightingManager->HitPt; // Hit point on an obstruction (m)
9254 : bool hit; // True iff obstruction is hit
9255 :
9256 3840 : NearestHitSurfNum = 0;
9257 3840 : Real64 NearestHitDistance_sq(std::numeric_limits<Real64>::max()); // Distance squared from receiving point to nearest hit point for a ray (m^2)
9258 3840 : NearestHitPt = 0.0;
9259 3840 : if (state.dataSurface->TotSurfaces < octreeCrossover) { // Linear search through surfaces
9260 :
9261 19200 : for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
9262 : // Determine if this ray hits the surface and, if so, get the distance from the receiving point to the hit
9263 : PierceSurface(state, ObsSurfNum, RecPt, RayVec, HitPt, hit);
9264 15360 : if (hit) { // Ray pierces surface
9265 : // If obstruction is a window and its base surface is the nearest obstruction hit so far set nearestHitSurface to this window
9266 : // Note that in this case NearestHitDistance_sq has already been calculated, so does not have to be recalculated
9267 3840 : if ((state.dataSurface->Surface(ObsSurfNum).Class == SurfaceClass::Window) &&
9268 0 : (state.dataSurface->Surface(ObsSurfNum).BaseSurf == NearestHitSurfNum)) {
9269 0 : NearestHitSurfNum = ObsSurfNum;
9270 : } else {
9271 : // Distance squared from receiving point to hit point
9272 3840 : Real64 const HitDistance_sq(distance_squared(HitPt, RecPt));
9273 : // Reset NearestHitSurfNum and NearestHitDistance_sq if this hit point is closer than previous closest
9274 3840 : if (HitDistance_sq < NearestHitDistance_sq) {
9275 3840 : NearestHitDistance_sq = HitDistance_sq;
9276 3840 : NearestHitSurfNum = ObsSurfNum;
9277 3840 : NearestHitPt = HitPt;
9278 : }
9279 : }
9280 : } // End of check if obstruction was hit
9281 : } // End of loop over possible obstructions for this ray
9282 :
9283 : } else { // Surface octree search
9284 :
9285 0 : SurfaceData const *nearestHitSurface(nullptr);
9286 :
9287 : // Lambda function for the octree to test for surface hit
9288 0 : auto surfaceHit = [=, &state, &RecPt, &RayVec, &hit, &NearestHitDistance_sq, &nearestHitSurface, &NearestHitPt](SurfaceData const &surface) {
9289 0 : if (surface.IsShadowPossibleObstruction) {
9290 : // Determine if this ray hits the surface and, if so, get the distance from the receiving point to the hit
9291 0 : PierceSurface(surface, RecPt, RayVec, state.dataDaylightingManager->HitPt, hit); // Check if ray pierces surface
9292 0 : if (hit) { // Ray pierces surface
9293 : // If obstruction is a window and its base surface is the nearest obstruction hit so far set nearestHitSurface to this window
9294 : // Note that in this case NearestHitDistance_sq has already been calculated, so does not have to be recalculated
9295 0 : if ((surface.Class == SurfaceClass::Window) && (surface.BaseSurf > 0) &&
9296 0 : (&state.dataSurface->Surface(surface.BaseSurf) == nearestHitSurface)) {
9297 0 : nearestHitSurface = &surface;
9298 : } else {
9299 : // Distance squared from receiving point to hit point
9300 0 : Real64 const HitDistance_sq(distance_squared(HitPt, RecPt));
9301 : // Reset nearestHitSurface and NearestHitDistance_sq if this hit point is closer than previous closest
9302 0 : if (HitDistance_sq < NearestHitDistance_sq) {
9303 0 : NearestHitDistance_sq = HitDistance_sq;
9304 0 : nearestHitSurface = &surface;
9305 0 : NearestHitPt = HitPt;
9306 : }
9307 : }
9308 : } // End of check if obstruction was hit
9309 : }
9310 0 : };
9311 :
9312 : // Process octree surface candidates
9313 0 : Vector3<Real64> const RayVec_inv(SurfaceOctreeCube::safe_inverse(RayVec));
9314 0 : state.dataHeatBalMgr->surfaceOctree.processSurfaceRayIntersectsCube(RecPt, RayVec, RayVec_inv, surfaceHit);
9315 0 : if (nearestHitSurface != nullptr) { // Find surface number: This is inefficient: Improve when surfaces know their own number
9316 0 : for (int i = 1; i <= state.dataSurface->TotSurfaces; ++i) {
9317 0 : if (&state.dataSurface->Surface(i) == nearestHitSurface) {
9318 0 : NearestHitSurfNum = i;
9319 0 : break;
9320 : }
9321 : }
9322 0 : assert(NearestHitSurfNum != 0);
9323 : }
9324 : }
9325 3840 : }
9326 :
9327 3840 : void DayltgSurfaceLumFromSun(EnergyPlusData &state,
9328 : int const IHR, // Hour number
9329 : Vector3<Real64> const &Ray, // Ray from window to reflecting surface (m)
9330 : int const ReflSurfNum, // Number of surface for which luminance is being calculated
9331 : Vector3<Real64> const &ReflHitPt, // Point on ReflSurfNum for luminance calculation (m)
9332 : Real64 &LumAtReflHitPtFrSun // Luminance at ReflHitPt from beam solar reflection for unit
9333 : )
9334 : {
9335 :
9336 : // SUBROUTINE INFORMATION:
9337 : // AUTHOR Fred Winkelmann
9338 : // DATE WRITTEN November 2003
9339 : // MODIFIED na
9340 : // RE-ENGINEERED na
9341 :
9342 : // PURPOSE OF THIS SUBROUTINE:
9343 : // Calculates exterior surface luminance due to beam solar diffuse reflection.
9344 :
9345 : // Locals
9346 : // SUBROUTINE ARGUMENT DEFINITIONS:
9347 : // beam normal illuminance (cd/m2)
9348 :
9349 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9350 3840 : auto &DayltgSurfaceLumFromSunReflNorm = state.dataDaylightingManager->DayltgSurfaceLumFromSunReflNorm; // Unit normal to reflecting surface (m)
9351 3840 : auto &DayltgSurfaceLumFromSunObsHitPt = state.dataDaylightingManager->DayltgSurfaceLumFromSunObsHitPt; // Hit point on obstruction (m)
9352 : bool hitObs; // True iff obstruction is hit
9353 : Real64 CosIncAngAtHitPt; // Cosine of angle of incidence of sun at HitPt
9354 : Real64 DiffVisRefl; // Diffuse visible reflectance of ReflSurfNum
9355 :
9356 3840 : LumAtReflHitPtFrSun = 0.0;
9357 : // Skip daylighting shelves since reflection from these is separately calculated
9358 7680 : if (state.dataSurface->SurfDaylightingShelfInd(ReflSurfNum) > 0) return;
9359 : // Normal to reflecting surface in hemisphere containing window element
9360 3840 : DayltgSurfaceLumFromSunReflNorm = state.dataSurface->Surface(ReflSurfNum).OutNormVec;
9361 3840 : if (state.dataSurface->Surface(ReflSurfNum).IsShadowing) {
9362 3840 : if (dot(DayltgSurfaceLumFromSunReflNorm, Ray) > 0.0) {
9363 3840 : DayltgSurfaceLumFromSunReflNorm *= -1.0;
9364 : }
9365 : }
9366 : // Cosine of angle of incidence of sun at HitPt if sun were to reach HitPt
9367 3840 : Vector3<Real64> const SUNCOS_IHR(state.dataSurface->SurfSunCosHourly(IHR));
9368 3840 : CosIncAngAtHitPt = dot(DayltgSurfaceLumFromSunReflNorm, SUNCOS_IHR);
9369 : // Require that the sun be in front of this surface relative to window element
9370 3840 : if (CosIncAngAtHitPt <= 0.0) return; // Sun is in back of reflecting surface
9371 : // Sun reaches ReflHitPt if vector from ReflHitPt to sun is unobstructed
9372 0 : hitObs = false;
9373 0 : for (int ObsSurfNum : state.dataSurface->AllShadowPossObstrSurfaceList) {
9374 : // Exclude as a possible obstructor ReflSurfNum and its base surface (if it has one)
9375 0 : if (ObsSurfNum == ReflSurfNum || ObsSurfNum == state.dataSurface->Surface(ReflSurfNum).BaseSurf) continue;
9376 : PierceSurface(state, ObsSurfNum, ReflHitPt, SUNCOS_IHR, DayltgSurfaceLumFromSunObsHitPt, hitObs);
9377 0 : if (hitObs) break;
9378 : }
9379 0 : if (hitObs) return; // Obstruction was hit, blocking s auto surfaceHit = [&state, &GroundHitPtun
9380 : // Obstruction was not hit; sun reaches ReflHitPt.
9381 : // Calculate luminance at ReflHitPt due to beam solar reflection (for unit beam normal illuminance)
9382 0 : if (state.dataSurface->Surface(ReflSurfNum).IsShadowing) {
9383 0 : DiffVisRefl = state.dataSurface->SurfShadowDiffuseVisRefl(ReflSurfNum);
9384 : // Note that if the shadowing surface has a non-zero glazing fraction (e.g., neighboring bldg) that the above is
9385 : // (1 - glazing fraction) * (vis refl of opaque part of shadowing surface); specular reflection is
9386 : // excluded in this value of DiffVisRefl.
9387 : } else { // Exterior building surface
9388 0 : if (!state.dataConstruction->Construct(state.dataSurface->Surface(ReflSurfNum).Construction).TypeIsWindow) {
9389 0 : DiffVisRefl = 1.0 - state.dataConstruction->Construct(state.dataSurface->Surface(ReflSurfNum).Construction).OutsideAbsorpSolar;
9390 : } else {
9391 : // Window; assume bare so no beam-to-diffuse reflection
9392 0 : DiffVisRefl = 0.0;
9393 : }
9394 : }
9395 0 : LumAtReflHitPtFrSun = CosIncAngAtHitPt * DiffVisRefl / DataGlobalConstants::Pi;
9396 : }
9397 :
9398 894397 : void DayltgInteriorMapIllum(EnergyPlusData &state)
9399 : {
9400 :
9401 : // *****super modified version of DayltgInteriorIllum by Peter Graham Ellis
9402 : // *****removes all control code, just calculates illum with previously determined control settings
9403 : // *****this should be packaged into a subroutine called from 2 places
9404 :
9405 : // SUBROUTINE INFORMATION:
9406 : // AUTHOR Fred Winkelmann
9407 : // DATE WRITTEN July 1997
9408 : // MODIFIED March 2000, FW: interpolate clear-sky daylight factors using
9409 : // HourOfDay/WeightNow and NextHour/WeightNextHour. Previously
9410 : // only HourOfDay was used
9411 : // Jan 2001, FW: interpolate in slat angle for windows with blinds
9412 : // that have movable slats
9413 : // Dec 2003, FW: fix bug--even though between-glass shade/blind is on
9414 : // daylight illum at ref pt was calculated as though it was off
9415 : // June 2009, TH: modified for thermochromic windows
9416 : // March 2010, TH: fix bug (CR 8057) for electrochromic windows
9417 : // RE-ENGINEERED na
9418 :
9419 : // PURPOSE OF THIS SUBROUTINE:
9420 : // Using daylighting factors and exterior illuminance, determine
9421 : // the current-hour interior daylight illuminance and glare index
9422 : // at each reference point in a space.
9423 :
9424 : // Called by InitSurfaceHeatBalance.
9425 :
9426 : // REFERENCES:
9427 : // Based on DOE-2.1E subroutine DINTIL.
9428 :
9429 : // Using/Aliasing
9430 : using General::POLYF;
9431 :
9432 : // Locals
9433 894397 : auto &daylight_illum = state.dataDaylightingManager->daylight_illum;
9434 :
9435 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9436 : int NREFPT; // Number of daylighting map reference points
9437 : // INTEGER :: REFPT1 ! 1st reference point
9438 : int ISky; // Sky type index
9439 : int ISky1; // Sky type index values for averaging two sky types
9440 : int ISky2;
9441 894397 : auto &DFSUHR = state.dataDaylightingManager->DFSUHR; // Sun daylight factor for bare/shaded window
9442 894397 : auto &IConstShaded = state.dataDaylightingManager->IConstShaded;
9443 894397 : auto &VTDark = state.dataDaylightingManager->VTDark;
9444 894397 : auto &VTMULT = state.dataDaylightingManager->VTMULT;
9445 894397 : auto &DayltgInteriorMapIllumDFSUHR = state.dataDaylightingManager->DayltgInteriorMapIllumDFSUHR;
9446 894397 : auto &DayltgInteriorMapIllumHorIllSky = state.dataDaylightingManager->DayltgInteriorMapIllumHorIllSky;
9447 894397 : auto &DFSKHR = state.dataDaylightingManager->DayltgInteriorMapIllumDFSKHR;
9448 : int IL; // Reference point index
9449 : int IWin; // Window index
9450 : int IS; // IS=1 for unshaded window, =2 for shaded window
9451 : int ICtrl; // Window shading control pointer
9452 : Real64 SkyWeight; // Weighting factor used to average two different sky types
9453 : Real64 HorIllSkyFac; // Ratio between horizontal illuminance from sky horizontal irradiance and
9454 : // luminous efficacy and horizontal illuminance from averaged sky
9455 : int loop; // Window loop index
9456 : int ILB;
9457 : int IConst;
9458 : Real64 VTRatio;
9459 : Real64 VTNow;
9460 : Real64 VTMaster;
9461 :
9462 894397 : if (state.dataDaylightingManager->DayltgInteriorMapIllum_FirstTimeFlag) {
9463 769 : daylight_illum.allocate(DataDaylighting::MaxMapRefPoints);
9464 769 : state.dataDaylightingManager->DayltgInteriorMapIllum_FirstTimeFlag = false;
9465 : }
9466 :
9467 894397 : if (state.dataGlobal->WarmupFlag) return;
9468 :
9469 : // Initialize reference point illuminance and window background luminance
9470 :
9471 152428 : for (int mapNum = 1; mapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++mapNum) {
9472 1737 : auto &thisMap = state.dataDaylightingData->IllumMapCalc(mapNum);
9473 1737 : int enclNum = thisMap.enclIndex;
9474 1737 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
9475 :
9476 1737 : NREFPT = thisMap.TotalMapRefPoints;
9477 :
9478 1737 : daylight_illum = 0.0;
9479 :
9480 1737 : if (state.dataEnvrn->SkyClearness > 3.0) { // Sky is average of clear and clear turbid
9481 1321 : SkyWeight = min(1.0, (state.dataEnvrn->SkyClearness - 3.0) / 3.0);
9482 1321 : ISky1 = 1;
9483 1321 : ISky2 = 2;
9484 416 : } else if (state.dataEnvrn->SkyClearness > 1.2) { // Sky is average of clear turbid and intermediate
9485 180 : SkyWeight = (state.dataEnvrn->SkyClearness - 1.2) / 1.8;
9486 180 : ISky1 = 2;
9487 180 : ISky2 = 3;
9488 : } else { // Sky is average of intermediate and overcast
9489 236 : SkyWeight = min(1.0, max(0.0, (state.dataEnvrn->SkyClearness - 1.0) / 0.2, (state.dataEnvrn->SkyBrightness - 0.05) / 0.4));
9490 236 : ISky1 = 3;
9491 236 : ISky2 = 4;
9492 : }
9493 :
9494 : // First loop over windows in this space.
9495 : // Find contribution of each window to the daylight illum
9496 : // and to the glare numerator at each reference point.
9497 : // Use shading flags set in WindowShadingManager.
9498 :
9499 11857 : for (loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
9500 10120 : IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
9501 :
9502 : // Added TH 6/29/2009 for thermochromic windows
9503 10120 : VTRatio = 1.0;
9504 10120 : if (NREFPT > 0) {
9505 10120 : IConst = state.dataSurface->Surface(IWin).Construction;
9506 10120 : if (state.dataConstruction->Construct(IConst).TCFlag == 1) {
9507 : // For thermochromic windows, daylight and glare factors are always calculated
9508 : // based on the master construction. They need to be adjusted by the VTRatio, including:
9509 : // ZoneDaylight()%DaylIllFacSky, DaylIllFacSun, DaylIllFacSunDisk; DaylBackFacSky,
9510 : // DaylBackFacSun, DaylBackFacSunDisk, DaylSourceFacSky, DaylSourceFacSun, DaylSourceFacSunDisk
9511 0 : VTNow = POLYF(1.0, state.dataConstruction->Construct(IConst).TransVisBeamCoef);
9512 0 : VTMaster =
9513 0 : POLYF(1.0, state.dataConstruction->Construct(state.dataConstruction->Construct(IConst).TCMasterConst).TransVisBeamCoef);
9514 0 : VTRatio = VTNow / VTMaster;
9515 : }
9516 : }
9517 :
9518 : // Loop over reference points
9519 978620 : for (ILB = 1; ILB <= NREFPT; ++ILB) {
9520 :
9521 : // Daylight factors for current sun position
9522 4842500 : for (ISky = 1; ISky <= 4; ++ISky) {
9523 : // ===Bare window===
9524 3874000 : DFSKHR(1, ISky) =
9525 7748000 : VTRatio * (state.dataGlobal->WeightNow * thisMap.DaylIllFacSky(state.dataGlobal->HourOfDay, 1, ISky, ILB, loop) +
9526 3874000 : state.dataGlobal->WeightPreviousHour * thisMap.DaylIllFacSky(state.dataGlobal->PreviousHour, 1, ISky, ILB, loop));
9527 :
9528 3874000 : if (ISky == 1) {
9529 968500 : DayltgInteriorMapIllumDFSUHR(1) =
9530 968500 : VTRatio *
9531 1937000 : (state.dataGlobal->WeightNow * (thisMap.DaylIllFacSun(state.dataGlobal->HourOfDay, 1, ILB, loop) +
9532 1937000 : thisMap.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, 1, ILB, loop)) +
9533 1937000 : state.dataGlobal->WeightPreviousHour * (thisMap.DaylIllFacSun(state.dataGlobal->PreviousHour, 1, ILB, loop) +
9534 968500 : thisMap.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, 1, ILB, loop)));
9535 : }
9536 :
9537 11018400 : if ((state.dataSurface->SurfWinWindowModelType(IWin) != WindowModel::BSDF) &&
9538 4477600 : (IS_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) || state.dataSurface->SurfWinSolarDiffusing(IWin))) {
9539 :
9540 : // ===Shaded window===
9541 3270400 : if (!state.dataSurface->SurfWinMovableSlats(IWin)) {
9542 : // Shade, screen, blind with fixed slats, or diffusing glass
9543 3270400 : DFSKHR(2, ISky) =
9544 3270400 : VTRatio *
9545 6540800 : (state.dataGlobal->WeightNow * thisMap.DaylIllFacSky(state.dataGlobal->HourOfDay, 2, ISky, ILB, loop) +
9546 3270400 : state.dataGlobal->WeightPreviousHour * thisMap.DaylIllFacSky(state.dataGlobal->PreviousHour, 2, ISky, ILB, loop));
9547 :
9548 3270400 : if (ISky == 1) {
9549 817600 : DayltgInteriorMapIllumDFSUHR(2) =
9550 817600 : VTRatio *
9551 1635200 : (state.dataGlobal->WeightNow * thisMap.DaylIllFacSun(state.dataGlobal->HourOfDay, 2, ILB, loop) +
9552 817600 : state.dataGlobal->WeightPreviousHour * thisMap.DaylIllFacSun(state.dataGlobal->PreviousHour, 2, ILB, loop));
9553 :
9554 817600 : if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin)) {
9555 817600 : DayltgInteriorMapIllumDFSUHR(2) +=
9556 817600 : VTRatio *
9557 1635200 : (state.dataGlobal->WeightNow * thisMap.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, 2, ILB, loop) +
9558 1635200 : state.dataGlobal->WeightPreviousHour *
9559 817600 : thisMap.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, 2, ILB, loop));
9560 : }
9561 : }
9562 : } else { // Blind with movable slats
9563 0 : int SurfWinSlatsAngIndex = state.dataSurface->SurfWinSlatsAngIndex(IWin);
9564 0 : Real64 SurfWinSlatsAngInterpFac = state.dataSurface->SurfWinSlatsAngInterpFac(IWin);
9565 0 : Real64 DaylIllFacSkyNow = General::InterpGeneral(
9566 0 : thisMap.DaylIllFacSky(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ISky, ILB, loop),
9567 : thisMap.DaylIllFacSky(
9568 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, ILB, loop),
9569 0 : SurfWinSlatsAngInterpFac);
9570 0 : Real64 DaylIllFacSkyPrev = General::InterpGeneral(
9571 0 : thisMap.DaylIllFacSky(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ISky, ILB, loop),
9572 : thisMap.DaylIllFacSky(
9573 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ISky, ILB, loop),
9574 0 : SurfWinSlatsAngInterpFac);
9575 :
9576 0 : DFSKHR(2, ISky) =
9577 0 : VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSkyNow + state.dataGlobal->WeightPreviousHour * DaylIllFacSkyPrev);
9578 :
9579 0 : if (ISky == 1) {
9580 0 : Real64 DaylIllFacSunNow = General::InterpGeneral(
9581 0 : thisMap.DaylIllFacSun(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ILB, loop),
9582 : thisMap.DaylIllFacSun(
9583 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ILB, loop),
9584 0 : SurfWinSlatsAngInterpFac);
9585 0 : Real64 DaylIllFacSunPrev = General::InterpGeneral(
9586 0 : thisMap.DaylIllFacSun(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ILB, loop),
9587 : thisMap.DaylIllFacSun(
9588 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ILB, loop),
9589 0 : SurfWinSlatsAngInterpFac);
9590 0 : DFSUHR(2) = VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSunNow +
9591 0 : state.dataGlobal->WeightPreviousHour * DaylIllFacSunPrev);
9592 :
9593 : // We add the contribution from the solar disk if slats do not block beam solar
9594 : // TH CR 8010, DaylIllFacSunDisk needs to be interpolated
9595 0 : if (!state.dataSurface->SurfWinSlatsBlockBeam(IWin)) {
9596 0 : Real64 DaylIllFacSunDiskNow = General::InterpGeneral(
9597 0 : thisMap.DaylIllFacSunDisk(state.dataGlobal->HourOfDay, SurfWinSlatsAngIndex + 1, ILB, loop),
9598 : thisMap.DaylIllFacSunDisk(
9599 0 : state.dataGlobal->HourOfDay, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ILB, loop),
9600 0 : SurfWinSlatsAngInterpFac);
9601 0 : Real64 DaylIllFacSunDiskPrev = General::InterpGeneral(
9602 0 : thisMap.DaylIllFacSunDisk(state.dataGlobal->PreviousHour, SurfWinSlatsAngIndex + 1, ILB, loop),
9603 : thisMap.DaylIllFacSunDisk(
9604 0 : state.dataGlobal->PreviousHour, std::min(MaxSlatAngs + 1, SurfWinSlatsAngIndex + 2), ILB, loop),
9605 0 : SurfWinSlatsAngInterpFac);
9606 0 : DFSUHR(2) += VTRatio * (state.dataGlobal->WeightNow * DaylIllFacSunDiskNow +
9607 0 : state.dataGlobal->WeightPreviousHour * DaylIllFacSunDiskPrev);
9608 : }
9609 : }
9610 :
9611 : } // End of check if window has blind with movable slats
9612 :
9613 : } // End of check if window is shaded or has diffusing glass
9614 : }
9615 :
9616 : // Get illuminance at ref point from bare and shaded window by
9617 : // multiplying daylight factors by exterior horizontal illuminance
9618 :
9619 : // Adding 0.001 in the following prevents zero DayltgInteriorMapIllumHorIllSky in early morning or late evening when sun
9620 : // is up in the present time step but GILSK(ISky,HourOfDay) and GILSK(ISky,NextHour) are both zero.
9621 4842500 : for (ISky = 1; ISky <= 4; ++ISky) {
9622 3874000 : DayltgInteriorMapIllumHorIllSky(ISky) =
9623 7748000 : state.dataGlobal->WeightNow * state.dataDaylightingManager->GILSK(state.dataGlobal->HourOfDay, ISky) +
9624 7748000 : state.dataGlobal->WeightPreviousHour * state.dataDaylightingManager->GILSK(state.dataGlobal->PreviousHour, ISky) + 0.001;
9625 : }
9626 :
9627 : // HISKF is current time step horizontal illuminance from sky, calculated in DayltgLuminousEfficacy,
9628 : // which is called in WeatherManager. HISUNF is current time step horizontal illuminance from sun,
9629 : // also calculated in DayltgLuminousEfficacy.
9630 1937000 : HorIllSkyFac = state.dataEnvrn->HISKF /
9631 968500 : ((1.0 - SkyWeight) * DayltgInteriorMapIllumHorIllSky(ISky2) + SkyWeight * DayltgInteriorMapIllumHorIllSky(ISky1));
9632 :
9633 2754600 : for (IS = 1; IS <= 2; ++IS) {
9634 1937000 : if (IS == 2 && state.dataSurface->SurfWinWindowModelType(IWin) == WindowModel::BSDF) break;
9635 1937000 : if (IS == 2 && NOT_SHADED(state.dataSurface->SurfWinShadingFlag(IWin)) && !state.dataSurface->SurfWinSolarDiffusing(IWin)) break;
9636 :
9637 1786100 : thisMap.IllumFromWinAtMapPt(loop, IS, ILB) =
9638 3572200 : DayltgInteriorMapIllumDFSUHR(IS) * state.dataEnvrn->HISUNF +
9639 3572200 : HorIllSkyFac * (DFSKHR(IS, ISky1) * SkyWeight * DayltgInteriorMapIllumHorIllSky(ISky1) +
9640 1786100 : DFSKHR(IS, ISky2) * (1.0 - SkyWeight) * DayltgInteriorMapIllumHorIllSky(ISky2));
9641 : }
9642 :
9643 : } // End of reference point loop
9644 : } // End of first loop over windows
9645 :
9646 : // Second loop over windows. Find total daylight illuminance
9647 : // and background luminance for each ref pt from all windows in
9648 : // the space. Use shading flags.
9649 :
9650 11857 : for (loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
9651 10120 : IWin = thisEnclDaylight.DayltgExtWinSurfNums(loop);
9652 :
9653 10120 : IS = findWinShadingStatus(state, IWin);
9654 :
9655 : // CR 8057. 3/17/2010.
9656 : // Switchable windows may be in partially switched state rather than fully dark state
9657 10120 : VTMULT = 1.0;
9658 :
9659 10120 : ICtrl = state.dataSurface->Surface(IWin).activeWindowShadingControl;
9660 10120 : if (state.dataSurface->Surface(IWin).HasShadeControl) {
9661 8815 : if (state.dataSurface->WindowShadingControl(ICtrl).shadingControlType == WindowShadingControlType::MeetDaylIlumSetp &&
9662 0 : state.dataSurface->SurfWinShadingFlag(IWin) == WinShadingType::SwitchableGlazing) {
9663 : // switchable windows in partial or fully switched state,
9664 : // get its intermediate VT calculated in DayltgInteriorIllum
9665 0 : IConstShaded = state.dataSurface->Surface(IWin).activeShadedConstruction;
9666 0 : if (IConstShaded > 0)
9667 0 : VTDark =
9668 0 : POLYF(1.0, state.dataConstruction->Construct(IConstShaded).TransVisBeamCoef) * state.dataSurface->SurfWinGlazedFrac(IWin);
9669 0 : if (VTDark > 0) VTMULT = state.dataSurface->SurfWinVisTransSelected(IWin) / VTDark;
9670 : }
9671 : }
9672 :
9673 978620 : for (IL = 1; IL <= NREFPT; ++IL) {
9674 : // Determine if illuminance contribution is from bare or shaded window
9675 968500 : daylight_illum(IL) += VTMULT * thisMap.IllumFromWinAtMapPt(loop, IS, IL);
9676 : }
9677 : } // End of second window loop
9678 :
9679 : // Variables for reporting
9680 153687 : for (IL = 1; IL <= NREFPT; ++IL) {
9681 151950 : thisMap.DaylIllumAtMapPt(IL) = max(daylight_illum(IL), 0.0);
9682 : }
9683 : } // End loop over maps
9684 : }
9685 :
9686 1529 : void ReportIllumMap(EnergyPlusData &state, int const MapNum)
9687 : {
9688 :
9689 : // SUBROUTINE INFORMATION:
9690 : // AUTHOR Peter Ellis
9691 : // DATE WRITTEN May 2003
9692 : // MODIFIED na
9693 : // RE-ENGINEERED na
9694 :
9695 : // PURPOSE OF THIS SUBROUTINE:
9696 : // This subroutine produces the Daylighting Illuminance Map output. Each separate map (by zone)
9697 : // is placed on a temporary file and later (see CloseReportIllumMaps) coallesced into a single
9698 : // output file.
9699 :
9700 : // Using/Aliasing
9701 : using DataStringGlobals::CharComma;
9702 : using DataStringGlobals::CharSpace;
9703 : using DataStringGlobals::CharTab;
9704 :
9705 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9706 3058 : std::string String;
9707 : int RefPt;
9708 : int X;
9709 : int Y;
9710 : int R;
9711 : int IllumOut;
9712 :
9713 1529 : auto &FirstTimeMaps = state.dataDaylightingManager->FirstTimeMaps;
9714 1529 : auto &EnvrnPrint = state.dataDaylightingManager->EnvrnPrint;
9715 1529 : auto &SavedMnDy = state.dataDaylightingManager->SavedMnDy;
9716 1529 : auto &XValue = state.dataDaylightingManager->XValue;
9717 1529 : auto &YValue = state.dataDaylightingManager->YValue;
9718 1529 : auto &IllumValue = state.dataDaylightingManager->IllumValue;
9719 3058 : std::string MapNoString;
9720 : int linelen;
9721 : // BSLLC Start
9722 : int SQYear;
9723 : int SQMonth;
9724 : int SQDayOfMonth;
9725 : int IllumIndex;
9726 : // static bool CommaDelimited( true ); //Unused Set but never used
9727 : // BSLLC Finish
9728 :
9729 1529 : if (state.dataDaylightingManager->ReportIllumMap_firstTime) {
9730 5 : state.dataDaylightingManager->ReportIllumMap_firstTime = false;
9731 5 : FirstTimeMaps.dimension((int)state.dataDaylightingData->IllumMap.size(), true);
9732 5 : EnvrnPrint.dimension((int)state.dataDaylightingData->IllumMap.size(), true);
9733 5 : SavedMnDy.allocate((int)state.dataDaylightingData->IllumMap.size());
9734 : }
9735 :
9736 1529 : if (FirstTimeMaps(MapNum)) {
9737 :
9738 7 : FirstTimeMaps(MapNum) = false;
9739 :
9740 7 : auto openMapFile = [&](const fs::path &filePath) -> InputOutputFile & {
9741 14 : auto &outputFile = *state.dataDaylightingData->IllumMap(MapNum).mapFile;
9742 7 : outputFile.filePath = fs::path(filePath.string() + fmt::to_string(MapNum));
9743 14 : outputFile.ensure_open(state, "ReportIllumMap");
9744 7 : return outputFile;
9745 7 : };
9746 7 : if (state.dataDaylightingData->MapColSep == CharTab) {
9747 0 : if (!openMapFile(state.files.outputMapTabFilePath).good()) return;
9748 : // CommaDelimited = false; //Unused Set but never used
9749 7 : } else if (state.dataDaylightingData->MapColSep == CharComma) {
9750 7 : if (!openMapFile(state.files.outputMapCsvFilePath).good()) return;
9751 : // CommaDelimited = true; //Unused Set but never used
9752 : } else {
9753 0 : if (!openMapFile(state.files.outputMapTxtFilePath).good()) return;
9754 : // CommaDelimited = false; //Unused Set but never used
9755 : }
9756 :
9757 7 : SavedMnDy(MapNum) = state.dataEnvrn->CurMnDyHr.substr(0, 5);
9758 :
9759 14 : state.dataDaylightingData->IllumMap(MapNum).Name =
9760 21 : format("{} at {:.2R}m", state.dataDaylightingData->IllumMap(MapNum).Name, state.dataDaylightingData->IllumMap(MapNum).Z);
9761 : }
9762 1529 : if (SavedMnDy(MapNum) != state.dataEnvrn->CurMnDyHr.substr(0, 5)) {
9763 13 : EnvrnPrint(MapNum) = true;
9764 13 : SavedMnDy(MapNum) = state.dataEnvrn->CurMnDyHr.substr(0, 5);
9765 : }
9766 :
9767 1529 : state.dataDaylightingData->IllumMap(MapNum).pointsHeader = "";
9768 1529 : int rCount = 0;
9769 3325 : for (int daylightCtrlNum = 1; daylightCtrlNum <= (int)state.dataDaylightingData->daylightControl.size(); ++daylightCtrlNum) {
9770 1796 : if (state.dataDaylightingData->daylightControl(daylightCtrlNum).zoneIndex == state.dataDaylightingData->IllumMap(MapNum).zoneIndex) {
9771 1529 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(daylightCtrlNum);
9772 :
9773 3414 : for (R = 1; R <= thisDaylightControl.TotalDaylRefPoints; ++R) {
9774 1885 : ++rCount;
9775 5655 : state.dataDaylightingData->IllumMap(MapNum).pointsHeader += format(" RefPt{}=({:.2R}:{:.2R}:{:.2R}),",
9776 : rCount,
9777 : thisDaylightControl.DaylRefPtAbsCoord(1, R),
9778 : thisDaylightControl.DaylRefPtAbsCoord(2, R),
9779 3770 : thisDaylightControl.DaylRefPtAbsCoord(3, R));
9780 : }
9781 : }
9782 : }
9783 :
9784 1529 : if (rCount > 0) {
9785 : // Remove trailing comma
9786 1529 : state.dataDaylightingData->IllumMap(MapNum).pointsHeader.pop_back();
9787 : }
9788 1529 : if (EnvrnPrint(MapNum)) {
9789 120 : WriteDaylightMapTitle(state,
9790 : MapNum,
9791 20 : *state.dataDaylightingData->IllumMap(MapNum).mapFile,
9792 20 : state.dataDaylightingData->IllumMap(MapNum).Name,
9793 20 : state.dataEnvrn->EnvironmentName,
9794 20 : state.dataDaylightingData->IllumMap(MapNum).zoneIndex,
9795 20 : state.dataDaylightingData->IllumMap(MapNum).pointsHeader,
9796 20 : state.dataDaylightingData->IllumMap(MapNum).Z);
9797 20 : EnvrnPrint(MapNum) = false;
9798 : }
9799 :
9800 1529 : if (!state.dataGlobal->WarmupFlag) {
9801 1529 : if (state.dataGlobal->TimeStep == state.dataGlobal->NumOfTimeStepInHour) { // Report only hourly
9802 :
9803 : // Write X scale column header
9804 544 : auto mapLine = format(" {} {:02}:00", SavedMnDy(MapNum), state.dataGlobal->HourOfDay);
9805 272 : if (state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLengthNeeded) linelen = int(len(mapLine));
9806 272 : RefPt = 1;
9807 2752 : for (X = 1; X <= state.dataDaylightingData->IllumMap(MapNum).Xnum; ++X) {
9808 : const auto AddXorYString = format("{}({:.2R};{:.2R})=",
9809 2480 : state.dataDaylightingData->MapColSep,
9810 2480 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt),
9811 9920 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt));
9812 2480 : if (state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLengthNeeded) linelen += int(len(AddXorYString));
9813 2480 : mapLine += AddXorYString;
9814 2480 : ++RefPt;
9815 : } // X
9816 :
9817 272 : if (state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLengthNeeded) {
9818 7 : state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLength = linelen;
9819 7 : if (static_cast<std::string::size_type>(state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLength) > len(mapLine)) {
9820 0 : ShowWarningError(state,
9821 0 : format("ReportIllumMap: Map=\"{}\" -- the X Header overflows buffer -- will be truncated at {} characters.",
9822 0 : state.dataDaylightingData->IllumMap(MapNum).Name,
9823 0 : int(len(mapLine))));
9824 0 : ShowContinueError(state,
9825 0 : format("...needed {} characters. Please contact EnergyPlus support.",
9826 0 : state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLength));
9827 : }
9828 7 : state.dataDaylightingData->IllumMap(MapNum).HeaderXLineLengthNeeded = false;
9829 : }
9830 :
9831 272 : print(*state.dataDaylightingData->IllumMap(MapNum).mapFile, "{}\n", mapLine);
9832 :
9833 : // Write Y scale prefix and illuminance values
9834 272 : RefPt = 1;
9835 2992 : for (Y = 1; Y <= state.dataDaylightingData->IllumMap(MapNum).Ynum; ++Y) {
9836 8160 : mapLine = format("({:.2R};{:.2R})=",
9837 2720 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(1, RefPt),
9838 5440 : state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtAbsCoord(2, RefPt));
9839 27520 : for (R = RefPt; R <= RefPt + state.dataDaylightingData->IllumMap(MapNum).Xnum - 1; ++R) {
9840 24800 : IllumOut = nint(state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPtHr(R));
9841 24800 : if (state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(R)) {
9842 24800 : String = fmt::to_string(IllumOut);
9843 : } else {
9844 0 : String = fmt::to_string(IllumOut);
9845 0 : String = "*" + String;
9846 : }
9847 24800 : mapLine += state.dataDaylightingData->MapColSep + String;
9848 : }
9849 :
9850 2720 : print(*state.dataDaylightingData->IllumMap(MapNum).mapFile, "{}\n", mapLine);
9851 :
9852 2720 : RefPt += state.dataDaylightingData->IllumMap(MapNum).Xnum;
9853 : } // X
9854 :
9855 272 : if (state.dataSQLiteProcedures->sqlite) {
9856 16 : if (state.dataDaylightingManager->SQFirstTime) {
9857 1 : int const nX(maxval(state.dataDaylightingData->IllumMap, &DataDaylighting::IllumMapData::Xnum));
9858 1 : int const nY(maxval(state.dataDaylightingData->IllumMap, &DataDaylighting::IllumMapData::Ynum));
9859 1 : XValue.allocate(nX);
9860 1 : YValue.allocate(nY);
9861 1 : IllumValue.allocate(nX, nY);
9862 1 : state.dataDaylightingManager->SQFirstTime = false;
9863 : }
9864 :
9865 : // We need DataGlobals::CalendarYear, and not DataEnvironment::Year because
9866 : // otherwise if you run a TMY file, you'll get for eg 1977, 1981, etc
9867 16 : SQYear = state.dataGlobal->CalendarYear;
9868 16 : SQMonth = state.dataEnvrn->Month;
9869 16 : SQDayOfMonth = state.dataEnvrn->DayOfMonth;
9870 :
9871 176 : for (Y = 1; Y <= state.dataDaylightingData->IllumMap(MapNum).Ynum; ++Y) {
9872 160 : YValue(Y) = state.dataDaylightingData->IllumMap(MapNum).Ymin + (Y - 1) * state.dataDaylightingData->IllumMap(MapNum).Yinc;
9873 1760 : for (X = 1; X <= state.dataDaylightingData->IllumMap(MapNum).Xnum; ++X) {
9874 1600 : XValue(X) = state.dataDaylightingData->IllumMap(MapNum).Xmin + (X - 1) * state.dataDaylightingData->IllumMap(MapNum).Xinc;
9875 1600 : IllumIndex = X + (Y - 1) * state.dataDaylightingData->IllumMap(MapNum).Xnum;
9876 1600 : IllumValue(X, Y) = nint(state.dataDaylightingData->IllumMapCalc(MapNum).DaylIllumAtMapPtHr(IllumIndex));
9877 1600 : if (!state.dataDaylightingData->IllumMapCalc(MapNum).MapRefPtInBounds(IllumIndex)) {
9878 0 : IllumValue(X, Y) = -IllumValue(X, Y);
9879 : }
9880 : } // X Loop
9881 : } // Y Loop
9882 :
9883 64 : state.dataSQLiteProcedures->sqlite->createSQLiteDaylightMap(MapNum,
9884 : SQYear,
9885 : SQMonth,
9886 : SQDayOfMonth,
9887 16 : state.dataGlobal->HourOfDay,
9888 16 : state.dataDaylightingData->IllumMap(MapNum).Xnum,
9889 : XValue,
9890 16 : state.dataDaylightingData->IllumMap(MapNum).Ynum,
9891 : YValue,
9892 : IllumValue);
9893 :
9894 : } // WriteOutputToSQLite
9895 : } // end time step
9896 : } // not Warmup
9897 : }
9898 :
9899 771 : void CloseReportIllumMaps(EnergyPlusData &state)
9900 : {
9901 :
9902 : // SUBROUTINE INFORMATION:
9903 : // AUTHOR Linda K. Lawrie
9904 : // DATE WRITTEN June 2003
9905 : // MODIFIED na
9906 : // RE-ENGINEERED na
9907 :
9908 : // PURPOSE OF THIS SUBROUTINE:
9909 : // This subroutine "closes" out the created daylight illuminance maps by merging them
9910 : // into the "eplusout.map" file.
9911 :
9912 : // Using/Aliasing
9913 : using DataStringGlobals::CharComma;
9914 : using DataStringGlobals::CharSpace;
9915 : using DataStringGlobals::CharTab;
9916 :
9917 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9918 771 : if ((int)state.dataDaylightingData->IllumMap.size() > 0) {
9919 : // Write map header
9920 5 : if (state.dataDaylightingData->MapColSep == CharTab) {
9921 0 : state.files.map.filePath = state.files.outputMapTabFilePath;
9922 5 : } else if (state.dataDaylightingData->MapColSep == CharComma) {
9923 5 : state.files.map.filePath = state.files.outputMapCsvFilePath;
9924 : } else {
9925 0 : state.files.map.filePath = state.files.outputMapTxtFilePath;
9926 : }
9927 :
9928 5 : state.files.map.ensure_open(state, "CloseReportIllumMaps");
9929 :
9930 12 : for (int MapNum = 1; MapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++MapNum) {
9931 7 : if (!state.dataDaylightingData->IllumMap(MapNum).mapFile->good()) continue; // fatal error processing
9932 :
9933 14 : const auto mapLines = state.dataDaylightingData->IllumMap(MapNum).mapFile->getLines();
9934 7 : if (mapLines.empty()) {
9935 0 : ShowSevereError(state, "CloseReportIllumMaps: IllumMap=\"" + state.dataDaylightingData->IllumMap(MapNum).Name + "\" is empty.");
9936 0 : break;
9937 : }
9938 3019 : for (const auto &mapLine : mapLines) {
9939 3012 : print(state.files.map, "{}\n", mapLine);
9940 : }
9941 7 : state.dataDaylightingData->IllumMap(MapNum).mapFile->del();
9942 : }
9943 :
9944 5 : if (!state.dataDaylightingData->mapResultsReported && !state.dataErrTracking->AbortProcessing) {
9945 0 : const auto message = "CloseReportIllumMaps: Illuminance maps requested but no data ever reported. Likely cause is no solar.";
9946 0 : ShowSevereError(state, message);
9947 0 : print(state.files.map, "{}\n", message);
9948 : }
9949 : }
9950 771 : }
9951 :
9952 771 : void CloseDFSFile(EnergyPlusData &state)
9953 : {
9954 :
9955 : // SUBROUTINE INFORMATION:
9956 : // AUTHOR Linda Lawrie
9957 : // DATE WRITTEN August 2010
9958 : // MODIFIED na
9959 : // RE-ENGINEERED na
9960 :
9961 : // PURPOSE OF THIS SUBROUTINE:
9962 : // Make sure DFSFile is closed at exit time. Do not rely on operating system to
9963 : // take care of it.
9964 :
9965 771 : state.files.dfs.close();
9966 771 : }
9967 :
9968 62 : void DayltgSetupAdjZoneListsAndPointers(EnergyPlusData &state)
9969 : {
9970 :
9971 : // SUBROUTINE INFORMATION:
9972 : // AUTHOR Fred Winkelmann
9973 : // DATE WRITTEN Feb. 2004
9974 : // MODIFIED: June 2010;LKL - Merged two routines.
9975 :
9976 : // PURPOSE OF THIS SUBROUTINE:
9977 : // For each Daylighting:Detailed enclosure, creates a list of adjacent enclosures,
9978 : // that have one or more exterior windows and that share one or more interior
9979 : // windows with Z. Used in calculation of daylighting through interior windows.
9980 :
9981 : // Sets the daylighting factor pointers for each Daylighting:Detailed control. The pointer
9982 : // may be associated with an exterior window in a daylit target zone's enclosure or an exterior window in
9983 : // an adjacent enclosure, daylit or not, that shares interior windows with the target zone's enclosure.
9984 :
9985 : // Count number of exterior Windows (use to allocate arrays)
9986 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
9987 708 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
9988 708 : thisEnclDaylight.TotalExtWindows = 0;
9989 :
9990 : // Count exterior windows in this solar enclosure
9991 8030 : for (int const surfNum : state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr) {
9992 15812 : if ((state.dataSurface->Surface(surfNum).Class == SurfaceClass::Window &&
9993 13478 : state.dataSurface->Surface(surfNum).ExtBoundCond == ExternalEnvironment) ||
9994 6156 : state.dataSurface->SurfWinOriginalClass(surfNum) == SurfaceClass::TDD_Diffuser) {
9995 1166 : ++thisEnclDaylight.TotalExtWindows;
9996 : }
9997 : }
9998 : } // End of primary enclosure loop
9999 :
10000 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
10001 708 : int NumList = 0;
10002 708 : if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
10003 286 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10004 286 : if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
10005 : // This is a Daylighting:Detailed enclosure
10006 : // Find adjacent zones/enclosures
10007 7218 : for (int adjEnclNum = 1; adjEnclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++adjEnclNum) {
10008 6935 : if (adjEnclNum == enclNum) continue;
10009 : // Require that adjEnclNum have a least one exterior window
10010 6652 : bool AdjEnclHasExtWins = false;
10011 64609 : for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
10012 68090 : if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
10013 5067 : (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment)) {
10014 5066 : AdjEnclHasExtWins = true;
10015 5066 : break;
10016 : }
10017 : }
10018 6652 : if (!AdjEnclHasExtWins) continue;
10019 : // Loop again through surfaces in ZoneNumAdj and see if any are interior windows adjacent to ZoneNum
10020 64869 : for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
10021 75871 : if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
10022 16067 : (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond >= 1)) {
10023 : // This is an interior window in ZoneNumAdj
10024 1 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNumAdj).ExtBoundCond).SolarEnclIndex == enclNum) {
10025 : // This interior window is adjacent to ZoneNum
10026 1 : ++NumList;
10027 1 : break;
10028 : }
10029 : }
10030 : }
10031 : }
10032 283 : thisEnclDaylight.AdjIntWinEnclNums.allocate(NumList);
10033 283 : thisEnclDaylight.AdjIntWinEnclNums = 0;
10034 : } // End of primary enclosure loop
10035 :
10036 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
10037 708 : int NumList = 0;
10038 708 : if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
10039 286 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10040 286 : if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
10041 : // This is a Daylighting:Detailed enclosure
10042 : // Find adjacent zones/enclosures
10043 7218 : for (int adjEnclNum = 1; adjEnclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++adjEnclNum) {
10044 6935 : if (adjEnclNum == enclNum) continue;
10045 : // Require that adjEnclNum have a least one exterior window
10046 6652 : bool AdjEnclHasExtWins = false;
10047 64609 : for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
10048 68090 : if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
10049 5067 : (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment)) {
10050 5066 : AdjEnclHasExtWins = true;
10051 5066 : break;
10052 : }
10053 : }
10054 6652 : if (!AdjEnclHasExtWins) continue;
10055 : // Loop again through surfaces in ZoneNumAdj and see if any are interior windows adjacent to enclNum
10056 64869 : for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
10057 75871 : if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
10058 16067 : (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond >= 1)) {
10059 : // This is an interior window in adjEnclNum
10060 1 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNumAdj).ExtBoundCond).SolarEnclIndex == enclNum) {
10061 : // This interior window is adjacent to ZoneNum
10062 1 : ++NumList;
10063 1 : int enclNumAdj = state.dataSurface->Surface(SurfNumAdj).SolarEnclIndex;
10064 1 : thisEnclDaylight.AdjIntWinEnclNums(NumList) = enclNumAdj;
10065 1 : state.dataDaylightingData->enclDaylight(enclNumAdj).adjEnclHasDayltgCtrl = true;
10066 1 : break;
10067 : }
10068 : }
10069 : }
10070 : }
10071 283 : thisEnclDaylight.NumOfIntWinAdjEncls = NumList;
10072 : } // End of primary enclosure loop
10073 :
10074 : // now fill out information on relationship between adjacent exterior windows and associated interior windows
10075 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
10076 708 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10077 : // first find count of exterior windows
10078 1415 : if (thisEnclDaylight.NumOfIntWinAdjEncls <= 0) {
10079 707 : thisEnclDaylight.NumOfIntWinAdjEnclExtWins = 0;
10080 707 : continue;
10081 : }
10082 2 : for (int adjEnclNum : thisEnclDaylight.AdjIntWinEnclNums) {
10083 9 : for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
10084 10 : if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
10085 2 : (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment)) {
10086 1 : ++thisEnclDaylight.NumOfIntWinAdjEnclExtWins;
10087 : }
10088 : }
10089 : }
10090 : // now allocate nested struct based on exterior window count
10091 1 : thisEnclDaylight.IntWinAdjEnclExtWin.allocate(thisEnclDaylight.NumOfIntWinAdjEnclExtWins);
10092 :
10093 : // now fill nested structure
10094 1 : int ExtWinIndex = 0;
10095 2 : for (int adjEnclNum : thisEnclDaylight.AdjIntWinEnclNums) {
10096 9 : for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
10097 10 : if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window) &&
10098 2 : (state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment)) {
10099 1 : ++ExtWinIndex;
10100 1 : thisEnclDaylight.IntWinAdjEnclExtWin(ExtWinIndex).SurfNum = SurfNumAdj;
10101 :
10102 : // now count interior windows shared by both zones
10103 1 : int NumOfIntWindowsCount = 0;
10104 9 : for (int SurfNumAdj2 : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
10105 10 : if ((state.dataSurface->Surface(SurfNumAdj2).Class == SurfaceClass::Window) &&
10106 2 : (state.dataSurface->Surface(SurfNumAdj2).ExtBoundCond >= 1)) {
10107 : // This is an interior window in ZoneNumAdj
10108 1 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNumAdj2).ExtBoundCond).SolarEnclIndex == enclNum) {
10109 : // This interior window is adjacent to ZoneNum and associated with this
10110 1 : ++NumOfIntWindowsCount;
10111 : }
10112 : }
10113 : }
10114 : // allocate nested array
10115 1 : thisEnclDaylight.IntWinAdjEnclExtWin(ExtWinIndex).IntWinNum.allocate(NumOfIntWindowsCount);
10116 1 : thisEnclDaylight.IntWinAdjEnclExtWin(ExtWinIndex).IntWinNum = 0;
10117 1 : int IntWinIndex = 0;
10118 9 : for (int SurfNumAdj2 : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
10119 10 : if ((state.dataSurface->Surface(SurfNumAdj2).Class == SurfaceClass::Window) &&
10120 2 : (state.dataSurface->Surface(SurfNumAdj2).ExtBoundCond >= 1)) {
10121 : // This is an interior window in ZoneNumAdj
10122 1 : if (state.dataSurface->Surface(state.dataSurface->Surface(SurfNumAdj2).ExtBoundCond).SolarEnclIndex == enclNum) {
10123 : // This interior window is adjacent to ZoneNum and associated with this
10124 1 : ++IntWinIndex;
10125 1 : thisEnclDaylight.IntWinAdjEnclExtWin(ExtWinIndex).IntWinNum(IntWinIndex) = SurfNumAdj2;
10126 : }
10127 : }
10128 : }
10129 : }
10130 : }
10131 : }
10132 : } // End of primary enclosure loop
10133 :
10134 124 : Array1D_int enclExtWin;
10135 62 : enclExtWin.dimension(state.dataViewFactor->NumOfSolarEnclosures, 0);
10136 :
10137 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
10138 708 : enclExtWin(enclNum) = 0;
10139 708 : if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
10140 286 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10141 286 : if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
10142 : // This is a Daylighting:Detailed zone
10143 :
10144 : // Get exterior windows in this solar enclosure
10145 3405 : for (int const surfNum : state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr) {
10146 7083 : if ((state.dataSurface->Surface(surfNum).Class == SurfaceClass::Window &&
10147 5406 : state.dataSurface->Surface(surfNum).ExtBoundCond == ExternalEnvironment) ||
10148 2284 : state.dataSurface->SurfWinOriginalClass(surfNum) == SurfaceClass::TDD_Diffuser) {
10149 838 : ++enclExtWin(enclNum);
10150 : }
10151 : }
10152 :
10153 : // Get exterior windows in adjacent enclosures that share interior windows with enclNum
10154 283 : if (thisEnclDaylight.NumOfIntWinAdjEncls > 0) {
10155 2 : for (int adjEnclNum : thisEnclDaylight.AdjIntWinEnclNums) {
10156 : // Get exterior windows in EnclNumAdj -- there must be at least one, otherwise
10157 : // it would not be an "AdjIntWinEncl"
10158 9 : for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
10159 18 : if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window &&
10160 15 : state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment) ||
10161 7 : state.dataSurface->SurfWinOriginalClass(SurfNumAdj) == SurfaceClass::TDD_Diffuser) {
10162 1 : ++enclExtWin(enclNum);
10163 : }
10164 : }
10165 : }
10166 : }
10167 : } // End of primary enclosure loop
10168 :
10169 62 : std::size_t maxShadeDeployOrderExtWinsSize(0);
10170 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
10171 708 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10172 708 : if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
10173 283 : thisEnclDaylight.NumOfDayltgExtWins = 0;
10174 283 : int thisEnclNumRefPoints = state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints;
10175 283 : if (thisEnclNumRefPoints > 0) {
10176 : // This is a Daylighting:Detailed enclosure
10177 :
10178 : // Get exterior windows in this enclosure
10179 283 : if (enclExtWin(enclNum) == 0) continue;
10180 283 : thisEnclDaylight.DayltgExtWinSurfNums.allocate(enclExtWin(enclNum));
10181 283 : thisEnclDaylight.DayltgExtWinSurfNums = 0;
10182 567 : for (int controlNum : thisEnclDaylight.daylightControlIndexes) {
10183 284 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(controlNum);
10184 284 : thisDaylightControl.MapShdOrdToLoopNum.allocate(enclExtWin(enclNum));
10185 284 : thisDaylightControl.MapShdOrdToLoopNum = 0;
10186 :
10187 284 : thisDaylightControl.SolidAngAtRefPt.allocate(enclExtWin(enclNum), thisDaylightControl.TotalDaylRefPoints);
10188 284 : thisDaylightControl.SolidAngAtRefPt = 0.0;
10189 284 : thisDaylightControl.SolidAngAtRefPtWtd.allocate(enclExtWin(enclNum), thisDaylightControl.TotalDaylRefPoints);
10190 284 : thisDaylightControl.SolidAngAtRefPtWtd = 0.0;
10191 284 : thisDaylightControl.IllumFromWinAtRefPt.allocate(enclExtWin(enclNum), 2, thisDaylightControl.TotalDaylRefPoints);
10192 284 : thisDaylightControl.IllumFromWinAtRefPt = 0.0;
10193 284 : thisDaylightControl.BackLumFromWinAtRefPt.allocate(enclExtWin(enclNum), 2, thisDaylightControl.TotalDaylRefPoints);
10194 284 : thisDaylightControl.BackLumFromWinAtRefPt = 0.0;
10195 284 : thisDaylightControl.SourceLumFromWinAtRefPt.allocate(enclExtWin(enclNum), 2, thisDaylightControl.TotalDaylRefPoints);
10196 284 : thisDaylightControl.SourceLumFromWinAtRefPt = 0.0;
10197 : }
10198 :
10199 283 : int enclExtWinCtr = 0;
10200 :
10201 3405 : for (int const surfNum : state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr) {
10202 7083 : if ((state.dataSurface->Surface(surfNum).Class == SurfaceClass::Window &&
10203 5406 : state.dataSurface->Surface(surfNum).ExtBoundCond == ExternalEnvironment) ||
10204 2284 : state.dataSurface->SurfWinOriginalClass(surfNum) == SurfaceClass::TDD_Diffuser) {
10205 838 : ++enclExtWinCtr;
10206 838 : thisEnclDaylight.DayltgExtWinSurfNums(enclExtWinCtr) = surfNum;
10207 : }
10208 : }
10209 :
10210 : // Get exterior windows in adjacent enclosures that share interior windows with enclNum
10211 283 : if (thisEnclDaylight.NumOfIntWinAdjEncls > 0) {
10212 2 : for (int adjEnclNum : thisEnclDaylight.AdjIntWinEnclNums) {
10213 : // Get exterior windows in EnclNumAdj -- there must be at least one, otherwise
10214 : // it would not be an "AdjIntWinEncl"
10215 9 : for (int SurfNumAdj : state.dataViewFactor->EnclSolInfo(adjEnclNum).SurfacePtr) {
10216 18 : if ((state.dataSurface->Surface(SurfNumAdj).Class == SurfaceClass::Window &&
10217 15 : state.dataSurface->Surface(SurfNumAdj).ExtBoundCond == ExternalEnvironment) ||
10218 7 : state.dataSurface->SurfWinOriginalClass(SurfNumAdj) == SurfaceClass::TDD_Diffuser) {
10219 1 : ++enclExtWinCtr;
10220 1 : thisEnclDaylight.DayltgExtWinSurfNums(enclExtWinCtr) = SurfNumAdj;
10221 :
10222 : // If no daylighting in the adjacent enclosure, set up variables anyway:
10223 1 : if (state.dataViewFactor->EnclSolInfo(adjEnclNum).TotalEnclosureDaylRefPoints == 0) {
10224 1 : if (!state.dataSurface->SurfWinSurfDayLightInit(SurfNumAdj)) {
10225 1 : state.dataSurface->SurfaceWindow(SurfNumAdj).SolidAngAtRefPt.allocate(thisEnclNumRefPoints);
10226 1 : state.dataSurface->SurfaceWindow(SurfNumAdj).SolidAngAtRefPt = 0.0;
10227 1 : state.dataSurface->SurfaceWindow(SurfNumAdj).SolidAngAtRefPtWtd.allocate(thisEnclNumRefPoints);
10228 1 : state.dataSurface->SurfaceWindow(SurfNumAdj).SolidAngAtRefPtWtd = 0.0;
10229 1 : state.dataSurface->SurfaceWindow(SurfNumAdj).IllumFromWinAtRefPt.allocate(2, thisEnclNumRefPoints);
10230 1 : state.dataSurface->SurfaceWindow(SurfNumAdj).IllumFromWinAtRefPt = 0.0;
10231 1 : state.dataSurface->SurfaceWindow(SurfNumAdj).BackLumFromWinAtRefPt.allocate(2, thisEnclNumRefPoints);
10232 1 : state.dataSurface->SurfaceWindow(SurfNumAdj).BackLumFromWinAtRefPt = 0.0;
10233 1 : state.dataSurface->SurfaceWindow(SurfNumAdj).SourceLumFromWinAtRefPt.allocate(2, thisEnclNumRefPoints);
10234 1 : state.dataSurface->SurfaceWindow(SurfNumAdj).SourceLumFromWinAtRefPt = 0.0;
10235 1 : state.dataSurface->SurfWinSurfDayLightInit(SurfNumAdj) = true;
10236 : }
10237 : }
10238 : }
10239 : }
10240 : }
10241 : }
10242 :
10243 283 : thisEnclDaylight.NumOfDayltgExtWins = enclExtWin(enclNum);
10244 283 : int winSize = enclExtWin(enclNum);
10245 :
10246 567 : for (int controlNum : thisEnclDaylight.daylightControlIndexes) {
10247 284 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(controlNum);
10248 284 : int refSize = thisDaylightControl.TotalDaylRefPoints;
10249 284 : thisDaylightControl.DaylIllFacSky.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, 4, refSize, winSize);
10250 284 : thisDaylightControl.DaylSourceFacSky.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, 4, refSize, winSize);
10251 284 : thisDaylightControl.DaylBackFacSky.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, 4, refSize, winSize);
10252 284 : thisDaylightControl.DaylIllFacSun.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
10253 284 : thisDaylightControl.DaylIllFacSunDisk.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
10254 284 : thisDaylightControl.DaylSourceFacSun.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
10255 284 : thisDaylightControl.DaylSourceFacSunDisk.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
10256 284 : thisDaylightControl.DaylBackFacSun.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
10257 284 : thisDaylightControl.DaylBackFacSunDisk.allocate(24, state.dataSurface->actualMaxSlatAngs + 1, refSize, winSize);
10258 : }
10259 : } // End of check if thisEnclNumRefPoints > 0
10260 :
10261 283 : if (state.dataSurface->TotWinShadingControl > 0) {
10262 22 : std::size_t maxSize = CreateShadeDeploymentOrder(state, enclNum);
10263 22 : if (maxSize > maxShadeDeployOrderExtWinsSize) maxShadeDeployOrderExtWinsSize = maxSize;
10264 : }
10265 : } // End of primary enclosure loop
10266 :
10267 : // size these for the maximum of the shade deployment order
10268 62 : state.dataDaylightingManager->DILLSW.allocate(maxShadeDeployOrderExtWinsSize);
10269 62 : state.dataDaylightingManager->DILLUN.allocate(maxShadeDeployOrderExtWinsSize);
10270 62 : state.dataDaylightingManager->WDAYIL.allocate(2, state.dataDaylightingData->maxRefPointsPerControl, maxShadeDeployOrderExtWinsSize);
10271 62 : state.dataDaylightingManager->WBACLU.allocate(2, state.dataDaylightingData->maxRefPointsPerControl, maxShadeDeployOrderExtWinsSize);
10272 62 : state.dataDaylightingManager->RDAYIL.allocate(state.dataDaylightingData->maxRefPointsPerControl, maxShadeDeployOrderExtWinsSize);
10273 62 : state.dataDaylightingManager->RBACLU.allocate(state.dataDaylightingData->maxRefPointsPerControl, maxShadeDeployOrderExtWinsSize);
10274 :
10275 62 : state.dataDaylightingManager->TVIS1.allocate(maxShadeDeployOrderExtWinsSize);
10276 62 : state.dataDaylightingManager->TVIS2.allocate(maxShadeDeployOrderExtWinsSize);
10277 62 : state.dataDaylightingManager->ASETIL.allocate(maxShadeDeployOrderExtWinsSize);
10278 :
10279 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
10280 708 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10281 708 : if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
10282 283 : int thisEnclNumRefPoints = state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints;
10283 283 : if (thisEnclNumRefPoints > 0) {
10284 283 : if (state.dataSurface->TotWinShadingControl > 0) {
10285 22 : MapShadeDeploymentOrderToLoopNumber(state, enclNum);
10286 : }
10287 : }
10288 : }
10289 :
10290 69 : for (int mapNum = 1; mapNum <= (int)state.dataDaylightingData->IllumMap.size(); ++mapNum) {
10291 7 : int numExtWin = enclExtWin(state.dataDaylightingData->IllumMapCalc(mapNum).enclIndex);
10292 7 : int numMapRefPts = state.dataDaylightingData->IllumMapCalc(mapNum).TotalMapRefPoints;
10293 :
10294 7 : if (numMapRefPts > 0) {
10295 7 : state.dataDaylightingData->IllumMapCalc(mapNum).IllumFromWinAtMapPt.allocate(numExtWin, 2, numMapRefPts);
10296 7 : state.dataDaylightingData->IllumMapCalc(mapNum).IllumFromWinAtMapPt = 0.0;
10297 :
10298 14 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSky.allocate(
10299 14 : 24, state.dataSurface->actualMaxSlatAngs + 1, 4, numMapRefPts, numExtWin);
10300 14 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSun.allocate(
10301 14 : 24, state.dataSurface->actualMaxSlatAngs + 1, numMapRefPts, numExtWin);
10302 14 : state.dataDaylightingData->IllumMapCalc(mapNum).DaylIllFacSunDisk.allocate(
10303 14 : 24, state.dataSurface->actualMaxSlatAngs + 1, numMapRefPts, numExtWin);
10304 : }
10305 : } // End of map loop
10306 :
10307 62 : state.dataDaylightingManager->EINTSK.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 4, 0.0);
10308 62 : state.dataDaylightingManager->EINTSU.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 0.0);
10309 62 : state.dataDaylightingManager->EINTSUdisk.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 0.0);
10310 62 : state.dataDaylightingManager->WLUMSK.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 4, 0.0);
10311 62 : state.dataDaylightingManager->WLUMSU.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 0.0);
10312 62 : state.dataDaylightingManager->WLUMSUdisk.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 0.0);
10313 62 : state.dataDaylightingManager->EDIRSK.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 4);
10314 62 : state.dataDaylightingManager->EDIRSU.dimension(24, state.dataSurface->actualMaxSlatAngs + 1);
10315 62 : state.dataDaylightingManager->EDIRSUdisk.dimension(24, state.dataSurface->actualMaxSlatAngs + 1);
10316 62 : state.dataDaylightingManager->AVWLSK.dimension(24, state.dataSurface->actualMaxSlatAngs + 1, 4);
10317 62 : state.dataDaylightingManager->AVWLSU.dimension(24, state.dataSurface->actualMaxSlatAngs + 1);
10318 62 : state.dataDaylightingManager->AVWLSUdisk.dimension(24, state.dataSurface->actualMaxSlatAngs + 1);
10319 62 : state.dataDaylightingManager->FLFWSU.dimension(state.dataSurface->actualMaxSlatAngs + 1);
10320 62 : state.dataDaylightingManager->FLFWSUdisk.dimension(state.dataSurface->actualMaxSlatAngs + 1);
10321 62 : state.dataDaylightingManager->FLCWSU.dimension(state.dataSurface->actualMaxSlatAngs + 1);
10322 62 : state.dataDaylightingManager->TransMult.dimension(state.dataSurface->actualMaxSlatAngs);
10323 62 : state.dataDaylightingManager->DayltgInterReflectedIllumTransBmBmMult.dimension(state.dataSurface->actualMaxSlatAngs);
10324 62 : state.dataDaylightingManager->TransBmBmMult.dimension(state.dataSurface->actualMaxSlatAngs);
10325 62 : state.dataDaylightingManager->TransBmBmMultRefl.dimension(state.dataSurface->actualMaxSlatAngs);
10326 62 : state.dataDaylightingManager->FLCWSK.dimension(state.dataSurface->actualMaxSlatAngs + 1, 4);
10327 62 : state.dataDaylightingManager->FLFWSK.dimension(state.dataSurface->actualMaxSlatAngs + 1, 4);
10328 :
10329 : static constexpr std::string_view Format_700("! <Enclosure/Window Adjacency Daylighting Counts>, Enclosure Name, Number of Exterior Windows, "
10330 : "Number of Exterior Windows in Adjacent Enclosures\n");
10331 62 : print(state.files.eio, Format_700);
10332 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
10333 708 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10334 708 : if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
10335 283 : if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
10336 : static constexpr std::string_view Format_701("Enclosure/Window Adjacency Daylighting Counts, {},{},{}\n");
10337 566 : print(state.files.eio,
10338 : Format_701,
10339 283 : state.dataViewFactor->EnclSolInfo(enclNum).Name,
10340 : thisEnclDaylight.TotalExtWindows,
10341 566 : (thisEnclDaylight.NumOfDayltgExtWins - thisEnclDaylight.TotalExtWindows));
10342 : }
10343 : static constexpr std::string_view Format_702(
10344 : "! <Enclosure/Window Adjacency Daylighting Matrix>, Enclosure Name, Number of Adjacent Enclosures with Windows,Adjacent "
10345 : "Enclosure Names - 1st 100 (max)\n");
10346 62 : print(state.files.eio, Format_702);
10347 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
10348 708 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10349 708 : if (!thisEnclDaylight.hasSplitFluxDaylighting) continue;
10350 283 : if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
10351 : static constexpr std::string_view Format_703("Enclosure/Window Adjacency Daylighting Matrix, {},{}");
10352 283 : print(state.files.eio, Format_703, state.dataViewFactor->EnclSolInfo(enclNum).Name, thisEnclDaylight.NumOfIntWinAdjEncls);
10353 284 : for (int loop = 1, loop_end = min(thisEnclDaylight.NumOfIntWinAdjEncls, 100); loop <= loop_end; ++loop) {
10354 1 : print(state.files.eio, ",{}", state.dataViewFactor->EnclSolInfo(thisEnclDaylight.AdjIntWinEnclNums(loop)).Name);
10355 : }
10356 283 : print(state.files.eio, "\n");
10357 : }
10358 :
10359 62 : enclExtWin.deallocate();
10360 62 : }
10361 :
10362 22 : std::size_t CreateShadeDeploymentOrder(EnergyPlusData &state, int const enclNum)
10363 : {
10364 : // J. Glazer - 2018
10365 : // create sorted list for shade deployment order
10366 : // first step is to create a sortable list of WindowShadingControl objects by sequence
10367 44 : std::vector<std::pair<int, int>> shadeControlSequence; // sequence, WindowShadingControl
10368 55 : for (int iShadeCtrl = 1; iShadeCtrl <= state.dataSurface->TotWinShadingControl; ++iShadeCtrl) {
10369 41 : for (int spaceNum : state.dataHeatBal->Zone(state.dataSurface->WindowShadingControl(iShadeCtrl).ZoneIndex).spaceIndexes) {
10370 33 : int shadeCtrlEnclNum = state.dataHeatBal->space(spaceNum).solarEnclosureNum;
10371 33 : if (shadeCtrlEnclNum == enclNum) {
10372 25 : shadeControlSequence.push_back(std::make_pair(state.dataSurface->WindowShadingControl(iShadeCtrl).SequenceNumber, iShadeCtrl));
10373 25 : break;
10374 : }
10375 : }
10376 : }
10377 : // sort the WindowShadingControl objects based on sequence number
10378 22 : sort(shadeControlSequence.begin(), shadeControlSequence.end());
10379 : // now make the deployment list of lists.
10380 : // each sublist is a group of surfaces that should be deployed together
10381 : // often the sublist is just a single item.
10382 22 : std::size_t maxShadeDeployOrderExtWinsSize = 0;
10383 44 : for (int controlNum : state.dataDaylightingData->enclDaylight(enclNum).daylightControlIndexes) {
10384 22 : auto &thisDaylightCtrl = state.dataDaylightingData->daylightControl(controlNum);
10385 47 : for (auto sequence : shadeControlSequence) {
10386 25 : int curShadeControl = sequence.second;
10387 25 : if (state.dataSurface->WindowShadingControl(curShadeControl).multiSurfaceControl == MultiSurfaceControl::Group) {
10388 : // add a group of surfaces since they should be deployed as a group
10389 8 : std::vector<int> group;
10390 13 : for (int i = 1; i <= state.dataSurface->WindowShadingControl(curShadeControl).FenestrationCount; i++) {
10391 9 : group.push_back(state.dataSurface->WindowShadingControl(curShadeControl).FenestrationIndex(i));
10392 : }
10393 4 : thisDaylightCtrl.ShadeDeployOrderExtWins.push_back(group);
10394 : } else {
10395 : // add each individial surface as a separate list so they are deployed individually
10396 46 : for (int i = 1; i <= state.dataSurface->WindowShadingControl(curShadeControl).FenestrationCount; i++) {
10397 50 : std::vector<int> singleMemberVector;
10398 25 : singleMemberVector.push_back(state.dataSurface->WindowShadingControl(curShadeControl).FenestrationIndex(i));
10399 25 : thisDaylightCtrl.ShadeDeployOrderExtWins.push_back(singleMemberVector);
10400 : }
10401 : }
10402 : }
10403 22 : maxShadeDeployOrderExtWinsSize = max(maxShadeDeployOrderExtWinsSize, thisDaylightCtrl.ShadeDeployOrderExtWins.size());
10404 : }
10405 22 : int maxNumOfDayltgExtWins = 0;
10406 117 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
10407 95 : maxNumOfDayltgExtWins = max(maxNumOfDayltgExtWins, state.dataDaylightingData->enclDaylight(enclNum).NumOfDayltgExtWins);
10408 : }
10409 22 : state.dataDaylightingManager->previously_shaded.allocate(maxNumOfDayltgExtWins);
10410 :
10411 44 : return maxShadeDeployOrderExtWinsSize;
10412 : }
10413 :
10414 22 : void MapShadeDeploymentOrderToLoopNumber(EnergyPlusData &state, int const enclNum)
10415 : {
10416 : // J. Glazer - 2018
10417 : // Allow a way to map back to the original "loop" index that is used in many other places in the
10418 : // ZoneDayLight data structure when traversing the list in the order of the window shaded deployment
10419 :
10420 22 : auto const &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10421 22 : auto const &thisSolEnclosureName = state.dataViewFactor->EnclSolInfo(enclNum).Name;
10422 22 : if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints > 0 && thisEnclDaylight.NumOfDayltgExtWins > 0) {
10423 44 : for (int controlNum : state.dataDaylightingData->enclDaylight(enclNum).daylightControlIndexes) {
10424 22 : auto &thisDaylightCtrl = state.dataDaylightingData->daylightControl(controlNum);
10425 22 : if (thisDaylightCtrl.ShadeDeployOrderExtWins.size() > 0) {
10426 21 : int count = 0;
10427 21 : bool showOnce = true;
10428 50 : for (auto listOfExtWin : thisDaylightCtrl.ShadeDeployOrderExtWins) {
10429 63 : for (auto IWinShdOrd : listOfExtWin) {
10430 34 : ++count;
10431 34 : if (count > thisEnclDaylight.NumOfDayltgExtWins) {
10432 0 : if (showOnce) {
10433 0 : ShowWarningError(state,
10434 0 : "MapShadeDeploymentOrderToLoopNumber: too many controlled shaded windows in enclosure " +
10435 : thisSolEnclosureName);
10436 0 : ShowContinueError(
10437 : state, "Check the Zone Name in the WindowShadingControl that references the following fenestration surfaces:");
10438 0 : showOnce = false;
10439 : }
10440 0 : ShowContinueError(state, " - " + state.dataSurface->Surface(IWinShdOrd).Name);
10441 : }
10442 34 : bool found = false;
10443 86 : for (int loop = 1; loop <= thisEnclDaylight.NumOfDayltgExtWins; ++loop) {
10444 86 : int IWinLoop = thisEnclDaylight.DayltgExtWinSurfNums(loop);
10445 86 : if (IWinShdOrd == IWinLoop) {
10446 34 : thisDaylightCtrl.MapShdOrdToLoopNum(count) = loop;
10447 34 : found = true;
10448 34 : break;
10449 : }
10450 : }
10451 : }
10452 : }
10453 : }
10454 : } // controlNum loop
10455 : }
10456 22 : }
10457 :
10458 1015 : void DayltgInterReflIllFrIntWins(EnergyPlusData &state, int const enclNum)
10459 : {
10460 :
10461 : // SUBROUTINE INFORMATION:
10462 : // AUTHOR Fred Winkelmann
10463 : // DATE WRITTEN Mar. 2004
10464 :
10465 : // PURPOSE OF THIS SUBROUTINE:
10466 : // Calculates the inter-reflected illuminance in a daylit zone from beam
10467 : // and diffuse daylight entering the zone through interior windows. This illuminance
10468 : // is determined by the split-flux method and is assumed to be uniform, i.e., the same
10469 : // at all reference points.
10470 :
10471 : Real64 QDifTrans; // Luminous flux transmitted through an int win from adjacent zone's enclosure (lumens)
10472 : Real64 QDifTransUp; // Upgoing part of QDifTrans (lumens)
10473 : Real64 QDifTransDn; // Downgoing part of QDifTrans (lumens)
10474 : Real64 DifInterReflIllThisWin; // Inter-reflected illuminance due to QDifTrans (lux)
10475 : Real64 BmInterReflIll; // Inter-reflected illuminance due to beam solar entering ZoneNum's enclosure
10476 : // through its interior windows (lux)
10477 :
10478 1015 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10479 1015 : thisEnclDaylight.InterReflIllFrIntWins = 0.0;
10480 :
10481 1015 : auto &thisEnclSurfaces(state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr);
10482 8120 : for (int const IWin : thisEnclSurfaces) {
10483 7105 : if (state.dataSurface->Surface(IWin).Class == SurfaceClass::Window && state.dataSurface->Surface(IWin).ExtBoundCond >= 1) {
10484 : // This is an interior window in ZoneNum
10485 1015 : int const ConstrNum = state.dataSurface->Surface(IWin).Construction;
10486 1015 : int const adjEnclNum = state.dataSurface->Surface(state.dataSurface->Surface(IWin).ExtBoundCond).SolarEnclIndex;
10487 3045 : QDifTrans = state.dataHeatBal->EnclSolQSDifSol(adjEnclNum) * state.dataConstruction->Construct(ConstrNum).TransDiffVis *
10488 2030 : state.dataSurface->Surface(IWin).Area * state.dataEnvrn->PDIFLW;
10489 1015 : QDifTransUp = QDifTrans * state.dataSurface->SurfWinFractionUpgoing(IWin);
10490 1015 : QDifTransDn = QDifTrans * (1.0 - state.dataSurface->SurfWinFractionUpgoing(IWin));
10491 3045 : if (state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea *
10492 2030 : (1.0 - state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect) !=
10493 : 0.0) {
10494 1015 : DifInterReflIllThisWin =
10495 1015 : (QDifTransDn * state.dataSurface->SurfWinRhoFloorWall(IWin) + QDifTransUp * state.dataSurface->SurfWinRhoCeilingWall(IWin)) /
10496 2030 : (state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea *
10497 1015 : (1.0 - state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect));
10498 : } else {
10499 0 : DifInterReflIllThisWin = 0.0;
10500 : }
10501 1015 : thisEnclDaylight.InterReflIllFrIntWins += DifInterReflIllThisWin;
10502 : }
10503 : }
10504 :
10505 : // Add inter-reflected illuminance from beam solar entering enclosure through interior windows
10506 : // TH, CR 7873, 9/17/2009
10507 1015 : BmInterReflIll = 0.0;
10508 1015 : if (state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea > 0) {
10509 3045 : BmInterReflIll = (state.dataHeatBal->EnclSolDBIntWin(enclNum) * state.dataEnvrn->BeamSolarRad * state.dataEnvrn->PDIRLW *
10510 1015 : state.dataDaylightingData->enclDaylight(enclNum).floorVisRefl) /
10511 2030 : (state.dataDaylightingData->enclDaylight(enclNum).totInsSurfArea *
10512 1015 : (1.0 - state.dataDaylightingData->enclDaylight(enclNum).aveVisDiffReflect));
10513 : }
10514 :
10515 1015 : thisEnclDaylight.InterReflIllFrIntWins += BmInterReflIll;
10516 1015 : }
10517 :
10518 62 : void CalcMinIntWinSolidAngs(EnergyPlusData &state)
10519 : {
10520 :
10521 : // SUBROUTINE INFORMATION:
10522 : // AUTHOR Fred Winkelmann
10523 : // DATE WRITTEN Feb. 2004
10524 : // MODIFIED:na
10525 : // RE-ENGINEERED na
10526 :
10527 : // PURPOSE OF THIS SUBROUTINE:
10528 : // For each Daylighting:Detailed zone finds the minimum solid angle subtended
10529 : // by interior windows through which daylight can pass from adjacent zones with
10530 : // exterior windows.
10531 :
10532 : // METHODOLOGY EMPLOYED:na
10533 : // REFERENCES:na
10534 : // Using/Aliasing
10535 :
10536 : // Locals
10537 : // SUBROUTINE ARGUMENT DEFINITIONS: na
10538 : // SUBROUTINE PARAMETER DEFINITIONS: na
10539 : // INTERFACE BLOCK SPECIFICATIONS: na
10540 : // DERIVED TYPE DEFINITIONS: na
10541 :
10542 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
10543 :
10544 : bool is_Triangle; // True if window is a triangle
10545 : bool is_Rectangle; // True if window is a rectangle
10546 : Real64 IntWinSolidAng; // Approximation to solid angle subtended by an interior window
10547 : // from a point a distance SQRT(zone floor area) away.
10548 62 : auto &W1 = state.dataDaylightingManager->CalcMinIntWinSolidAngsW1; // Window vertices
10549 62 : auto &W2 = state.dataDaylightingManager->CalcMinIntWinSolidAngsW2;
10550 62 : auto &W3 = state.dataDaylightingManager->CalcMinIntWinSolidAngsW3;
10551 62 : auto &WC = state.dataDaylightingManager->CalcMinIntWinSolidAngsWC; // Center point of window
10552 62 : auto &W21 = state.dataDaylightingManager->CalcMinIntWinSolidAngsW21; // Unit vectors from window vertex 2 to 1 and 2 to 3
10553 62 : auto &W23 = state.dataDaylightingManager->CalcMinIntWinSolidAngsW23;
10554 62 : auto &RREF = state.dataDaylightingManager->CalcMinIntWinSolidAngsRREF; // Location of a reference point in absolute coordinate system
10555 62 : auto &Ray = state.dataDaylightingManager->CalcMinIntWinSolidAngsRay; // Unit vector along ray from reference point to window center
10556 62 : auto &REFWC = state.dataDaylightingManager->CalcMinIntWinSolidAngsREFWC; // Vector from reference point to center of window
10557 62 : auto &WNORM = state.dataDaylightingManager->CalcMinIntWinSolidAngsWNORM; // Unit vector normal to window (pointing away from room)
10558 : Real64 HW; // Window height and width (m)
10559 : Real64 WW;
10560 : Real64 DIS; // Distance from ref point to window center (m)
10561 : Real64 COSB; // Cosine of angle between ray from ref pt to center of window
10562 : // and window outward normal
10563 :
10564 770 : for (int enclNum = 1; enclNum <= state.dataViewFactor->NumOfSolarEnclosures; ++enclNum) {
10565 708 : auto &thisEnclDaylight = state.dataDaylightingData->enclDaylight(enclNum);
10566 708 : thisEnclDaylight.MinIntWinSolidAng = 2.0 * DataGlobalConstants::Pi;
10567 708 : if (state.dataViewFactor->EnclSolInfo(enclNum).TotalEnclosureDaylRefPoints == 0) continue;
10568 286 : if (thisEnclDaylight.NumOfIntWinAdjEncls == 0) continue;
10569 8 : for (int IWin : state.dataViewFactor->EnclSolInfo(enclNum).SurfacePtr) {
10570 7 : if ((state.dataSurface->Surface(IWin).Class == SurfaceClass::Window) && (state.dataSurface->Surface(IWin).ExtBoundCond >= 1)) {
10571 : // This is an interior window in enclNum
10572 1 : int const winAdjEnclNum = state.dataSurface->Surface(state.dataSurface->Surface(IWin).ExtBoundCond).SolarEnclIndex;
10573 1 : bool IntWinNextToIntWinAdjZone = false; // True if an interior window is next to a zone with one or more exterior windows
10574 1 : for (int adjEnclNum : thisEnclDaylight.AdjIntWinEnclNums) {
10575 1 : if (winAdjEnclNum == adjEnclNum) {
10576 1 : IntWinNextToIntWinAdjZone = true;
10577 1 : break;
10578 : }
10579 : }
10580 1 : if (IntWinNextToIntWinAdjZone) {
10581 2 : for (int controlNum : thisEnclDaylight.daylightControlIndexes) {
10582 1 : auto &thisDaylightControl = state.dataDaylightingData->daylightControl(controlNum);
10583 2 : for (int IL = 1; IL <= thisDaylightControl.TotalDaylRefPoints; ++IL) {
10584 : // Reference point in absolute coordinate system
10585 1 : RREF = thisDaylightControl.DaylRefPtAbsCoord({1, 3}, IL);
10586 1 : is_Triangle = (state.dataSurface->Surface(IWin).Sides == 3);
10587 1 : is_Rectangle = (state.dataSurface->Surface(IWin).Sides == 4);
10588 1 : if (is_Rectangle) {
10589 : // Vertices of window numbered counter-clockwise starting at upper left as viewed
10590 : // from inside of room. Assumes original vertices are numbered counter-clockwise from
10591 : // upper left as viewed from outside.
10592 1 : W3 = state.dataSurface->Surface(IWin).Vertex(2);
10593 1 : W2 = state.dataSurface->Surface(IWin).Vertex(3);
10594 1 : W1 = state.dataSurface->Surface(IWin).Vertex(4);
10595 0 : } else if (is_Triangle) {
10596 0 : W3 = state.dataSurface->Surface(IWin).Vertex(2);
10597 0 : W2 = state.dataSurface->Surface(IWin).Vertex(3);
10598 0 : W1 = state.dataSurface->Surface(IWin).Vertex(1);
10599 : }
10600 : // Unit vectors from window vertex 2 to 1 and 2 to 3, center point of window,
10601 : // and vector from ref pt to center of window
10602 1 : W21 = W1 - W2;
10603 1 : W23 = W3 - W2;
10604 1 : HW = W21.magnitude();
10605 1 : WW = W23.magnitude();
10606 1 : if (is_Rectangle) {
10607 1 : WC = W2 + (W23 + W21) / 2.0;
10608 0 : } else if (is_Triangle) {
10609 0 : WC = W2 + (W23 + W21) / 3.0;
10610 : }
10611 : // Vector from ref point to center of window
10612 1 : REFWC = WC - RREF;
10613 1 : W21 /= HW;
10614 1 : W23 /= WW;
10615 : // Unit vector normal to window (pointing away from room)
10616 1 : WNORM = state.dataSurface->Surface(IWin).OutNormVec;
10617 : // Distance from ref point to center of window
10618 1 : DIS = REFWC.magnitude();
10619 : // Unit vector from ref point to center of window
10620 1 : Ray = REFWC / DIS;
10621 : // Cosine of angle between ray from ref pt to center of window and window outward normal
10622 1 : COSB = dot(WNORM, Ray);
10623 1 : if (COSB > 0.01765) { // 0 <= B < 89 deg
10624 : // Above test avoids case where ref point cannot receive daylight directly from the
10625 : // interior window
10626 1 : IntWinSolidAng = COSB * state.dataSurface->Surface(IWin).Area / (pow_2(DIS) + 0.001);
10627 1 : thisEnclDaylight.MinIntWinSolidAng = min(thisEnclDaylight.MinIntWinSolidAng, IntWinSolidAng);
10628 : }
10629 : } // End of loop over reference points
10630 : } // End of loop over daylighting controls
10631 : }
10632 : }
10633 : } // End of loop over surfaces in zone
10634 : } // End of loop over zones
10635 62 : }
10636 :
10637 124 : void CheckForGeometricTransform(EnergyPlusData &state, bool &doTransform, Real64 &OldAspectRatio, Real64 &NewAspectRatio)
10638 : {
10639 :
10640 : // SUBROUTINE INFORMATION:
10641 : // AUTHOR Linda Lawrie
10642 : // DATE WRITTEN February 2009
10643 : // MODIFIED na
10644 : // RE-ENGINEERED na
10645 :
10646 : // PURPOSE OF THIS SUBROUTINE:
10647 : // check for geometrytransform in the daylighting access for reference and map points
10648 :
10649 : // METHODOLOGY EMPLOYED:
10650 : // once reference points have been converted to WCS,
10651 : // change them to reflect a different aspect
10652 : // ratio for the entire building based on user input.
10653 :
10654 : // REFERENCES:
10655 : // na
10656 :
10657 : // Using/Aliasing
10658 : // Locals
10659 : // SUBROUTINE ARGUMENT DEFINITIONS:
10660 :
10661 : // SUBROUTINE PARAMETER DEFINITIONS:
10662 124 : static std::string const CurrentModuleObject("GeometryTransform");
10663 :
10664 : // INTERFACE BLOCK SPECIFICATIONS
10665 : // na
10666 :
10667 : // DERIVED TYPE DEFINITIONS
10668 : // na
10669 :
10670 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
10671 248 : Array1D_string cAlphas(1);
10672 248 : Array1D<Real64> rNumerics;
10673 : int NAlphas;
10674 : int NNum;
10675 : int IOStat;
10676 248 : std::string transformPlane;
10677 :
10678 : // begin execution
10679 : // get user input...
10680 124 : doTransform = false;
10681 124 : OldAspectRatio = 1.0;
10682 124 : NewAspectRatio = 1.0;
10683 :
10684 124 : if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject) == 1) {
10685 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
10686 : CurrentModuleObject,
10687 : 1,
10688 : cAlphas,
10689 : NAlphas,
10690 : rNumerics,
10691 : NNum,
10692 : IOStat,
10693 0 : state.dataIPShortCut->lNumericFieldBlanks,
10694 0 : state.dataIPShortCut->lAlphaFieldBlanks,
10695 0 : state.dataIPShortCut->cAlphaFieldNames,
10696 0 : state.dataIPShortCut->cNumericFieldNames);
10697 0 : OldAspectRatio = rNumerics(1);
10698 0 : NewAspectRatio = rNumerics(2);
10699 0 : transformPlane = cAlphas(1);
10700 0 : if (transformPlane != "XY") {
10701 0 : ShowWarningError(state,
10702 0 : CurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" + cAlphas(1) + "...ignored.");
10703 : }
10704 0 : doTransform = true;
10705 0 : state.dataSurface->AspectTransform = true;
10706 : }
10707 124 : if (state.dataSurface->WorldCoordSystem) {
10708 56 : doTransform = false;
10709 56 : state.dataSurface->AspectTransform = false;
10710 : }
10711 124 : }
10712 :
10713 20 : void WriteDaylightMapTitle(EnergyPlusData &state,
10714 : int const mapNum,
10715 : InputOutputFile &mapFile,
10716 : std::string const &mapName,
10717 : std::string const &environmentName,
10718 : int const ZoneNum,
10719 : std::string const &refPts,
10720 : Real64 const zcoord)
10721 : {
10722 : // SUBROUTINE INFORMATION:
10723 : // AUTHOR Greg Stark
10724 : // DATE WRITTEN Sept 2008
10725 : // MODIFIED na
10726 : // RE-ENGINEERED na
10727 :
10728 : // PURPOSE OF THIS SUBROUTINE:
10729 : // The purpose of the routine is to allow the daylighting map data to be written in various formats
10730 :
10731 : // must add correct number of commas at end
10732 60 : const auto fullmapName = fmt::format("{}:{}:{} Illuminance [lux] (Hourly)", state.dataHeatBal->Zone(ZoneNum).Name, environmentName, mapName);
10733 100 : print(mapFile,
10734 : "Date/Time{}{}{}{}{}{}\n",
10735 20 : state.dataDaylightingData->MapColSep,
10736 : fullmapName,
10737 20 : state.dataDaylightingData->MapColSep,
10738 : refPts,
10739 20 : state.dataDaylightingData->MapColSep,
10740 40 : state.dataDaylightingData->MapColSep);
10741 :
10742 20 : if (state.dataSQLiteProcedures->sqlite) {
10743 1 : state.dataSQLiteProcedures->sqlite->createSQLiteDaylightMapTitle(mapNum, fullmapName, environmentName, ZoneNum, refPts, zcoord);
10744 : }
10745 20 : }
10746 :
10747 2313 : } // namespace EnergyPlus::DaylightingManager
|