LCOV - code coverage report
Current view: top level - EnergyPlus - DaylightingDevices.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 419 738 56.8 %
Date: 2023-01-17 19:17:23 Functions: 19 20 95.0 %

          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

Generated by: LCOV version 1.13