LCOV - code coverage report
Current view: top level - EnergyPlus - DaylightingDevices.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 414 756 54.8 %
Date: 2024-08-23 23:50:59 Functions: 15 15 100.0 %

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

Generated by: LCOV version 1.14