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 <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Fmath.hh>
53 : #include <ObjexxFCL/numeric.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Construction.hh>
57 : #include <EnergyPlus/Data/EnergyPlusData.hh>
58 : #include <EnergyPlus/DataDaylighting.hh>
59 : #include <EnergyPlus/DataDaylightingDevices.hh>
60 : #include <EnergyPlus/DataHeatBalance.hh>
61 : #include <EnergyPlus/DataIPShortCuts.hh>
62 : #include <EnergyPlus/DataSurfaces.hh>
63 : #include <EnergyPlus/DataSystemVariables.hh>
64 : #include <EnergyPlus/DaylightingDevices.hh>
65 : #include <EnergyPlus/DaylightingManager.hh>
66 : #include <EnergyPlus/DisplayRoutines.hh>
67 : #include <EnergyPlus/FluidProperties.hh>
68 : #include <EnergyPlus/General.hh>
69 : #include <EnergyPlus/HeatBalanceInternalHeatGains.hh>
70 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
71 : #include <EnergyPlus/OutputProcessor.hh>
72 : #include <EnergyPlus/SolarShading.hh>
73 : #include <EnergyPlus/UtilityRoutines.hh>
74 :
75 : namespace EnergyPlus {
76 :
77 : namespace DaylightingDevices {
78 :
79 : // MODULE INFORMATION:
80 : // AUTHOR Peter Graham Ellis
81 : // DATE WRITTEN May 2003
82 : // MODIFIED PGE, Aug 2003: Added daylighting shelves.
83 : // RE-ENGINEERED na
84 :
85 : // PURPOSE OF THIS MODULE:
86 : // Simulates daylighting devices, namely tubular daylighting devices (a.k.a. light pipes, sun pipes, or
87 : // tubular skylights) and daylighting shelves (a.k.a. light shelves).
88 :
89 : // METHODOLOGY EMPLOYED:
90 : // TUBULAR DAYLIGHTING DEVICE
91 : // A tubular daylighting device (TDD) is constructed of three components: a dome, a pipe, and a diffuser.
92 : // The dome and diffuser are treated as special window surfaces to take advantage of many of the already
93 : // existing daylighting and heat transfer routines. Together the dome and diffuser become "receiver"
94 : // and "transmitter", i.e. radiation entering the dome ends up exiting the diffuser. The geometry and
95 : // construction of the pipe and the constructions of the window surfaces determine the transmittance of
96 : // the TDD.
97 : // The main task of the module is to determine the total transmittance of the TDD for several
98 : // types of radiation, including visible beam, solar beam, solar isotropic, and solar anisotropic sky.
99 : // The fundamental building block for each type of radiation is the transmittance of a beam or ray of
100 : // radiation (visible or solar) at a given incident angle. This transmittance is calculated and
101 : // tabulated for each TDD during initialization using a numerical integral based on the analytical
102 : // solution derived by Swift and Smith. Diffuse transmittances are subsequently calculated by integrating
103 : // discrete rays over the viewable area.
104 : // There are three parts to the TDD model:
105 : // 1. Daylighting
106 : // 2. Solar gain
107 : // 3. Thermal conductive/convective gain
108 : // The daylighting simulation uses the visible beam transmittance to find the amount of direct beam
109 : // solar illuminance that enters the zone. The visible beam transmittance is also used for calculating
110 : // the contribution of each discrete ray from a differential area during a comprehensive sky/ground
111 : // integration.
112 : // The heat balance simulation handles both the solar gain and thermal conductive/convective gain.
113 : // Although visible and solar radiation are similar, solar gain is simulated very differently from the
114 : // daylighting illuminance calculations. The gain from direct beam solar is found using the
115 : // solar beam transmittance. The diffuse solar, however, is more complicated. A sky/ground integration
116 : // is NOT performed. Instead anisotropic sky view factor multipliers (SurfAnisoSkyMult) are calculated for
117 : // each surface. The diffuse sky/ground transmittance of the TDD is solved using a modification of the
118 : // SurfAnisoSkyMult. The ground radiation transmittance and anisotropic sky transmittance are found separately.
119 : // See CalcTDDTransSolIso, CalcTDDTransSolHorizon, CalcTDDTransSolAniso below.
120 : // For thermal conductive/convective gain, TDDs are treated as one big object with an effective R value.
121 : // The outside face temperature of the dome and the inside face temperature of the diffuser are calculated
122 : // with the outside and inside heat balances respectively. The temperatures are then copied to the inside
123 : // face of the dome and the outside face of the diffuser. Normal exterior and interior convection and IR
124 : // radiation exchange occurs for both surfaces.
125 : // Solar radiation that is not transmitted through the pipe is absorbed and distributed among the transition
126 : // zones that the pipe passes through between dome and diffuser. The heat is distributed proportionate to
127 : // the length of the zone. Any exterior length of pipe also receives a proportionate amount of heat, but
128 : // this is lost to the outside.
129 : // REFERENCES:
130 : // Ellis, P. G., and Strand, R. K. Paper to be published.
131 : // Swift, P. D., and Smith, G. B. "Cylindrical Mirror Light Pipes",
132 : // Solar Energy Materials and Solar Cells 36 (1995), pp. 159-168.
133 : // DAYLIGHTING SHELVES
134 : // A daylighting shelf is constructed of up to three components: a window, an inside shelf, and an outside
135 : // shelf. Both inside shelf and outside shelf are optional, but if neither is specified, nothing happens.
136 : // The window must be divided into two window surfaces: an upper window and a lower window. The upper
137 : // window interacts with the daylighting shelf but the lower window does not, except to receive shading from
138 : // the outside shelf. The inside shelf, if specified, acts to reflect all transmitted light from the
139 : // upper window onto the ceiling of the zone as diffuse light. The outside shelf, if specified, changes
140 : // the total amount of light incident on the window. All light reflected from the outside shelf also goes
141 : // onto the zone ceiling.
142 : // Most of the work for daylighting shelves is actually done in DaylightingManager.cc, SolarShading.cc,
143 : // and HeatBalanceSurfaceManager.cc. The main task of the module is to get the input and initialize the
144 : // shelf. The biggest part of initialization is calculating the window view factor to the outside shelf.
145 : // It is up to the user to reduce the window view factor to ground accordingly.
146 : // The inside shelf is modeled in both daylighting and heat balance simulations by converting all light
147 : // transmitted by the upper window into diffuse upgoing flux. No beam or downgoing flux can pass the end
148 : // of the shelf regardless of the shelf's position or orientation. Since it is defined as a partition,
149 : // the inside shelf is essentially the same as an internal mass surface. The initialization doubles the
150 : // surface area so that both sides are exposed to the zone air. All beam solar transmitted by the window
151 : // is absorbed in one side of the shelf, i.e. half of the doubled area.
152 : // The outside shelf is modeled in the daylighting simulation after the detailed sky/ground integration has
153 : // been completed. Since exterior surfaces currently do not reflect or have a luminance in the Daylighting
154 : // Manager, the shelf just serves to block part of the ground luminance. The luminance of the shelf itself
155 : // is added as a lump sum based on the view factor to the shelf, the sunlit fraction, the reflectance of the
156 : // shelf construction, and the sun and sky illuminance on the shelf. All the luminance is added to the
157 : // diffuse upgoing flux. The shelf view factor to sky is assumed to be 1.0 for lack of better information.
158 : // The outside shelf is treated similarly in the heat balance simulation, but here the shelf view factor to
159 : // sky is conveniently given by SurfAnisoSkyMult. NOTE: The solar shading code was modified to allow sunlit
160 : // fraction, sunlit area, SurfAnisoSkyMult, etc. to be calculated for attached shading surfaces.
161 : // Future shelf model improvements:
162 : // 1. Allow beam and downgoing flux to pass the end of the inside shelf depending on actual shelf goemetry.
163 : // 2. Reduce outside shelf view factor to sky (for daylighting) by taking into account anisotropic sky
164 : // distribution and shading, i.e. the daylighting equivalent of SurfAnisoSkyMult.
165 : // 3. Expand view factor to shelf calculation to handle more complicated geometry.
166 : // REFERENCES:
167 : // Mills, A. F. Heat and Mass Transfer, 1995, p. 499. (Shape factor for adjacent rectangles.)
168 :
169 : // Using/Aliasing
170 : using DataSurfaces::ExternalEnvironment;
171 : using DataSurfaces::SurfaceClass;
172 :
173 771 : void InitDaylightingDevices(EnergyPlusData &state)
174 : {
175 :
176 : // SUBROUTINE INFORMATION:
177 : // AUTHOR Peter Graham Ellis
178 : // DATE WRITTEN May 2003
179 : // MODIFIED PGE, Aug 2003: Added daylighting shelves.
180 : // RE-ENGINEERED na
181 :
182 : // PURPOSE OF THIS SUBROUTINE:
183 : // This subroutine initializes all daylighting device: TDD pipes and daylighting shelves.
184 : // This is only called once at the beginning of the simulation under the BeginSimFlag.
185 :
186 : // METHODOLOGY EMPLOYED:
187 : // Daylighting and thermal variables are calculated. BeamTrans/COSAngle table is calculated.
188 :
189 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
190 : int PipeNum; // TDD pipe object number
191 : int StoredNum; // Stored TDD pipe object number
192 : int AngleNum;
193 : int TZoneNum;
194 : int Loop;
195 : Real64 Theta; // Angle of entry in degrees, 0 is parallel to pipe axis
196 : Real64 dTheta; // Angle increment
197 : Real64 Reflectance; // Visible or solar reflectance of surface
198 : Real64 SumTZoneLengths;
199 : bool Found;
200 : int ShelfNum; // Daylighting shelf object number
201 : int ShelfSurf; // Daylighting shelf surface number
202 : int WinSurf; // Window surface number
203 :
204 771 : int NumStored(0); // Counter for number of pipes stored as they are calculated
205 :
206 9 : struct TDDPipeStoredData
207 : {
208 : // Members
209 : Real64 AspectRatio; // Aspect ratio, length / diameter
210 : Real64 Reflectance; // Reflectance of surface
211 : Array1D<Real64> TransBeam; // Table of beam transmittance vs. cosine angle
212 :
213 : // Default Constructor
214 1 : TDDPipeStoredData() : AspectRatio(0.0), Reflectance(0.0), TransBeam(DataDaylightingDevices::NumOfAngles, 0.0)
215 : {
216 1 : }
217 : };
218 :
219 : // Object Data
220 1542 : Array1D<TDDPipeStoredData> TDDPipeStored;
221 :
222 : // Initialize tubular daylighting devices (TDDs)
223 771 : GetTDDInput(state);
224 :
225 771 : if ((int)state.dataDaylightingDevicesData->TDDPipe.size() > 0) {
226 1 : DisplayString(state, "Initializing Tubular Daylighting Devices");
227 : // Setup COSAngle list for all TDDs
228 1 : state.dataDaylightingDevices->COSAngle(1) = 0.0;
229 1 : state.dataDaylightingDevices->COSAngle(DataDaylightingDevices::NumOfAngles) = 1.0;
230 :
231 1 : dTheta = 90.0 * DataGlobalConstants::DegToRadians / (DataDaylightingDevices::NumOfAngles - 1.0);
232 1 : Theta = 90.0 * DataGlobalConstants::DegToRadians;
233 18 : for (AngleNum = 2; AngleNum <= DataDaylightingDevices::NumOfAngles - 1; ++AngleNum) {
234 17 : Theta -= dTheta;
235 17 : state.dataDaylightingDevices->COSAngle(AngleNum) = std::cos(Theta);
236 : } // AngleNum
237 :
238 1 : TDDPipeStored.allocate((int)state.dataDaylightingDevicesData->TDDPipe.size() * 2);
239 :
240 3 : for (PipeNum = 1; PipeNum <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++PipeNum) {
241 : // Initialize optical properties
242 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).AspectRatio =
243 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TotLength / state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diameter;
244 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).ReflectVis =
245 2 : 1.0 - state.dataConstruction->Construct(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Construction).InsideAbsorpVis;
246 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).ReflectSol =
247 2 : 1.0 - state.dataConstruction->Construct(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Construction).InsideAbsorpSolar;
248 :
249 : // Calculate the beam transmittance table for visible and solar spectrum
250 : // First time thru use the visible reflectance
251 2 : Reflectance = state.dataDaylightingDevicesData->TDDPipe(PipeNum).ReflectVis;
252 6 : for (Loop = 1; Loop <= 2; ++Loop) {
253 : // For computational efficiency, search stored pipes to see if an identical pipe has already been calculated
254 4 : Found = false;
255 6 : for (StoredNum = 1; StoredNum <= NumStored; ++StoredNum) {
256 4 : if (TDDPipeStored(StoredNum).AspectRatio != state.dataDaylightingDevicesData->TDDPipe(PipeNum).AspectRatio) continue;
257 2 : if (TDDPipeStored(StoredNum).Reflectance == Reflectance) {
258 2 : Found = true; // StoredNum points to the matching TDDPipeStored
259 2 : break;
260 : }
261 : } // StoredNum
262 :
263 4 : if (!Found) { // Not yet calculated
264 :
265 : // Add a new pipe to TDDPipeStored
266 2 : ++NumStored;
267 2 : TDDPipeStored(NumStored).AspectRatio = state.dataDaylightingDevicesData->TDDPipe(PipeNum).AspectRatio;
268 2 : TDDPipeStored(NumStored).Reflectance = Reflectance;
269 :
270 : // Set beam transmittances for 0 and 90 degrees
271 2 : TDDPipeStored(NumStored).TransBeam(1) = 0.0;
272 2 : TDDPipeStored(NumStored).TransBeam(DataDaylightingDevices::NumOfAngles) = 1.0;
273 :
274 : // Calculate intermediate beam transmittances between 0 and 90 degrees
275 2 : Theta = 90.0 * DataGlobalConstants::DegToRadians;
276 36 : for (AngleNum = 2; AngleNum <= DataDaylightingDevices::NumOfAngles - 1; ++AngleNum) {
277 34 : Theta -= dTheta;
278 34 : TDDPipeStored(NumStored).TransBeam(AngleNum) =
279 34 : CalcPipeTransBeam(Reflectance, state.dataDaylightingDevicesData->TDDPipe(PipeNum).AspectRatio, Theta);
280 : } // AngleNum
281 :
282 2 : StoredNum = NumStored;
283 : }
284 :
285 : // Assign stored values to TDDPipe
286 4 : if (Loop == 1) { // Visible
287 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeTransVisBeam = TDDPipeStored(StoredNum).TransBeam;
288 : } else { // Solar
289 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeTransSolBeam = TDDPipeStored(StoredNum).TransBeam;
290 : }
291 :
292 : // Second time thru use the solar reflectance
293 4 : Reflectance = state.dataDaylightingDevicesData->TDDPipe(PipeNum).ReflectSol;
294 : } // Loop
295 :
296 : // Calculate the solar isotropic diffuse and horizon transmittances. These values are constant for a given TDD.
297 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolIso = CalcTDDTransSolIso(state, PipeNum);
298 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolHorizon = CalcTDDTransSolHorizon(state, PipeNum);
299 :
300 : // Initialize thermal properties
301 2 : SumTZoneLengths = 0.0;
302 4 : for (TZoneNum = 1; TZoneNum <= state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones; ++TZoneNum) {
303 2 : SumTZoneLengths += state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength(TZoneNum);
304 :
305 4 : SetupZoneInternalGain(state,
306 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZone(TZoneNum),
307 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name,
308 : DataHeatBalance::IntGainType::DaylightingDeviceTubular,
309 2 : &state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneHeatGain(TZoneNum));
310 :
311 : } // TZoneNum
312 :
313 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).ExtLength =
314 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TotLength - SumTZoneLengths;
315 :
316 : // Setup report variables: CurrentModuleObject='DaylightingDevice:Tubular'
317 8 : SetupOutputVariable(state,
318 : "Tubular Daylighting Device Transmitted Solar Radiation Rate",
319 : OutputProcessor::Unit::W,
320 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransmittedSolar,
321 : OutputProcessor::SOVTimeStepType::Zone,
322 : OutputProcessor::SOVStoreType::Average,
323 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
324 8 : SetupOutputVariable(state,
325 : "Tubular Daylighting Device Pipe Absorbed Solar Radiation Rate",
326 : OutputProcessor::Unit::W,
327 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeAbsorbedSolar,
328 : OutputProcessor::SOVTimeStepType::Zone,
329 : OutputProcessor::SOVStoreType::Average,
330 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
331 8 : SetupOutputVariable(state,
332 : "Tubular Daylighting Device Heat Gain Rate",
333 : OutputProcessor::Unit::W,
334 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).HeatGain,
335 : OutputProcessor::SOVTimeStepType::Zone,
336 : OutputProcessor::SOVStoreType::Average,
337 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
338 8 : SetupOutputVariable(state,
339 : "Tubular Daylighting Device Heat Loss Rate",
340 : OutputProcessor::Unit::W,
341 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).HeatLoss,
342 : OutputProcessor::SOVTimeStepType::Zone,
343 : OutputProcessor::SOVStoreType::Average,
344 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
345 :
346 8 : SetupOutputVariable(state,
347 : "Tubular Daylighting Device Beam Solar Transmittance",
348 : OutputProcessor::Unit::None,
349 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolBeam,
350 : OutputProcessor::SOVTimeStepType::Zone,
351 : OutputProcessor::SOVStoreType::Average,
352 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
353 8 : SetupOutputVariable(state,
354 : "Tubular Daylighting Device Beam Visible Transmittance",
355 : OutputProcessor::Unit::None,
356 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransVisBeam,
357 : OutputProcessor::SOVTimeStepType::Zone,
358 : OutputProcessor::SOVStoreType::Average,
359 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
360 8 : SetupOutputVariable(state,
361 : "Tubular Daylighting Device Diffuse Solar Transmittance",
362 : OutputProcessor::Unit::None,
363 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolDiff,
364 : OutputProcessor::SOVTimeStepType::Zone,
365 : OutputProcessor::SOVStoreType::Average,
366 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
367 8 : SetupOutputVariable(state,
368 : "Tubular Daylighting Device Diffuse Visible Transmittance",
369 : OutputProcessor::Unit::None,
370 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransVisDiff,
371 : OutputProcessor::SOVTimeStepType::Zone,
372 : OutputProcessor::SOVStoreType::Average,
373 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
374 :
375 : } // PipeNum
376 :
377 1 : TDDPipeStored.deallocate();
378 : }
379 :
380 : // Initialize daylighting shelves
381 771 : GetShelfInput(state);
382 :
383 771 : if ((int)state.dataDaylightingDevicesData->Shelf.size() > 0) DisplayString(state, "Initializing Light Shelf Daylighting Devices");
384 :
385 772 : for (ShelfNum = 1; ShelfNum <= (int)state.dataDaylightingDevicesData->Shelf.size(); ++ShelfNum) {
386 1 : WinSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).Window;
387 :
388 1 : ShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).InSurf;
389 1 : if (ShelfSurf > 0) {
390 : // Double surface area so that both sides of the shelf are treated as internal mass
391 1 : state.dataSurface->Surface(ShelfSurf).Area *= 2.0;
392 : }
393 :
394 1 : ShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf;
395 1 : if (ShelfSurf > 0) {
396 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).OutReflectVis =
397 1 : 1.0 - state.dataConstruction->Construct(state.dataDaylightingDevicesData->Shelf(ShelfNum).Construction).OutsideAbsorpVis;
398 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).OutReflectSol =
399 1 : 1.0 - state.dataConstruction->Construct(state.dataDaylightingDevicesData->Shelf(ShelfNum).Construction).OutsideAbsorpSolar;
400 :
401 1 : if (state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor < 0) CalcViewFactorToShelf(state, ShelfNum);
402 :
403 3 : adjustViewFactorsWithShelf(state,
404 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor,
405 1 : state.dataSurface->Surface(WinSurf).ViewFactorSky,
406 1 : state.dataSurface->Surface(WinSurf).ViewFactorGround,
407 : WinSurf,
408 : ShelfNum);
409 :
410 : // Report calculated view factor so that user knows what to make the view factor to ground
411 1 : if (!state.dataDaylightingDevices->ShelfReported) {
412 1 : print(state.files.eio,
413 1 : "! <Shelf Details>,Name,View Factor to Outside Shelf,Window Name,Window View Factor to Sky,Window View Factor to Ground\n");
414 1 : state.dataDaylightingDevices->ShelfReported = true;
415 : }
416 6 : print(state.files.eio,
417 : "{},{:.2R},{},{:.2R},{:.2R}\n",
418 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).Name,
419 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor,
420 1 : state.dataSurface->Surface(WinSurf).Name,
421 1 : state.dataSurface->Surface(WinSurf).ViewFactorSky,
422 2 : state.dataSurface->Surface(WinSurf).ViewFactorGround);
423 : // CALL SetupOutputVariable(state, 'View Factor To Outside Shelf []', &
424 : // Shelf(ShelfNum)%ViewFactor,'Zone','Average',Shelf(ShelfNum)%Name)
425 : }
426 : }
427 :
428 : // Warning that if Calculate Solar Reflection From Exterior Surfaces = Yes in Building input, then
429 : // solar reflection calculated from obstructions will not be used in daylighting shelf or tubular device
430 : // calculation
431 :
432 780 : if (state.dataSurface->CalcSolRefl &&
433 18 : ((int)state.dataDaylightingDevicesData->TDDPipe.size() > 0 || (int)state.dataDaylightingDevicesData->Shelf.size() > 0)) {
434 0 : ShowWarningError(state, "InitDaylightingDevices: Solar Distribution Model includes Solar Reflection calculations;");
435 0 : ShowContinueError(state, "the resulting reflected solar values will not be used in the");
436 0 : ShowContinueError(state, "DaylightingDevice:Shelf or DaylightingDevice:Tubular calculations.");
437 : }
438 771 : }
439 :
440 771 : void GetTDDInput(EnergyPlusData &state)
441 : {
442 :
443 : // SUBROUTINE INFORMATION:
444 : // AUTHOR Peter Graham Ellis
445 : // DATE WRITTEN May 2003
446 : // MODIFIED na
447 : // RE-ENGINEERED na
448 :
449 : // PURPOSE OF THIS SUBROUTINE:
450 : // Gets the input for TDD pipes and does some error checking.
451 :
452 : // METHODOLOGY EMPLOYED:
453 : // Standard EnergyPlus methodology.
454 :
455 : // Using/Aliasing
456 :
457 : using General::SafeDivide;
458 :
459 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
460 : int IOStatus; // Used in GetObjectItem
461 : int NumAlphas; // Number of Alphas for each GetObjectItem call
462 : int NumNumbers; // Number of Numbers for each GetObjectItem call
463 : int PipeNum; // TDD pipe object number
464 : int SurfNum; // Dome or diffuser surface
465 : int TZoneNum; // Transition zone loop
466 1542 : std::string TZoneName; // Transition zone name
467 : Real64 PipeArea;
468 :
469 771 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
470 :
471 771 : cCurrentModuleObject = "DaylightingDevice:Tubular";
472 771 : int NumOfTDDPipes = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
473 :
474 771 : if (NumOfTDDPipes > 0) {
475 1 : state.dataDaylightingDevicesData->TDDPipe.allocate(NumOfTDDPipes);
476 :
477 3 : for (PipeNum = 1; PipeNum <= NumOfTDDPipes; ++PipeNum) {
478 14 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
479 : cCurrentModuleObject,
480 : PipeNum,
481 2 : state.dataIPShortCut->cAlphaArgs,
482 : NumAlphas,
483 2 : state.dataIPShortCut->rNumericArgs,
484 : NumNumbers,
485 : IOStatus,
486 2 : state.dataIPShortCut->lNumericFieldBlanks,
487 2 : state.dataIPShortCut->lAlphaFieldBlanks,
488 2 : state.dataIPShortCut->cAlphaFieldNames,
489 2 : state.dataIPShortCut->cNumericFieldNames);
490 4 : UtilityRoutines::IsNameEmpty(
491 4 : state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, state.dataDaylightingDevices->GetTDDInputErrorsFound);
492 : // Pipe name
493 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name = state.dataIPShortCut->cAlphaArgs(1);
494 :
495 : // Get TDD:DOME object
496 2 : SurfNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataSurface->Surface);
497 :
498 2 : if (SurfNum == 0) {
499 0 : ShowSevereError(state,
500 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Dome " +
501 0 : state.dataIPShortCut->cAlphaArgs(2) + " not found.");
502 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
503 : } else {
504 2 : if (FindTDDPipe(state, SurfNum) > 0) {
505 0 : ShowSevereError(state,
506 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Dome " +
507 0 : state.dataIPShortCut->cAlphaArgs(2) + " is referenced by more than one TDD.");
508 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
509 : }
510 :
511 2 : if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::TDD_Dome) {
512 0 : ShowSevereError(state,
513 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Dome " +
514 0 : state.dataIPShortCut->cAlphaArgs(2) + " is not of surface type TubularDaylightDome.");
515 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
516 : }
517 :
518 2 : if (state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).TotGlassLayers > 1) {
519 0 : ShowSevereError(state,
520 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Dome " +
521 0 : state.dataIPShortCut->cAlphaArgs(2) + " construction (" +
522 0 : state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).Name +
523 : ") must have only 1 glass layer.");
524 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
525 : }
526 :
527 2 : if (state.dataSurface->Surface(SurfNum).HasShadeControl) {
528 0 : ShowSevereError(state,
529 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Dome " +
530 0 : state.dataIPShortCut->cAlphaArgs(2) + " must not have a shading control.");
531 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
532 : }
533 :
534 2 : if (state.dataSurface->Surface(SurfNum).FrameDivider > 0) {
535 0 : ShowSevereError(state,
536 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Dome " +
537 0 : state.dataIPShortCut->cAlphaArgs(2) + " must not have a frame/divider.");
538 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
539 : }
540 :
541 2 : if (state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).WindowTypeEQL) {
542 0 : ShowSevereError(state,
543 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Dome " +
544 0 : state.dataIPShortCut->cAlphaArgs(2) + " Equivalent Layer Window is not supported.");
545 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
546 : }
547 : // Window multiplier is already handled in SurfaceGeometry.cc
548 :
549 2 : if (!state.dataSurface->Surface(SurfNum).ExtSolar) {
550 0 : ShowWarningError(state,
551 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Dome " +
552 0 : state.dataIPShortCut->cAlphaArgs(2) + " is not exposed to exterior radiation.");
553 : }
554 :
555 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome = SurfNum;
556 2 : state.dataSurface->SurfWinTDDPipeNum(SurfNum) = PipeNum;
557 : }
558 :
559 : // Get TDD:DIFFUSER object
560 2 : SurfNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataSurface->Surface);
561 :
562 2 : if (SurfNum == 0) {
563 0 : ShowSevereError(state,
564 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Diffuser " +
565 0 : state.dataIPShortCut->cAlphaArgs(3) + " not found.");
566 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
567 : } else {
568 2 : if (FindTDDPipe(state, SurfNum) > 0) {
569 0 : ShowSevereError(state,
570 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Diffuser " +
571 0 : state.dataIPShortCut->cAlphaArgs(3) + " is referenced by more than one TDD.");
572 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
573 : }
574 :
575 2 : if (state.dataSurface->SurfWinOriginalClass(SurfNum) != SurfaceClass::TDD_Diffuser) {
576 0 : ShowSevereError(state,
577 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Diffuser " +
578 0 : state.dataIPShortCut->cAlphaArgs(3) + " is not of surface type TubularDaylightDiffuser.");
579 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
580 : }
581 :
582 2 : if (state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).TotGlassLayers > 1) {
583 0 : ShowSevereError(state,
584 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Diffuser " +
585 0 : state.dataIPShortCut->cAlphaArgs(3) + " construction (" +
586 0 : state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).Name +
587 : ") must have only 1 glass layer.");
588 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
589 : }
590 :
591 2 : if (state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).TransDiff <= 1.0e-10) {
592 0 : ShowSevereError(state,
593 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Diffuser " +
594 0 : state.dataIPShortCut->cAlphaArgs(3) + " construction (" +
595 0 : state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).Name +
596 : ") invalid value.");
597 0 : ShowContinueError(state,
598 0 : format("Diffuse solar transmittance of construction [{:.4R}] too small for calculations.",
599 0 : state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).TransDiff));
600 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
601 : }
602 :
603 4 : if (state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome > 0 &&
604 4 : std::abs(state.dataSurface->Surface(SurfNum).Area -
605 2 : state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Area) > 0.1) {
606 0 : if (SafeDivide(std::abs(state.dataSurface->Surface(SurfNum).Area -
607 0 : state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Area),
608 0 : state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Area) >
609 : 0.1) { // greater than 10%
610 0 : ShowSevereError(state,
611 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
612 : ": Dome and diffuser areas are significantly different (>10%).");
613 0 : ShowContinueError(state,
614 0 : format("...Diffuser Area=[{:.4R}]; Dome Area=[{:.4R}].",
615 0 : state.dataSurface->Surface(SurfNum).Area,
616 0 : state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Area));
617 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
618 : } else {
619 0 : ShowWarningError(state,
620 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
621 : ": Dome and diffuser areas differ by > .1 m2.");
622 0 : ShowContinueError(state,
623 0 : format("...Diffuser Area=[{:.4R}]; Dome Area=[{:.4R}].",
624 0 : state.dataSurface->Surface(SurfNum).Area,
625 0 : state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Area));
626 : }
627 : }
628 :
629 2 : if (state.dataSurface->Surface(SurfNum).HasShadeControl) {
630 0 : ShowSevereError(state,
631 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Diffuser " +
632 0 : state.dataIPShortCut->cAlphaArgs(3) + " must not have a shading control.");
633 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
634 : }
635 :
636 2 : if (state.dataSurface->Surface(SurfNum).FrameDivider > 0) {
637 0 : ShowSevereError(state,
638 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Diffuser " +
639 0 : state.dataIPShortCut->cAlphaArgs(3) + " must not have a frame/divider.");
640 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
641 : }
642 :
643 2 : if (state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).WindowTypeEQL) {
644 0 : ShowSevereError(state,
645 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Diffuser " +
646 0 : state.dataIPShortCut->cAlphaArgs(2) + " Equivalent Layer Window is not supported.");
647 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
648 : }
649 :
650 : // Window multiplier is already handled in SurfaceGeometry.cc
651 :
652 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diffuser = SurfNum;
653 2 : state.dataSurface->SurfWinTDDPipeNum(SurfNum) = PipeNum;
654 : }
655 :
656 : // Construction
657 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Construction =
658 2 : UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataConstruction->Construct);
659 :
660 2 : if (state.dataDaylightingDevicesData->TDDPipe(PipeNum).Construction == 0) {
661 0 : ShowSevereError(state,
662 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Pipe construction " +
663 0 : state.dataIPShortCut->cAlphaArgs(4) + " not found.");
664 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
665 : } else {
666 2 : state.dataConstruction->Construct(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Construction).IsUsed = true;
667 : }
668 :
669 2 : if (state.dataIPShortCut->rNumericArgs(1) > 0) {
670 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diameter = state.dataIPShortCut->rNumericArgs(1);
671 : } else {
672 0 : ShowSevereError(
673 0 : state, cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Pipe diameter must be greater than zero.");
674 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
675 : }
676 :
677 2 : PipeArea = 0.25 * DataGlobalConstants::Pi * pow_2(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diameter);
678 4 : if (state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome > 0 &&
679 2 : std::abs(PipeArea - state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Area) > 0.1) {
680 0 : if (SafeDivide(std::abs(PipeArea - state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Area),
681 0 : state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Area) >
682 : 0.1) { // greater than 10%
683 0 : ShowSevereError(state,
684 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
685 : ": Pipe and dome/diffuser areas are significantly different (>10%).");
686 0 : ShowContinueError(state,
687 0 : format("...Pipe Area=[{:.4R}]; Dome/Diffuser Area=[{:.4R}].",
688 : PipeArea,
689 0 : state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Area));
690 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
691 : } else {
692 0 : ShowWarningError(state,
693 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
694 : ": Pipe and dome/diffuser areas differ by > .1 m2.");
695 0 : ShowContinueError(state,
696 0 : format("...Pipe Area=[{:.4R}]; Dome/Diffuser Area=[{:.4R}].",
697 : PipeArea,
698 0 : state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Area));
699 : }
700 : }
701 :
702 2 : if (state.dataIPShortCut->rNumericArgs(2) > 0) {
703 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TotLength = state.dataIPShortCut->rNumericArgs(2);
704 : } else {
705 0 : ShowSevereError(state,
706 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Pipe length must be greater than zero.");
707 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
708 : }
709 :
710 2 : if (state.dataIPShortCut->rNumericArgs(3) > 0) {
711 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).Reff = state.dataIPShortCut->rNumericArgs(3);
712 : } else {
713 0 : ShowSevereError(state,
714 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
715 : ": Effective thermal resistance (R value) must be greater than zero.");
716 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
717 : }
718 :
719 : // Transition zones
720 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones = NumAlphas - 4;
721 :
722 2 : if (state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones < 1) {
723 0 : ShowWarningError(state,
724 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
725 : ": No transition zones specified. All pipe absorbed solar goes to exterior.");
726 2 : } else if (state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones > DataDaylightingDevices::MaxTZones) {
727 0 : ShowSevereError(state,
728 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
729 : ": Maximum number of transition zones exceeded.");
730 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
731 : } else {
732 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZone.allocate(state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones);
733 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength.allocate(
734 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones);
735 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneHeatGain.allocate(
736 4 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones);
737 :
738 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZone = 0;
739 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength = 0.0;
740 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneHeatGain = 0.0;
741 :
742 4 : for (TZoneNum = 1; TZoneNum <= state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones; ++TZoneNum) {
743 2 : TZoneName = state.dataIPShortCut->cAlphaArgs(TZoneNum + 4);
744 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZone(TZoneNum) =
745 2 : UtilityRoutines::FindItemInList(TZoneName, state.dataHeatBal->Zone);
746 2 : if (state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZone(TZoneNum) == 0) {
747 0 : ShowSevereError(state,
748 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Transition zone " + TZoneName +
749 : " not found.");
750 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
751 : }
752 :
753 2 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength(TZoneNum) = state.dataIPShortCut->rNumericArgs(TZoneNum + 3);
754 2 : if (state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength(TZoneNum) < 0) {
755 0 : ShowSevereError(state,
756 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Transition zone length for " +
757 0 : TZoneName + " must be zero or greater.");
758 0 : state.dataDaylightingDevices->GetTDDInputErrorsFound = true;
759 : }
760 : } // TZoneNum
761 : }
762 :
763 : } // PipeNum
764 :
765 1 : if (state.dataDaylightingDevices->GetTDDInputErrorsFound) ShowFatalError(state, "Errors in DaylightingDevice:Tubular input.");
766 1 : state.dataDaylightingManager->TDDTransVisBeam.allocate(24, NumOfTDDPipes);
767 1 : state.dataDaylightingManager->TDDFluxInc.allocate(24, 4, NumOfTDDPipes);
768 1 : state.dataDaylightingManager->TDDFluxTrans.allocate(24, 4, NumOfTDDPipes);
769 3 : for (int tddNum = 1; tddNum <= NumOfTDDPipes; ++tddNum) {
770 50 : for (int hr = 1; hr <= 24; ++hr) {
771 48 : state.dataDaylightingManager->TDDTransVisBeam(hr, tddNum) = 0.0;
772 240 : for (int iSky = 1; iSky <= 4; ++iSky) {
773 192 : state.dataDaylightingManager->TDDFluxInc(hr, iSky, tddNum) = 0.0;
774 192 : state.dataDaylightingManager->TDDFluxTrans(hr, iSky, tddNum) = 0.0;
775 : }
776 : }
777 : }
778 : }
779 771 : }
780 :
781 771 : void GetShelfInput(EnergyPlusData &state)
782 : {
783 :
784 : // SUBROUTINE INFORMATION:
785 : // AUTHOR Peter Graham Ellis
786 : // DATE WRITTEN August 2003
787 : // MODIFIED na
788 : // RE-ENGINEERED na
789 :
790 : // PURPOSE OF THIS SUBROUTINE:
791 : // Gets the input for light shelves and does some error checking.
792 :
793 : // METHODOLOGY EMPLOYED:
794 : // Standard EnergyPlus methodology.
795 :
796 : // Using/Aliasing
797 :
798 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
799 : int IOStatus; // Used in GetObjectItem
800 : int NumAlphas; // Number of Alphas for each GetObjectItem call
801 : int NumNumbers; // Number of Numbers for each GetObjectItem call
802 : int ShelfNum; // Daylighting shelf object number
803 : int SurfNum; // Window, inside, or outside shelf surfaces
804 : int ConstrNum; // Outside shelf construction object number
805 :
806 771 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
807 :
808 771 : cCurrentModuleObject = "DaylightingDevice:Shelf";
809 771 : int NumOfShelf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
810 :
811 771 : if (NumOfShelf > 0) {
812 1 : state.dataDaylightingDevicesData->Shelf.allocate(NumOfShelf);
813 :
814 2 : for (ShelfNum = 1; ShelfNum <= NumOfShelf; ++ShelfNum) {
815 7 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
816 : cCurrentModuleObject,
817 : ShelfNum,
818 1 : state.dataIPShortCut->cAlphaArgs,
819 : NumAlphas,
820 1 : state.dataIPShortCut->rNumericArgs,
821 : NumNumbers,
822 : IOStatus,
823 1 : state.dataIPShortCut->lNumericFieldBlanks,
824 1 : state.dataIPShortCut->lAlphaFieldBlanks,
825 1 : state.dataIPShortCut->cAlphaFieldNames,
826 1 : state.dataIPShortCut->cNumericFieldNames);
827 2 : UtilityRoutines::IsNameEmpty(
828 2 : state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, state.dataDaylightingDevices->GetShelfInputErrorsFound);
829 : // Shelf name
830 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).Name = state.dataIPShortCut->cAlphaArgs(1);
831 :
832 : // Get window object
833 1 : SurfNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataSurface->Surface);
834 :
835 1 : if (SurfNum == 0) {
836 0 : ShowSevereError(state,
837 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Window " +
838 0 : state.dataIPShortCut->cAlphaArgs(2) + " not found.");
839 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
840 : } else {
841 1 : if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Window) {
842 0 : ShowSevereError(state,
843 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Window " +
844 0 : state.dataIPShortCut->cAlphaArgs(2) + " is not of surface type WINDOW.");
845 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
846 : }
847 :
848 1 : if (state.dataSurface->SurfDaylightingShelfInd(SurfNum) > 0) {
849 0 : ShowSevereError(state,
850 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Window " +
851 0 : state.dataIPShortCut->cAlphaArgs(2) + " is referenced by more than one shelf.");
852 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
853 : }
854 :
855 1 : if (state.dataSurface->Surface(SurfNum).HasShadeControl) {
856 0 : ShowSevereError(state,
857 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Window " +
858 0 : state.dataIPShortCut->cAlphaArgs(2) + " must not have a shading control.");
859 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
860 : }
861 :
862 1 : if (state.dataSurface->Surface(SurfNum).FrameDivider > 0) {
863 0 : ShowSevereError(state,
864 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Window " +
865 0 : state.dataIPShortCut->cAlphaArgs(2) + " must not have a frame/divider.");
866 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
867 : }
868 :
869 1 : if (state.dataSurface->Surface(SurfNum).Sides != 4) {
870 0 : ShowSevereError(state,
871 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Window " +
872 0 : state.dataIPShortCut->cAlphaArgs(2) + " must have 4 sides.");
873 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
874 : }
875 1 : if (state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).WindowTypeEQL) {
876 0 : ShowSevereError(state,
877 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Window " +
878 0 : state.dataIPShortCut->cAlphaArgs(2) + " Equivalent Layer Window is not supported.");
879 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
880 : }
881 :
882 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).Window = SurfNum;
883 1 : state.dataSurface->SurfDaylightingShelfInd(SurfNum) = ShelfNum;
884 : }
885 :
886 : // Get inside shelf heat transfer surface (optional)
887 1 : if (state.dataIPShortCut->cAlphaArgs(3) != "") {
888 1 : SurfNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataSurface->Surface);
889 :
890 1 : if (SurfNum == 0) {
891 0 : ShowSevereError(state,
892 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Inside shelf " +
893 0 : state.dataIPShortCut->cAlphaArgs(3) + " not found.");
894 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
895 : } else {
896 : // No error if shelf belongs to more than one window, e.g. concave corners
897 :
898 1 : if (state.dataSurface->Surface(SurfNum).ExtBoundCond != SurfNum) {
899 0 : ShowSevereError(state,
900 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Inside shelf " +
901 0 : state.dataIPShortCut->cAlphaArgs(3) + " must be its own Outside Boundary Condition Object.");
902 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
903 : }
904 :
905 1 : if (state.dataSurface->Surface(SurfNum).Sides != 4) {
906 0 : ShowSevereError(state,
907 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Inside shelf " +
908 0 : state.dataIPShortCut->cAlphaArgs(3) + " must have 4 sides.");
909 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
910 : }
911 :
912 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).InSurf = SurfNum;
913 : }
914 : }
915 :
916 : // Get outside shelf attached shading surface (optional)
917 1 : if (state.dataIPShortCut->cAlphaArgs(4) != "") {
918 1 : SurfNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataSurface->Surface);
919 :
920 1 : if (SurfNum == 0) {
921 0 : ShowSevereError(state,
922 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Outside shelf " +
923 0 : state.dataIPShortCut->cAlphaArgs(4) + " not found.");
924 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
925 : } else {
926 : // No error if shelf belongs to more than one window, e.g. concave corners
927 :
928 1 : if (state.dataSurface->Surface(SurfNum).Class != SurfaceClass::Shading) {
929 0 : ShowSevereError(state,
930 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Outside shelf " +
931 0 : state.dataIPShortCut->cAlphaArgs(4) + " is not a Shading:Zone:Detailed object.");
932 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
933 : }
934 :
935 1 : if (state.dataSurface->Surface(SurfNum).SchedShadowSurfIndex > 0) {
936 0 : ShowSevereError(state,
937 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Outside shelf " +
938 0 : state.dataIPShortCut->cAlphaArgs(4) + " must not have a transmittance schedule.");
939 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
940 : }
941 :
942 1 : if (state.dataSurface->Surface(SurfNum).Sides != 4) {
943 0 : ShowSevereError(state,
944 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) + ": Outside shelf " +
945 0 : state.dataIPShortCut->cAlphaArgs(4) + " must have 4 sides.");
946 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
947 : }
948 :
949 : // Get outside shelf construction (required if outside shelf is specified)
950 1 : if (state.dataIPShortCut->cAlphaArgs(5) != "") {
951 1 : ConstrNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(5), state.dataConstruction->Construct);
952 :
953 1 : if (ConstrNum == 0) {
954 0 : ShowSevereError(state,
955 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
956 0 : ": Outside shelf construction " + state.dataIPShortCut->cAlphaArgs(5) + " not found.");
957 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
958 1 : } else if (state.dataConstruction->Construct(ConstrNum).TypeIsWindow) {
959 0 : ShowSevereError(state,
960 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
961 0 : ": Outside shelf construction " + state.dataIPShortCut->cAlphaArgs(5) +
962 : " must not have WindowMaterial:Glazing.");
963 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
964 : } else {
965 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).Construction = ConstrNum;
966 1 : state.dataConstruction->Construct(ConstrNum).IsUsed = true;
967 : }
968 : } else {
969 0 : ShowSevereError(state,
970 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
971 : ": Outside shelf requires an outside shelf construction to be specified.");
972 0 : state.dataDaylightingDevices->GetShelfInputErrorsFound = true;
973 : }
974 :
975 : // Get view factor to outside shelf (optional)
976 1 : if (NumNumbers > 0) {
977 0 : state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor = state.dataIPShortCut->rNumericArgs(1);
978 :
979 0 : if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
980 0 : ShowWarningError(state,
981 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
982 : ": View factor to outside shelf is zero. Shelf does not reflect on window.");
983 : }
984 : } else {
985 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor =
986 : -1.0; // Flag to have the view factor calculated during initialization
987 : }
988 :
989 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf = SurfNum;
990 :
991 : // Reset some properties of the SURFACE:SHADING:ATTACHED object in order to receive radiation and shading
992 : // Normally this would be done during initialization, but that's not early enough for some shading calculations
993 1 : state.dataSurface->Surface(SurfNum).BaseSurf = SurfNum;
994 1 : state.dataSurface->Surface(SurfNum).HeatTransSurf = true;
995 1 : state.dataSurface->AllHTSurfaceList.push_back(SurfNum);
996 : // Is this needed? surfZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
997 1 : state.dataSurface->Surface(SurfNum).Construction = ConstrNum; // Kludge to allow shading surface to be a heat transfer surface
998 1 : state.dataSurface->SurfActiveConstruction(SurfNum) = ConstrNum;
999 1 : state.dataConstruction->Construct(ConstrNum).IsUsed = true;
1000 : }
1001 : }
1002 :
1003 1 : if (state.dataDaylightingDevicesData->Shelf(ShelfNum).InSurf == 0 && state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf == 0)
1004 0 : ShowWarningError(state,
1005 0 : cCurrentModuleObject + " = " + state.dataIPShortCut->cAlphaArgs(1) +
1006 : ": No inside shelf or outside shelf was specified.");
1007 :
1008 : } // ShelfNum
1009 :
1010 1 : if (state.dataDaylightingDevices->GetShelfInputErrorsFound) ShowFatalError(state, "Errors in DaylightingDevice:Shelf input.");
1011 : }
1012 771 : }
1013 :
1014 34 : Real64 CalcPipeTransBeam(Real64 const R, // Reflectance of surface, constant (can be made R = f(theta) later)
1015 : Real64 const A, // Aspect ratio, L / d
1016 : Real64 const Theta // Angle of entry in radians
1017 : )
1018 : {
1019 :
1020 : // SUBROUTINE INFORMATION:
1021 : // AUTHOR Peter Graham Ellis
1022 : // DATE WRITTEN May 2003
1023 : // MODIFIED na
1024 : // RE-ENGINEERED na
1025 :
1026 : // PURPOSE OF THIS SUBROUTINE:
1027 : // Calculates the numerical integral for the transmittance of a reflective cylinder with
1028 : // incident collimated beam radiation as described in Swift and Smith.
1029 :
1030 : // METHODOLOGY EMPLOYED:
1031 : // Since this integral can be slow, a table of values is calculated and stored during
1032 : // initialization of the TDD. Intermediate values are calculated by interpolation.
1033 : // Transmittance of sky and ground diffuse radiation is done by other functions.
1034 :
1035 : // REFERENCES:
1036 : // Swift, P. D., and Smith, G. B. "Cylindrical Mirror Light Pipes",
1037 : // Solar Energy Materials and Solar Cells 36 (1995), pp. 159-168.
1038 :
1039 : // OTHER NOTES:
1040 : // The execution time of this function can be reduced by adjusting parameters N and xTol below.
1041 : // However, there is some penalty in accuracy for N < 100,000 and xTol > 150.
1042 :
1043 : // USE STATEMENTS: na
1044 :
1045 : // Return value
1046 : Real64 CalcPipeTransBeam;
1047 :
1048 : // Locals
1049 : // FUNCTION ARGUMENT DEFINITIONS:
1050 :
1051 : // FUNCTION PARAMETER DEFINITIONS:
1052 34 : Real64 constexpr N(100000.0); // Number of integration points
1053 34 : Real64 constexpr xTol(150.0); // Tolerance factor to skip iterations where dT is approximately 0
1054 : // Must be >= 1.0, increase this number to decrease the execution time
1055 34 : Real64 const myLocalTiny(TINY(1.0));
1056 :
1057 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1058 : Real64 i; // Integration interval between points
1059 : Real64 s; // Entry point
1060 : Real64 dT;
1061 : Real64 T; // Beam transmittance for collimated solar real
1062 : Real64 x; // Intermediate variables for speed optimization
1063 : Real64 c1;
1064 : Real64 c2;
1065 : Real64 xLimit; // Limiting x value to prevent floating point underflow
1066 :
1067 34 : CalcPipeTransBeam = 0.0;
1068 :
1069 34 : T = 0.0;
1070 34 : i = 1.0 / N;
1071 :
1072 34 : xLimit = (std::log(pow_2(N) * myLocalTiny) / std::log(R)) / xTol;
1073 :
1074 34 : c1 = A * std::tan(Theta);
1075 34 : c2 = 4.0 / DataGlobalConstants::Pi;
1076 :
1077 34 : s = i;
1078 6799966 : while (s < (1.0 - i)) {
1079 3399966 : x = c1 / s;
1080 :
1081 3399966 : if (x < xLimit) {
1082 3007257 : dT = c2 * std::pow(R, int(x)) * (1.0 - (1.0 - R) * (x - int(x))) * pow_2(s) / std::sqrt(1.0 - pow_2(s));
1083 3007257 : T += dT;
1084 : }
1085 :
1086 3399966 : s += i;
1087 : }
1088 :
1089 34 : T /= (N - 1.0); // - 1.0, because started on i, not 0
1090 :
1091 34 : CalcPipeTransBeam = T;
1092 :
1093 34 : return CalcPipeTransBeam;
1094 : }
1095 :
1096 2 : Real64 CalcTDDTransSolIso(EnergyPlusData &state, int const PipeNum) // TDD pipe object number
1097 : {
1098 :
1099 : // SUBROUTINE INFORMATION:
1100 : // AUTHOR Peter Graham Ellis
1101 : // DATE WRITTEN July 2003
1102 : // MODIFIED na
1103 : // RE-ENGINEERED na
1104 :
1105 : // PURPOSE OF THIS SUBROUTINE:
1106 : // Calculates the transmittance of sky isotropic radiation for use with the anisotropic sky transmittance.
1107 : // This value is also used for all ground reflected solar radiation (which is isotropic).
1108 :
1109 : // METHODOLOGY EMPLOYED:
1110 : // The transmittance is calculated and stored once at initialization because the value is a constant.
1111 : // The routine numerically integrates over the entire sky. All radiation is isotropic, but incident
1112 : // angle varies over the hemisphere.
1113 : // Trans = Flux Transmitted / Flux Incident
1114 : // Not sure if shading and tilt is adequately accounted for by DifShdgRatioIsoSky later on or not...
1115 :
1116 : // REFERENCES:
1117 : // See AnisoSkyViewFactors in SolarShading.cc.
1118 :
1119 : // USE STATEMENTS: na
1120 :
1121 : // Return value
1122 : Real64 CalcTDDTransSolIso;
1123 :
1124 : // Locals
1125 : // FUNCTION ARGUMENT DEFINITIONS:
1126 :
1127 : // FUNCTION PARAMETER DEFINITIONS:
1128 2 : int constexpr NPH(1000); // Number of altitude integration points
1129 :
1130 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1131 2 : Real64 FluxInc = 0.0; // Incident solar flux
1132 2 : Real64 FluxTrans = 0.0; // Transmitted solar flux
1133 : Real64 trans; // Total beam solar transmittance of TDD
1134 : Real64 COSI; // Cosine of incident angle
1135 : Real64 SINI; // Sine of incident angle
1136 :
1137 2 : Real64 const dPH = 90.0 * DataGlobalConstants::DegToRadians / NPH; // Altitude angle of sky element
1138 2 : Real64 PH = 0.5 * dPH; // Altitude angle increment
1139 :
1140 : // Integrate from 0 to Pi/2 altitude
1141 2002 : for (int N = 1; N <= NPH; ++N) {
1142 2000 : COSI = std::cos(DataGlobalConstants::PiOvr2 - PH);
1143 2000 : SINI = std::sin(DataGlobalConstants::PiOvr2 - PH);
1144 :
1145 2000 : Real64 P = COSI; // Angular distribution function: P = COS(Incident Angle) for diffuse isotropic
1146 :
1147 : // Calculate total TDD transmittance for given angle
1148 2000 : trans = TransTDD(state, PipeNum, COSI, DataDaylightingDevices::RadType::SolarBeam);
1149 :
1150 2000 : FluxInc += P * SINI * dPH;
1151 2000 : FluxTrans += trans * P * SINI * dPH;
1152 :
1153 2000 : PH += dPH; // Increment the altitude angle
1154 : } // N
1155 :
1156 2 : CalcTDDTransSolIso = FluxTrans / FluxInc;
1157 :
1158 2 : return CalcTDDTransSolIso;
1159 : }
1160 :
1161 2 : Real64 CalcTDDTransSolHorizon(EnergyPlusData &state, int const PipeNum) // TDD pipe object number
1162 : {
1163 :
1164 : // SUBROUTINE INFORMATION:
1165 : // AUTHOR Peter Graham Ellis
1166 : // DATE WRITTEN July 2003
1167 : // MODIFIED na
1168 : // RE-ENGINEERED na
1169 :
1170 : // PURPOSE OF THIS SUBROUTINE:
1171 : // Calculates the transmittance of sky horizon radiation for use with the anisotropic sky transmittance.
1172 :
1173 : // METHODOLOGY EMPLOYED:
1174 : // The transmittance is calculated and stored once at initialization because the value is a constant.
1175 : // The routine numerically integrates over the horizon as an infinitesimally narrow strip of the sky.
1176 : // Horizon radiation is isotropic, but incident angle varies over the semicircle.
1177 : // Trans = Flux Transmitted / Flux Incident
1178 : // Not sure if shading is adequately accounted for by DifShdgRatioHoriz later on or not...
1179 :
1180 : // REFERENCES:
1181 : // See AnisoSkyViewFactors in SolarShading.cc.
1182 :
1183 : // Using/Aliasing
1184 : using namespace DataSurfaces;
1185 :
1186 : // Return value
1187 : Real64 CalcTDDTransSolHorizon;
1188 :
1189 : // Locals
1190 : // FUNCTION ARGUMENT DEFINITIONS:
1191 :
1192 : // FUNCTION PARAMETER DEFINITIONS:
1193 2 : int constexpr NTH(18); // Number of azimuth integration points
1194 :
1195 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1196 2 : Real64 FluxInc = 0.0; // Incident solar flux
1197 2 : Real64 FluxTrans = 0.0; // Transmitted solar flux
1198 : Real64 CosPhi; // Cosine of TDD:DOME altitude angle
1199 : Real64 Theta; // TDD:DOME azimuth angle
1200 :
1201 2 : CosPhi = std::cos(DataGlobalConstants::PiOvr2 - state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Tilt *
1202 : DataGlobalConstants::DegToRadians);
1203 2 : Theta = state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Azimuth * DataGlobalConstants::DegToRadians;
1204 :
1205 2 : if (CosPhi > 0.01) { // Dome has a view of the horizon
1206 : // Integrate over the semicircle
1207 2 : Real64 const THMIN = Theta - DataGlobalConstants::PiOvr2; // Minimum azimuth integration limit
1208 : // Real64 const THMAX = Theta + PiOvr2; // Maximum azimuth integration limit
1209 2 : Real64 const dTH = 180.0 * DataGlobalConstants::DegToRadians / NTH; // Azimuth angle increment
1210 2 : Real64 TH = THMIN + 0.5 * dTH; // Azimuth angle of sky horizon element
1211 :
1212 38 : for (int N = 1; N <= NTH; ++N) {
1213 : // Calculate incident angle between dome outward normal and horizon element
1214 36 : Real64 COSI = CosPhi * std::cos(TH - Theta); // Cosine of the incident angle
1215 :
1216 : // Calculate total TDD transmittance for given angle
1217 36 : Real64 trans = TransTDD(state, PipeNum, COSI, DataDaylightingDevices::RadType::SolarBeam); // Total beam solar transmittance of TDD
1218 :
1219 36 : FluxInc += COSI * dTH;
1220 36 : FluxTrans += trans * COSI * dTH;
1221 :
1222 36 : TH += dTH; // Increment the azimuth angle
1223 : } // N
1224 :
1225 2 : CalcTDDTransSolHorizon = FluxTrans / FluxInc;
1226 :
1227 : } else { // Dome is nearly horizontal and has almost no view of the horizon
1228 0 : CalcTDDTransSolHorizon = 0.0; // = TransTDD(state, PipeNum, ???, SolarBeam) ! Could change to an angle near the horizon
1229 : }
1230 :
1231 2 : return CalcTDDTransSolHorizon;
1232 : }
1233 :
1234 4928 : Real64 CalcTDDTransSolAniso(EnergyPlusData &state,
1235 : int const PipeNum, // TDD pipe object number
1236 : Real64 const COSI // Cosine of the incident angle
1237 : )
1238 : {
1239 :
1240 : // SUBROUTINE INFORMATION:
1241 : // AUTHOR Peter Graham Ellis
1242 : // DATE WRITTEN July 2003
1243 : // MODIFIED na
1244 : // RE-ENGINEERED na
1245 :
1246 : // PURPOSE OF THIS SUBROUTINE:
1247 : // Calculates the transmittance of the anisotropic sky.
1248 :
1249 : // METHODOLOGY EMPLOYED:
1250 : // Similar to the Trans = FluxTrans/FluxInc integrations above, the anisotropic sky can be decomposed
1251 : // and have a different transmittance applied to each component.
1252 : // FluxInc = IsoSkyRad + CircumSolarRad + HorizonRad
1253 : // FluxTrans = T1*IsoSkyRad + T2*CircumSolarRad + T3*HorizonRad
1254 : // It turns out that FluxTrans/FluxInc is equivalent to AnisoSkyTDDMult/SurfAnisoSkyMult.
1255 : // SurfAnisoSkyMult has been conveniently calculated already in AnisoSkyViewFactors in SolarShading.cc.
1256 : // SurfAnisoSkyMult = MultIsoSky*DifShdgRatioIsoSky + MultCircumSolar*SunlitFrac + MultHorizonZenith*DifShdgRatioHoriz
1257 : // In this routine a similar AnisoSkyTDDMult is calculated that applies the appropriate transmittance to each
1258 : // of the components above. The result is Trans = AnisoSkyTDDMult/SurfAnisoSkyMult.
1259 : // Shading and orientation are already taken care of by DifShdgRatioIsoSky and DifShdgRatioHoriz.
1260 :
1261 : // REFERENCES:
1262 : // See AnisoSkyViewFactors in SolarShading.cc.
1263 :
1264 : // Return value
1265 : Real64 CalcTDDTransSolAniso;
1266 :
1267 : // Locals
1268 : // FUNCTION ARGUMENT DEFINITIONS:
1269 :
1270 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1271 : int DomeSurf; // TDD:DOME surface number
1272 : Real64 IsoSkyRad; // Isotropic sky radiation component
1273 : Real64 CircumSolarRad; // Circumsolar sky radiation component
1274 : Real64 HorizonRad; // Horizon sky radiation component
1275 : Real64 AnisoSkyTDDMult; // Anisotropic sky multiplier for TDD
1276 :
1277 4928 : DomeSurf = state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome;
1278 :
1279 4928 : if (!state.dataSysVars->DetailedSkyDiffuseAlgorithm || !state.dataSurface->ShadingTransmittanceVaries ||
1280 0 : state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
1281 4928 : IsoSkyRad = state.dataSolarShading->SurfMultIsoSky(DomeSurf) * state.dataSolarShading->SurfDifShdgRatioIsoSky(DomeSurf);
1282 4928 : HorizonRad = state.dataSolarShading->SurfMultHorizonZenith(DomeSurf) * state.dataSolarShading->SurfDifShdgRatioHoriz(DomeSurf);
1283 : } else {
1284 0 : IsoSkyRad = state.dataSolarShading->SurfMultIsoSky(DomeSurf) * state.dataSolarShading->SurfCurDifShdgRatioIsoSky(DomeSurf);
1285 0 : HorizonRad = state.dataSolarShading->SurfMultHorizonZenith(DomeSurf) *
1286 0 : state.dataSolarShading->SurfDifShdgRatioHorizHRTS(state.dataGlobal->TimeStep, state.dataGlobal->HourOfDay, DomeSurf);
1287 : }
1288 9856 : CircumSolarRad = state.dataSolarShading->SurfMultCircumSolar(DomeSurf) *
1289 4928 : state.dataHeatBal->SurfSunlitFrac(state.dataGlobal->HourOfDay, state.dataGlobal->TimeStep, DomeSurf);
1290 :
1291 14784 : AnisoSkyTDDMult = state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolIso * IsoSkyRad +
1292 4928 : TransTDD(state, PipeNum, COSI, DataDaylightingDevices::RadType::SolarBeam) * CircumSolarRad +
1293 4928 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolHorizon * HorizonRad;
1294 :
1295 4928 : if (state.dataSolarShading->SurfAnisoSkyMult(DomeSurf) > 0.0) {
1296 4928 : CalcTDDTransSolAniso = AnisoSkyTDDMult / state.dataSolarShading->SurfAnisoSkyMult(DomeSurf);
1297 : } else {
1298 0 : CalcTDDTransSolAniso = 0.0;
1299 : }
1300 :
1301 4928 : return CalcTDDTransSolAniso;
1302 : }
1303 :
1304 802540 : Real64 TransTDD(EnergyPlusData &state,
1305 : int const PipeNum, // TDD pipe object number
1306 : Real64 const COSI, // Cosine of the incident angle
1307 : DataDaylightingDevices::RadType const RadiationType // Radiation type flag
1308 : )
1309 : {
1310 :
1311 : // SUBROUTINE INFORMATION:
1312 : // AUTHOR Peter Graham Ellis
1313 : // DATE WRITTEN May 2003
1314 : // MODIFIED na
1315 : // RE-ENGINEERED na
1316 :
1317 : // PURPOSE OF THIS SUBROUTINE:
1318 : // Calculates the total transmittance of the TDD for specified radiation type.
1319 :
1320 : // METHODOLOGY EMPLOYED:
1321 : // The transmittances for each component (i.e. TDD:DIFFUSER, TDD:DOME, and pipe) are calculated.
1322 : // All transmittances are multiplied to get the total for the TDD:
1323 : // TransTDD = transDome * transPipe * transDiff
1324 : // Transmittance of beam radiation is calculated by interpolating the values in a
1325 : // table created during initialization. The table values are from Swift and Smith's
1326 : // numerical integral for collimated beam radiation.
1327 : // Transmittances of isotropic and anisotropic diffuse radiation are more complicated and call
1328 : // other subroutines in this module.
1329 : // All light reaching the TDD:DIFFUSER is assumed to be diffuse.
1330 : // NOTE: Dome transmittance could be improved by taking into account curvature of the dome.
1331 :
1332 : // REFERENCES:
1333 : // Swift, P. D., and Smith, G. B. "Cylindrical Mirror Light Pipes",
1334 : // Solar Energy Materials and Solar Cells 36 (1995), pp. 159-168.
1335 :
1336 : // Using/Aliasing
1337 : using General::POLYF;
1338 :
1339 : // Return value
1340 : Real64 TransTDD;
1341 :
1342 : // Locals
1343 : // FUNCTION ARGUMENT DEFINITIONS:
1344 :
1345 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1346 : int constDome; // Construction object number for TDD:DOME
1347 : int constDiff; // Construction object number for TDD:DIFFUSER
1348 : Real64 transDome;
1349 : Real64 transPipe;
1350 : Real64 transDiff;
1351 :
1352 802540 : TransTDD = 0.0;
1353 :
1354 : // Get constructions of each TDD component
1355 802540 : constDome = state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Construction;
1356 802540 : constDiff = state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diffuser).Construction;
1357 :
1358 : // Get the transmittance of each component and of total TDD
1359 802540 : switch (RadiationType) {
1360 788268 : case DataDaylightingDevices::RadType::VisibleBeam: {
1361 788268 : transDome = POLYF(COSI, state.dataConstruction->Construct(constDome).TransVisBeamCoef);
1362 788268 : transPipe = InterpolatePipeTransBeam(state, COSI, state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeTransVisBeam);
1363 788268 : transDiff = state.dataConstruction->Construct(constDiff).TransDiffVis; // May want to change to POLYF also!
1364 :
1365 788268 : TransTDD = transDome * transPipe * transDiff;
1366 :
1367 788268 : } break;
1368 9344 : case DataDaylightingDevices::RadType::SolarBeam: {
1369 9344 : transDome = POLYF(COSI, state.dataConstruction->Construct(constDome).TransSolBeamCoef);
1370 9344 : transPipe = InterpolatePipeTransBeam(state, COSI, state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeTransSolBeam);
1371 9344 : transDiff = state.dataConstruction->Construct(constDiff).TransDiff; // May want to change to POLYF also!
1372 :
1373 9344 : TransTDD = transDome * transPipe * transDiff;
1374 :
1375 9344 : } break;
1376 4928 : case DataDaylightingDevices::RadType::SolarAniso: {
1377 4928 : TransTDD = CalcTDDTransSolAniso(state, PipeNum, COSI);
1378 4928 : } break;
1379 0 : case DataDaylightingDevices::RadType::SolarIso: {
1380 0 : TransTDD = state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolIso;
1381 0 : } break;
1382 0 : default:
1383 0 : break;
1384 : }
1385 :
1386 802540 : return TransTDD;
1387 : }
1388 :
1389 797612 : Real64 InterpolatePipeTransBeam(EnergyPlusData &state,
1390 : Real64 const COSI, // Cosine of the incident angle
1391 : const Array1D<Real64> &transBeam // Table of beam transmittance vs. cosine angle
1392 : )
1393 : {
1394 :
1395 : // SUBROUTINE INFORMATION:
1396 : // AUTHOR Peter Graham Ellis
1397 : // DATE WRITTEN July 2003
1398 : // MODIFIED na
1399 : // RE-ENGINEERED na
1400 :
1401 : // PURPOSE OF THIS SUBROUTINE:
1402 : // Interpolates the beam transmittance vs. cosine angle table.
1403 :
1404 : // METHODOLOGY EMPLOYED: na
1405 : // REFERENCES: na
1406 :
1407 : // Using/Aliasing
1408 : using FluidProperties::FindArrayIndex; // USEd code could be copied here to eliminate dependence on FluidProperties
1409 :
1410 : // Return value
1411 : Real64 InterpolatePipeTransBeam;
1412 :
1413 : // Argument array dimensioning
1414 797612 : EP_SIZE_CHECK(transBeam, DataDaylightingDevices::NumOfAngles);
1415 :
1416 : // Locals
1417 : // FUNCTION ARGUMENT DEFINITIONS:
1418 :
1419 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1420 : int Lo;
1421 : int Hi;
1422 : Real64 m;
1423 : Real64 b;
1424 :
1425 797612 : InterpolatePipeTransBeam = 0.0;
1426 :
1427 : // Linearly interpolate transBeam/COSAngle table to get value at current cosine of the angle
1428 797612 : Lo = FindArrayIndex(COSI, state.dataDaylightingDevices->COSAngle);
1429 797612 : Hi = Lo + 1;
1430 :
1431 797612 : if (Lo > 0 && Hi <= DataDaylightingDevices::NumOfAngles) {
1432 797192 : m = (transBeam(Hi) - transBeam(Lo)) / (state.dataDaylightingDevices->COSAngle(Hi) - state.dataDaylightingDevices->COSAngle(Lo));
1433 797192 : b = transBeam(Lo) - m * state.dataDaylightingDevices->COSAngle(Lo);
1434 :
1435 797192 : InterpolatePipeTransBeam = m * COSI + b;
1436 : } else {
1437 420 : InterpolatePipeTransBeam = 0.0;
1438 : }
1439 :
1440 797612 : return InterpolatePipeTransBeam;
1441 : }
1442 :
1443 4 : int FindTDDPipe(EnergyPlusData &state, int const WinNum)
1444 : {
1445 :
1446 : // SUBROUTINE INFORMATION:
1447 : // AUTHOR Peter Graham Ellis
1448 : // DATE WRITTEN May 2003
1449 : // MODIFIED na
1450 : // RE-ENGINEERED na
1451 :
1452 : // PURPOSE OF THIS SUBROUTINE:
1453 : // Given the TDD:DOME or TDD:DIFFUSER object number, returns TDD pipe number.
1454 :
1455 : // Return value
1456 : int FindTDDPipe;
1457 :
1458 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1459 : int PipeNum; // TDD pipe object number
1460 :
1461 4 : FindTDDPipe = 0;
1462 :
1463 4 : if ((int)state.dataDaylightingDevicesData->TDDPipe.size() <= 0) {
1464 0 : ShowFatalError(
1465 : state,
1466 0 : "FindTDDPipe: Surface=" + state.dataSurface->Surface(WinNum).Name +
1467 : ", TDD:Dome object does not reference a valid Diffuser object....needs DaylightingDevice:Tubular of same name as Surface.");
1468 : }
1469 :
1470 12 : for (PipeNum = 1; PipeNum <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++PipeNum) {
1471 16 : if ((WinNum == state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome) ||
1472 8 : (WinNum == state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diffuser)) {
1473 0 : FindTDDPipe = PipeNum;
1474 0 : break;
1475 : }
1476 : } // PipeNum
1477 :
1478 4 : return FindTDDPipe;
1479 : }
1480 :
1481 2568509 : void DistributeTDDAbsorbedSolar(EnergyPlusData &state)
1482 : {
1483 :
1484 : // SUBROUTINE INFORMATION:
1485 : // AUTHOR Peter Graham Ellis
1486 : // DATE WRITTEN July 2003
1487 : // MODIFIED na
1488 : // RE-ENGINEERED na
1489 :
1490 : // PURPOSE OF THIS SUBROUTINE:
1491 : // Sums the absorbed solar gains from TDD pipes that pass through transition zones.
1492 :
1493 : // METHODOLOGY EMPLOYED:
1494 : // The total absorbed solar gain is a sum of the following gains:
1495 : // 1. Inward bound solar absorbed by multiple pipe reflections (solar entering pipe - solar exiting pipe)
1496 : // 2. Outward bound solar absorbed by multiple pipe reflections due to:
1497 : // a. Reflection off of diffuser surface (inside of TDD)
1498 : // b. Zone diffuse interior shortwave incident on the diffuser from windows, lights, etc.
1499 : // 3. Inward absorbed solar in dome and diffuser glass
1500 : // This subroutine is called by InitIntSolarDistribution in HeatBalanceSurfaceManager.cc.
1501 :
1502 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1503 : int PipeNum; // TDD pipe object number
1504 : int DiffSurf; // Surface number of TDD:DIFFUSER
1505 : int TZoneNum; // Transition zone index
1506 : Real64 transDiff; // Diffuse transmittance of TDD:DIFFUSER
1507 : Real64 QRefl; // Diffuse radiation reflected back up the pipe
1508 : Real64 TotTDDPipeGain; // Total absorbed solar gain in the tubular daylighting device pipe
1509 :
1510 2572559 : for (PipeNum = 1; PipeNum <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++PipeNum) {
1511 4050 : DiffSurf = state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diffuser;
1512 4050 : transDiff = state.dataConstruction->Construct(state.dataSurface->Surface(DiffSurf).Construction).TransDiff;
1513 :
1514 : // Calculate diffuse solar reflected back up the pipe by the inside surface of the TDD:DIFFUSER
1515 : // All solar arriving at the diffuser is assumed to be isotropically diffuse by this point
1516 12150 : QRefl = (state.dataHeatBal->SurfQRadSWOutIncident(DiffSurf) - state.dataHeatBal->SurfWinQRadSWwinAbsTot(DiffSurf)) *
1517 4050 : state.dataSurface->Surface(DiffSurf).Area -
1518 4050 : state.dataSurface->SurfWinTransSolar(DiffSurf);
1519 :
1520 : // Add diffuse interior shortwave reflected from zone surfaces and from zone sources, lights, etc.
1521 12150 : QRefl += state.dataHeatBal->EnclSolQSWRad(state.dataSurface->Surface(DiffSurf).SolarEnclIndex) *
1522 8100 : state.dataSurface->Surface(DiffSurf).Area * transDiff;
1523 :
1524 12150 : TotTDDPipeGain = state.dataSurface->SurfWinTransSolar(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome) -
1525 8100 : state.dataHeatBal->SurfQRadSWOutIncident(DiffSurf) * state.dataSurface->Surface(DiffSurf).Area +
1526 8100 : QRefl * (1.0 - state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolIso / transDiff) +
1527 8100 : state.dataHeatBal->SurfWinQRadSWwinAbs(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome, 1) *
1528 8100 : state.dataSurface->Surface(DiffSurf).Area / 2.0 +
1529 4050 : state.dataHeatBal->SurfWinQRadSWwinAbs(DiffSurf, 1) * state.dataSurface->Surface(DiffSurf).Area /
1530 : 2.0; // Solar entering pipe | Solar exiting pipe | Absorbed due to
1531 : // reflections on the way out | Inward absorbed solar from dome
1532 : // glass | Inward absorbed solar from diffuser glass
1533 4050 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeAbsorbedSolar = max(0.0, TotTDDPipeGain); // Report variable [W]
1534 :
1535 8100 : for (TZoneNum = 1; TZoneNum <= state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones; ++TZoneNum) {
1536 : // Distribute absorbed solar gain in proportion to transition zone length
1537 4050 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneHeatGain(TZoneNum) =
1538 8100 : TotTDDPipeGain * (state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength(TZoneNum) /
1539 4050 : state.dataDaylightingDevicesData->TDDPipe(PipeNum).TotLength);
1540 : } // TZoneNum
1541 : }
1542 2568509 : }
1543 :
1544 1 : void CalcViewFactorToShelf(EnergyPlusData &state, int const ShelfNum) // Daylighting shelf object number
1545 : {
1546 :
1547 : // SUBROUTINE INFORMATION:
1548 : // AUTHOR Peter Graham Ellis
1549 : // DATE WRITTEN August 2003
1550 : // MODIFIED na
1551 : // RE-ENGINEERED na
1552 :
1553 : // PURPOSE OF THIS SUBROUTINE:
1554 : // Attempts to calculate exact analytical view factor from window to outside shelf.
1555 :
1556 : // METHODOLOGY EMPLOYED:
1557 : // Uses a standard analytical solution. It is required that window and shelf have the same width, i.e.
1558 : // one edge (or two vertices) shared in common. An error or warning is issued if not true.
1559 : // A more general routine should be implemented at some point to solve for more complicated geometries.
1560 : // Until then, the user has the option to specify their own solution for the view factor in the input object.
1561 :
1562 : // REFERENCES:
1563 : // Mills, A. F. Heat and Mass Transfer, 1995, p. 499. (Shape factor for adjacent rectangles.)
1564 :
1565 : // USE STATEMENTS:
1566 :
1567 : // Locals
1568 : // SUBROUTINE ARGUMENT DEFINITIONS:
1569 :
1570 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1571 : Real64 W; // Width, height, and length of window/shelf geometry
1572 : Real64 H;
1573 : Real64 L;
1574 : Real64 M; // Intermediate variables
1575 : Real64 N;
1576 : Real64 E1; // Intermediate equations
1577 : Real64 E2;
1578 : Real64 E3;
1579 : Real64 E4;
1580 : int VWin; // Vertex indices
1581 : int VShelf;
1582 : int NumMatch; // Number of vertices matched
1583 :
1584 1 : W = state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).Window).Width;
1585 1 : H = state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).Window).Height;
1586 :
1587 : // Find length, i.e. projection, of outside shelf
1588 1 : if (state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf).Width == W) {
1589 1 : L = state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf).Height;
1590 0 : } else if (state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf).Height == W) {
1591 0 : L = state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf).Width;
1592 : } else {
1593 0 : ShowFatalError(state,
1594 0 : "DaylightingDevice:Shelf = " + state.dataDaylightingDevicesData->Shelf(ShelfNum).Name +
1595 : ": Width of window and outside shelf do not match.");
1596 : }
1597 :
1598 : // Error if more or less than two vertices match
1599 1 : NumMatch = 0;
1600 5 : for (VWin = 1; VWin <= 4; ++VWin) {
1601 20 : for (VShelf = 1; VShelf <= 4; ++VShelf) {
1602 32 : if (distance(state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).Window).Vertex(VWin),
1603 32 : state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf).Vertex(VShelf)) == 0.0)
1604 2 : ++NumMatch;
1605 : }
1606 : }
1607 :
1608 1 : if (NumMatch < 2) {
1609 0 : ShowWarningError(state,
1610 0 : "DaylightingDevice:Shelf = " + state.dataDaylightingDevicesData->Shelf(ShelfNum).Name +
1611 : ": Window and outside shelf must share two vertices. View factor calculation may be inaccurate.");
1612 1 : } else if (NumMatch > 2) {
1613 0 : ShowFatalError(state,
1614 0 : "DaylightingDevice:Shelf = " + state.dataDaylightingDevicesData->Shelf(ShelfNum).Name +
1615 : ": Window and outside shelf share too many vertices.");
1616 : }
1617 :
1618 : // Calculate exact analytical view factor from window to outside shelf
1619 1 : M = H / W;
1620 1 : N = L / W;
1621 :
1622 1 : E1 = M * std::atan(1.0 / M) + N * std::atan(1.0 / N) - std::sqrt(pow_2(N) + pow_2(M)) * std::atan(std::pow(pow_2(N) + pow_2(M), -0.5));
1623 1 : E2 = ((1.0 + pow_2(M)) * (1.0 + pow_2(N))) / (1.0 + pow_2(M) + pow_2(N));
1624 1 : E3 = std::pow(pow_2(M) * (1.0 + pow_2(M) + pow_2(N)) / ((1.0 + pow_2(M)) * (pow_2(M) + pow_2(N))), pow_2(M));
1625 1 : E4 = std::pow(pow_2(N) * (1.0 + pow_2(M) + pow_2(N)) / ((1.0 + pow_2(N)) * (pow_2(M) + pow_2(N))), pow_2(N));
1626 :
1627 1 : state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor = (1.0 / (DataGlobalConstants::Pi * M)) * (E1 + 0.25 * std::log(E2 * E3 * E4));
1628 1 : }
1629 :
1630 1 : void adjustViewFactorsWithShelf(
1631 : EnergyPlusData &state, Real64 &viewFactorToShelf, Real64 &viewFactorToSky, Real64 &viewFactorToGround, int WinSurf, int ShelfNum)
1632 : {
1633 : // First, make sure none of the view factors are less than zero and return if there isn't a problem or if
1634 : // view factor to shelf greater than one. Both cases together would also eliminate if other views are zero
1635 : // which means nothing would need to be done.
1636 1 : if (viewFactorToSky <= 0.0) viewFactorToSky = 0.0;
1637 1 : if (viewFactorToGround <= 0.0) viewFactorToGround = 0.0;
1638 1 : if (viewFactorToShelf <= 0.0) { // No shelf impact for which to account
1639 0 : ShowWarningError(state,
1640 0 : format("DaylightingDevice:Shelf = {}: Window view factor to shelf was less than 0. This should not happen.",
1641 0 : state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
1642 0 : ShowContinueError(state, "The view factor has been reset to zero.");
1643 0 : viewFactorToShelf = 0.0;
1644 0 : if ((viewFactorToGround + viewFactorToSky) > 1.0) { // This data came in incorrect, fix by proportional reduction
1645 0 : viewFactorToGround = viewFactorToGround / (viewFactorToGround + viewFactorToSky);
1646 0 : viewFactorToSky = 1.0 - viewFactorToGround;
1647 0 : ShowWarningError(state,
1648 0 : format("DaylightingDevice:Shelf = {}: The sum of the window view factors to ground and sky were greater than 1. "
1649 : "This should not happen.",
1650 0 : state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
1651 0 : ShowContinueError(
1652 : state, "The view factors have been reset to so that they do not exceed 1. Check/fix your input file data to avoid this issue.");
1653 : }
1654 0 : return;
1655 : }
1656 1 : if (viewFactorToShelf + viewFactorToSky + viewFactorToGround <= 1.0) return; // nothing wrong here
1657 0 : if (viewFactorToShelf >= 1.0) { // Don't allow shelf view of greater than 1 (zero out other views)
1658 0 : ShowWarningError(state,
1659 0 : format("DaylightingDevice:Shelf = {}: Window view factor to shelf was greater than 1. This should not happen.",
1660 0 : state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
1661 0 : ShowContinueError(state, "The view factor has been reset to 1 and the other view factors to sky and ground have been set to 0.");
1662 0 : viewFactorToShelf = 1.0;
1663 0 : viewFactorToGround = 0.0;
1664 0 : viewFactorToSky = 0.0;
1665 0 : return;
1666 : }
1667 :
1668 : // If the flow is still here, there is something that needs to be adjusted so set the maximum shelf height and the minimum window height
1669 0 : int ShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf;
1670 0 : Real64 zShelfMax = state.dataSurface->Surface(ShelfSurf).Vertex(1).z;
1671 0 : Real64 zShelfMin = zShelfMax;
1672 0 : for (int vertex = 2; vertex <= state.dataSurface->Surface(ShelfSurf).Sides; ++vertex) {
1673 0 : if (state.dataSurface->Surface(ShelfSurf).Vertex(vertex).z > zShelfMax)
1674 0 : zShelfMax = state.dataSurface->Surface(ShelfSurf).Vertex(vertex).z;
1675 0 : if (state.dataSurface->Surface(ShelfSurf).Vertex(vertex).z < zShelfMin)
1676 0 : zShelfMin = state.dataSurface->Surface(ShelfSurf).Vertex(vertex).z;
1677 : }
1678 0 : Real64 zWinMax = state.dataSurface->Surface(WinSurf).Vertex(1).z;
1679 0 : Real64 zWinMin = zWinMax;
1680 0 : for (int vertex = 2; vertex <= state.dataSurface->Surface(WinSurf).Sides; ++vertex) {
1681 0 : if (state.dataSurface->Surface(WinSurf).Vertex(vertex).z > zWinMax) zWinMax = state.dataSurface->Surface(WinSurf).Vertex(vertex).z;
1682 0 : if (state.dataSurface->Surface(WinSurf).Vertex(vertex).z < zWinMin) zWinMin = state.dataSurface->Surface(WinSurf).Vertex(vertex).z;
1683 : }
1684 :
1685 : Real64 leftoverViewFactor;
1686 : // Now correct the view factors based on the location of the shelf with respect to the window
1687 0 : ShowWarningError(
1688 : state,
1689 0 : format("DaylightingDevice:Shelf = {}: Window view factor to shelf [{:.2R}] results in a sum of view factors greater than 1.",
1690 0 : state.dataDaylightingDevicesData->Shelf(ShelfNum).Name,
1691 0 : state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor));
1692 0 : if (zWinMin >= zShelfMax) { // Shelf is fully below window, reduce view to ground first based on view to shelf
1693 0 : ShowContinueError(
1694 : state,
1695 : "Since the light shelf is below the window to which it is associated, the view factor of the window to the ground was reduced");
1696 0 : ShowContinueError(
1697 : state, "and possibly also the view factor to the sky. Check you input and/or consider turning off autosizing of the view factors.");
1698 0 : leftoverViewFactor = 1.0 - viewFactorToShelf - viewFactorToSky;
1699 0 : if (leftoverViewFactor >= 0.0) {
1700 0 : viewFactorToGround = leftoverViewFactor; // Other view factors okay
1701 : } else {
1702 0 : viewFactorToGround = 0.0;
1703 0 : viewFactorToSky = 1.0 - viewFactorToShelf;
1704 0 : if (viewFactorToSky < 0.0) {
1705 0 : viewFactorToSky = 0.0;
1706 0 : viewFactorToShelf = 1.0;
1707 : }
1708 : }
1709 :
1710 0 : } else if (zShelfMin >= zWinMax) { // Shelf is fully above window, reduce view to sky first based on view to shelf
1711 0 : ShowContinueError(
1712 : state, "Since the light shelf is above the window to which it is associated, the view factor of the window to the sky was reduced");
1713 0 : ShowContinueError(
1714 : state,
1715 : "and possibly also the view factor to the ground. Check you input and/or consider turning off autosizing of the view factors.");
1716 0 : leftoverViewFactor = 1.0 - viewFactorToShelf - viewFactorToGround;
1717 0 : if (leftoverViewFactor >= 0.0) {
1718 0 : viewFactorToSky = leftoverViewFactor;
1719 : } else {
1720 0 : viewFactorToSky = 0.0;
1721 0 : viewFactorToGround = 1.0 - viewFactorToShelf;
1722 0 : if (viewFactorToGround < 0.0) {
1723 0 : viewFactorToGround = 0.0;
1724 0 : viewFactorToShelf = 1.0;
1725 : }
1726 : }
1727 : } else { // At least part of the shelf is somewhere in the middle of the window so we need to split out the view factors
1728 0 : ShowContinueError(
1729 : state,
1730 : "Since the light shelf is neither fully above or fully below the window to which it is associated, the view factor of the window");
1731 0 : ShowContinueError(
1732 : state,
1733 : "to the ground and sky were both potentially reduced. Check you input and/or consider turning off autosizing of the view factors.");
1734 : Real64 zShelfAvg;
1735 0 : if (((zShelfMin >= zWinMin) && (zShelfMax <= zWinMax)) || // Shelf does not go above or below the window
1736 0 : ((zShelfMin < zWinMin) && (zShelfMax > zWinMax))) { // Shelf goes both above AND below the window
1737 0 : zShelfAvg = 0.5 * (zShelfMin + zShelfMax);
1738 0 : } else if (zShelfMin < zWinMin) { // Shelf goes partially below the window only
1739 0 : Real64 fracAbove = 0.0;
1740 0 : if (zShelfMax > zShelfMin) {
1741 0 : fracAbove = (zShelfMax - zWinMin) / (zShelfMax - zShelfMin);
1742 0 : if (fracAbove > 1.0) fracAbove = 1.0;
1743 : }
1744 0 : zShelfAvg = zWinMin + fracAbove * (zShelfMax - zWinMin);
1745 : } else { // (zShelfMax > zWinMax): Shelf goes partially above window
1746 0 : Real64 fracBelow = 0.0;
1747 0 : if (zShelfMax > zShelfMin) {
1748 0 : fracBelow = (zWinMax - zShelfMin) / (zShelfMax - zShelfMin);
1749 : }
1750 0 : zShelfAvg = zWinMax - fracBelow * (zWinMax - zShelfMin);
1751 : }
1752 :
1753 : // Find height ratio based on shelf average height
1754 : Real64 heightRatio;
1755 0 : if (zWinMax > zWinMin) { // Window has a positive height
1756 0 : heightRatio = (zShelfAvg - zWinMin) / (zWinMax - zWinMin);
1757 0 : heightRatio = min(heightRatio, 1.0);
1758 0 : heightRatio = max(heightRatio, 0.0);
1759 : } else { // Window does not have a positive height (not realistic) so set height ratio based on shelf location
1760 0 : if (zShelfAvg > zWinMax) {
1761 0 : heightRatio = 1.0;
1762 : } else {
1763 0 : heightRatio = 0.0;
1764 : }
1765 : }
1766 :
1767 : // Take what is left over after the view to shelf is subtracted and then distribute/adjust that proportionally
1768 : // for the views to ground and sky based on their original weights. Finally, account for the location of the shelf
1769 : // with respect to the shelf and reset the values of the actual variables used in the rest of the simulation.
1770 0 : leftoverViewFactor = 1.0 - viewFactorToShelf; // By previous logic above, leftover is greater than zero and less than one
1771 : Real64 vfGroundAdjustMax;
1772 : Real64 vfGroundAdjustMin;
1773 0 : if (viewFactorToGround > viewFactorToShelf) { // How much view to ground could be reduced potentially if shelf at bottom
1774 0 : vfGroundAdjustMin = viewFactorToGround - viewFactorToShelf;
1775 : } else {
1776 0 : vfGroundAdjustMin = 0.0;
1777 : }
1778 0 : if (viewFactorToGround > leftoverViewFactor) { // How much view to ground could be reduced potentially if shelf at top
1779 0 : vfGroundAdjustMax = leftoverViewFactor;
1780 : } else {
1781 0 : vfGroundAdjustMax = viewFactorToGround;
1782 : }
1783 0 : viewFactorToGround = vfGroundAdjustMin + heightRatio * (vfGroundAdjustMax - vfGroundAdjustMin);
1784 0 : viewFactorToSky = leftoverViewFactor - viewFactorToGround;
1785 : }
1786 0 : ShowWarningError(state,
1787 0 : format("DaylightingDevice:Shelf = {}: As a result of user input (see previous messages), at least one view factor but "
1788 : "possibly more than one was reduced.",
1789 0 : state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
1790 0 : ShowContinueError(state,
1791 : "These include the view factors to the ground, the sky, and the exterior light shelf. Note that views to other exterior "
1792 : "surfaces could further complicated this.");
1793 0 : ShowContinueError(state, "Please consider manually calculating or adjusting view factors to avoid this problem.");
1794 : }
1795 :
1796 2568509 : void FigureTDDZoneGains(EnergyPlusData &state)
1797 : {
1798 :
1799 : // SUBROUTINE INFORMATION:
1800 : // AUTHOR B. Griffith
1801 : // DATE WRITTEN Dec 2011
1802 : // MODIFIED na
1803 : // RE-ENGINEERED na
1804 :
1805 : // PURPOSE OF THIS SUBROUTINE:
1806 : // intialize zone gains at begin new environment
1807 :
1808 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1809 2568509 : auto &MyEnvrnFlag = state.dataDaylightingDevices->MyEnvrnFlag;
1810 : int Loop;
1811 :
1812 2568509 : if ((int)state.dataDaylightingDevicesData->TDDPipe.size() == 0) return;
1813 :
1814 2025 : if (state.dataGlobal->BeginEnvrnFlag && MyEnvrnFlag) {
1815 15 : for (Loop = 1; Loop <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++Loop) {
1816 10 : state.dataDaylightingDevicesData->TDDPipe(Loop).TZoneHeatGain = 0.0;
1817 : }
1818 5 : MyEnvrnFlag = false;
1819 : }
1820 2025 : if (!state.dataGlobal->BeginEnvrnFlag) MyEnvrnFlag = true;
1821 : }
1822 :
1823 : } // namespace DaylightingDevices
1824 :
1825 2313 : } // namespace EnergyPlus
|