LCOV - code coverage report
Current view: top level - EnergyPlus - DaylightingDevices.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 24.5 % 756 185
Test Date: 2025-05-22 16:09:37 Functions: 46.7 % 15 7

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, 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 geometry.
     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          108 :     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            0 :             TDDPipeStoredData() : AspectRatio(0.0), Reflectance(0.0), TransBeam(NumOfAngles, 0.0)
     197              :             {
     198            0 :             }
     199              :         };
     200              : 
     201              :         // Object Data
     202          108 :         Array1D<TDDPipeStoredData> TDDPipeStored;
     203              : 
     204              :         // Initialize tubular daylighting devices (TDDs)
     205          108 :         GetTDDInput(state);
     206              : 
     207          108 :         if ((int)state.dataDaylightingDevicesData->TDDPipe.size() > 0) {
     208            0 :             DisplayString(state, "Initializing Tubular Daylighting Devices");
     209              :             // Setup COSAngle list for all TDDs
     210            0 :             state.dataDaylightingDevices->COSAngle(1) = 0.0;
     211            0 :             state.dataDaylightingDevices->COSAngle(NumOfAngles) = 1.0;
     212              : 
     213            0 :             Real64 dTheta = 90.0 * Constant::DegToRad / (NumOfAngles - 1.0);
     214            0 :             Real64 Theta = 90.0 * Constant::DegToRad;
     215            0 :             for (int AngleNum = 2; AngleNum <= NumOfAngles - 1; ++AngleNum) {
     216            0 :                 Theta -= dTheta;
     217            0 :                 state.dataDaylightingDevices->COSAngle(AngleNum) = std::cos(Theta);
     218              :             } // AngleNum
     219              : 
     220            0 :             TDDPipeStored.allocate((int)state.dataDaylightingDevicesData->TDDPipe.size() * 2);
     221              : 
     222            0 :             for (int PipeNum = 1; PipeNum <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++PipeNum) {
     223              :                 // Initialize optical properties
     224            0 :                 state.dataDaylightingDevicesData->TDDPipe(PipeNum).AspectRatio =
     225            0 :                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TotLength / state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diameter;
     226            0 :                 state.dataDaylightingDevicesData->TDDPipe(PipeNum).ReflectVis =
     227            0 :                     1.0 - state.dataConstruction->Construct(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Construction).InsideAbsorpVis;
     228            0 :                 state.dataDaylightingDevicesData->TDDPipe(PipeNum).ReflectSol =
     229            0 :                     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            0 :                 Real64 Reflectance = state.dataDaylightingDevicesData->TDDPipe(PipeNum).ReflectVis;
     234            0 :                 int NumStored = 0; // Counter for number of pipes stored as they are calculated
     235              :                 int StoredNum;     // Stored TDD pipe object number
     236            0 :                 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            0 :                     bool Found = false;
     239            0 :                     for (StoredNum = 1; StoredNum <= NumStored; ++StoredNum) {
     240            0 :                         if (TDDPipeStored(StoredNum).AspectRatio != state.dataDaylightingDevicesData->TDDPipe(PipeNum).AspectRatio) continue;
     241            0 :                         if (TDDPipeStored(StoredNum).Reflectance == Reflectance) {
     242            0 :                             Found = true; // StoredNum points to the matching TDDPipeStored
     243            0 :                             break;
     244              :                         }
     245              :                     } // StoredNum
     246              : 
     247            0 :                     if (!Found) { // Not yet calculated
     248              : 
     249              :                         // Add a new pipe to TDDPipeStored
     250            0 :                         ++NumStored;
     251            0 :                         TDDPipeStored(NumStored).AspectRatio = state.dataDaylightingDevicesData->TDDPipe(PipeNum).AspectRatio;
     252            0 :                         TDDPipeStored(NumStored).Reflectance = Reflectance;
     253              : 
     254              :                         // Set beam transmittances for 0 and 90 degrees
     255            0 :                         TDDPipeStored(NumStored).TransBeam(1) = 0.0;
     256            0 :                         TDDPipeStored(NumStored).TransBeam(NumOfAngles) = 1.0;
     257              : 
     258              :                         // Calculate intermediate beam transmittances between 0 and 90 degrees
     259            0 :                         Theta = 90.0 * Constant::DegToRad;
     260            0 :                         for (int AngleNum = 2; AngleNum <= NumOfAngles - 1; ++AngleNum) {
     261            0 :                             Theta -= dTheta;
     262            0 :                             TDDPipeStored(NumStored).TransBeam(AngleNum) =
     263            0 :                                 CalcPipeTransBeam(Reflectance, state.dataDaylightingDevicesData->TDDPipe(PipeNum).AspectRatio, Theta);
     264              :                         } // AngleNum
     265              : 
     266            0 :                         StoredNum = NumStored;
     267              :                     }
     268              : 
     269              :                     // Assign stored values to TDDPipe
     270            0 :                     if (Loop == 1) { // Visible
     271            0 :                         state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeTransVisBeam = TDDPipeStored(StoredNum).TransBeam;
     272              :                     } else { // Solar
     273            0 :                         state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeTransSolBeam = TDDPipeStored(StoredNum).TransBeam;
     274              :                     }
     275              : 
     276              :                     // Second time thru use the solar reflectance
     277            0 :                     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            0 :                 state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolIso = CalcTDDTransSolIso(state, PipeNum);
     282            0 :                 state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolHorizon = CalcTDDTransSolHorizon(state, PipeNum);
     283              : 
     284              :                 // Initialize thermal properties
     285            0 :                 Real64 SumTZoneLengths = 0.0;
     286            0 :                 for (int TZoneNum = 1; TZoneNum <= state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones; ++TZoneNum) {
     287            0 :                     SumTZoneLengths += state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength(TZoneNum);
     288              : 
     289            0 :                     SetupZoneInternalGain(state,
     290            0 :                                           state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZone(TZoneNum),
     291            0 :                                           state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name,
     292              :                                           DataHeatBalance::IntGainType::DaylightingDeviceTubular,
     293            0 :                                           &state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneHeatGain(TZoneNum));
     294              : 
     295              :                 } // TZoneNum
     296              : 
     297            0 :                 state.dataDaylightingDevicesData->TDDPipe(PipeNum).ExtLength =
     298            0 :                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TotLength - SumTZoneLengths;
     299              : 
     300              :                 // Setup report variables: CurrentModuleObject='DaylightingDevice:Tubular'
     301            0 :                 SetupOutputVariable(state,
     302              :                                     "Tubular Daylighting Device Transmitted Solar Radiation Rate",
     303              :                                     Constant::Units::W,
     304            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransmittedSolar,
     305              :                                     OutputProcessor::TimeStepType::Zone,
     306              :                                     OutputProcessor::StoreType::Average,
     307            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
     308            0 :                 SetupOutputVariable(state,
     309              :                                     "Tubular Daylighting Device Pipe Absorbed Solar Radiation Rate",
     310              :                                     Constant::Units::W,
     311            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeAbsorbedSolar,
     312              :                                     OutputProcessor::TimeStepType::Zone,
     313              :                                     OutputProcessor::StoreType::Average,
     314            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
     315            0 :                 SetupOutputVariable(state,
     316              :                                     "Tubular Daylighting Device Heat Gain Rate",
     317              :                                     Constant::Units::W,
     318            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).HeatGain,
     319              :                                     OutputProcessor::TimeStepType::Zone,
     320              :                                     OutputProcessor::StoreType::Average,
     321            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
     322            0 :                 SetupOutputVariable(state,
     323              :                                     "Tubular Daylighting Device Heat Loss Rate",
     324              :                                     Constant::Units::W,
     325            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).HeatLoss,
     326              :                                     OutputProcessor::TimeStepType::Zone,
     327              :                                     OutputProcessor::StoreType::Average,
     328            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
     329              : 
     330            0 :                 SetupOutputVariable(state,
     331              :                                     "Tubular Daylighting Device Beam Solar Transmittance",
     332              :                                     Constant::Units::None,
     333            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolBeam,
     334              :                                     OutputProcessor::TimeStepType::Zone,
     335              :                                     OutputProcessor::StoreType::Average,
     336            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
     337            0 :                 SetupOutputVariable(state,
     338              :                                     "Tubular Daylighting Device Beam Visible Transmittance",
     339              :                                     Constant::Units::None,
     340            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransVisBeam,
     341              :                                     OutputProcessor::TimeStepType::Zone,
     342              :                                     OutputProcessor::StoreType::Average,
     343            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
     344            0 :                 SetupOutputVariable(state,
     345              :                                     "Tubular Daylighting Device Diffuse Solar Transmittance",
     346              :                                     Constant::Units::None,
     347            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolDiff,
     348              :                                     OutputProcessor::TimeStepType::Zone,
     349              :                                     OutputProcessor::StoreType::Average,
     350            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
     351            0 :                 SetupOutputVariable(state,
     352              :                                     "Tubular Daylighting Device Diffuse Visible Transmittance",
     353              :                                     Constant::Units::None,
     354            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransVisDiff,
     355              :                                     OutputProcessor::TimeStepType::Zone,
     356              :                                     OutputProcessor::StoreType::Average,
     357            0 :                                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name);
     358              : 
     359              :             } // PipeNum
     360              : 
     361            0 :             TDDPipeStored.deallocate();
     362              :         }
     363              : 
     364              :         // Initialize daylighting shelves
     365          108 :         GetShelfInput(state);
     366              : 
     367          108 :         if ((int)state.dataDaylightingDevicesData->Shelf.size() > 0) DisplayString(state, "Initializing Light Shelf Daylighting Devices");
     368              : 
     369          108 :         for (int ShelfNum = 1; ShelfNum <= (int)state.dataDaylightingDevicesData->Shelf.size(); ++ShelfNum) {
     370            0 :             int WinSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).Window;
     371              : 
     372            0 :             int ShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).InSurf;
     373            0 :             if (ShelfSurf > 0) {
     374              :                 // Double surface area so that both sides of the shelf are treated as internal mass
     375            0 :                 state.dataSurface->Surface(ShelfSurf).Area *= 2.0;
     376              :             }
     377              : 
     378            0 :             ShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf;
     379            0 :             if (ShelfSurf > 0) {
     380            0 :                 state.dataDaylightingDevicesData->Shelf(ShelfNum).OutReflectVis =
     381            0 :                     1.0 - state.dataConstruction->Construct(state.dataDaylightingDevicesData->Shelf(ShelfNum).Construction).OutsideAbsorpVis;
     382            0 :                 state.dataDaylightingDevicesData->Shelf(ShelfNum).OutReflectSol =
     383            0 :                     1.0 - state.dataConstruction->Construct(state.dataDaylightingDevicesData->Shelf(ShelfNum).Construction).OutsideAbsorpSolar;
     384              : 
     385            0 :                 if (state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor < 0) CalcViewFactorToShelf(state, ShelfNum);
     386              : 
     387            0 :                 adjustViewFactorsWithShelf(state,
     388            0 :                                            state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor,
     389            0 :                                            state.dataSurface->Surface(WinSurf).ViewFactorSky,
     390            0 :                                            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            0 :                 if (!state.dataDaylightingDevices->ShelfReported) {
     396            0 :                     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            0 :                     state.dataDaylightingDevices->ShelfReported = true;
     399              :                 }
     400            0 :                 print(state.files.eio,
     401              :                       "{},{:.2R},{},{:.2R},{:.2R}\n",
     402            0 :                       state.dataDaylightingDevicesData->Shelf(ShelfNum).Name,
     403            0 :                       state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor,
     404            0 :                       state.dataSurface->Surface(WinSurf).Name,
     405            0 :                       state.dataSurface->Surface(WinSurf).ViewFactorSky,
     406            0 :                       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          108 :         if (state.dataSurface->CalcSolRefl &&
     417            0 :             ((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          108 :     }
     423              : 
     424          110 :     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          110 :         auto &ipsc = state.dataIPShortCut;
     438          110 :         auto &cCurrentModuleObject = ipsc->cCurrentModuleObject;
     439              : 
     440          110 :         cCurrentModuleObject = "DaylightingDevice:Tubular";
     441          110 :         int NumOfTDDPipes = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     442              : 
     443          110 :         if (NumOfTDDPipes > 0) {
     444            2 :             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            6 :             for (int PipeNum = 1; PipeNum <= NumOfTDDPipes; ++PipeNum) {
     450            8 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     451              :                                                                          cCurrentModuleObject,
     452              :                                                                          PipeNum,
     453            4 :                                                                          ipsc->cAlphaArgs,
     454              :                                                                          NumAlphas,
     455            4 :                                                                          ipsc->rNumericArgs,
     456              :                                                                          NumNumbers,
     457              :                                                                          IOStatus,
     458            4 :                                                                          ipsc->lNumericFieldBlanks,
     459            4 :                                                                          ipsc->lAlphaFieldBlanks,
     460            4 :                                                                          ipsc->cAlphaFieldNames,
     461            4 :                                                                          ipsc->cNumericFieldNames);
     462              :                 // Pipe name
     463            4 :                 state.dataDaylightingDevicesData->TDDPipe(PipeNum).Name = ipsc->cAlphaArgs(1);
     464              : 
     465              :                 // Get TDD:DOME object
     466            4 :                 int SurfNum = Util::FindItemInList(ipsc->cAlphaArgs(2), state.dataSurface->Surface);
     467              : 
     468            4 :                 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            4 :                     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            4 :                     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            4 :                     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            4 :                     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            4 :                     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            4 :                     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            4 :                     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            4 :                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome = SurfNum;
     536            4 :                     state.dataSurface->SurfWinTDDPipeNum(SurfNum) = PipeNum;
     537              :                 }
     538              : 
     539              :                 // Get TDD:DIFFUSER object
     540            4 :                 SurfNum = Util::FindItemInList(ipsc->cAlphaArgs(3), state.dataSurface->Surface);
     541              : 
     542            4 :                 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            4 :                     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            4 :                     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            4 :                     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            4 :                     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            8 :                     if (state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome > 0 &&
     589            4 :                         std::abs(state.dataSurface->Surface(SurfNum).Area -
     590            4 :                                  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            4 :                     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            4 :                     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            4 :                     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            4 :                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diffuser = SurfNum;
     644            4 :                     state.dataSurface->SurfWinTDDPipeNum(SurfNum) = PipeNum;
     645              :                 }
     646              : 
     647              :                 // Construction
     648            4 :                 state.dataDaylightingDevicesData->TDDPipe(PipeNum).Construction =
     649            4 :                     Util::FindItemInList(ipsc->cAlphaArgs(4), state.dataConstruction->Construct);
     650              : 
     651            4 :                 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            4 :                     state.dataConstruction->Construct(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Construction).IsUsed = true;
     657              :                 }
     658              : 
     659            4 :                 if (ipsc->rNumericArgs(1) > 0) {
     660            4 :                     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            4 :                 Real64 PipeArea = 0.25 * Constant::Pi * pow_2(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diameter);
     667            8 :                 if (state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome > 0 &&
     668            4 :                     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            4 :                 if (ipsc->rNumericArgs(2) > 0) {
     692            4 :                     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            4 :                 if (ipsc->rNumericArgs(3) > 0) {
     699            4 :                     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            4 :                 state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones = NumAlphas - 4;
     710              : 
     711            4 :                 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            4 :                 } 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            4 :                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZone.allocate(state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones);
     722            8 :                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength.allocate(
     723            4 :                         state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones);
     724            8 :                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneHeatGain.allocate(
     725            4 :                         state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones);
     726              : 
     727            4 :                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZone = 0;
     728            4 :                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength = 0.0;
     729            4 :                     state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneHeatGain = 0.0;
     730              : 
     731            8 :                     for (int TZoneNum = 1; TZoneNum <= state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones; ++TZoneNum) {
     732            4 :                         std::string const TZoneName = ipsc->cAlphaArgs(TZoneNum + 4);
     733            4 :                         state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZone(TZoneNum) = Util::FindItemInList(TZoneName, state.dataHeatBal->Zone);
     734            4 :                         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            4 :                         state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength(TZoneNum) = ipsc->rNumericArgs(TZoneNum + 3);
     741            4 :                         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            4 :                     } // TZoneNum
     750              :                 }
     751              : 
     752              :             } // PipeNum
     753              : 
     754            2 :             if (state.dataDaylightingDevices->GetTDDInputErrorsFound) ShowFatalError(state, "Errors in DaylightingDevice:Tubular input.");
     755            2 :             state.dataDayltg->TDDTransVisBeam.allocate(Constant::iHoursInDay, NumOfTDDPipes);
     756            2 :             state.dataDayltg->TDDFluxInc.allocate(Constant::iHoursInDay, NumOfTDDPipes);
     757            2 :             state.dataDayltg->TDDFluxTrans.allocate(Constant::iHoursInDay, NumOfTDDPipes);
     758           50 :             for (int hr = 1; hr <= Constant::iHoursInDay; ++hr) {
     759          144 :                 for (int tddNum = 1; tddNum <= NumOfTDDPipes; ++tddNum) {
     760           96 :                     state.dataDayltg->TDDTransVisBeam(hr, tddNum) = 0.0;
     761          384 :                     state.dataDayltg->TDDFluxInc(hr, tddNum) = Illums();
     762          384 :                     state.dataDayltg->TDDFluxTrans(hr, tddNum) = Illums();
     763              :                 } // for (tddNum)
     764              :             }     // for (hr)
     765              :         }
     766          110 :     }
     767              : 
     768          108 :     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          108 :         auto &ipsc = state.dataIPShortCut;
     782          108 :         auto &cCurrentModuleObject = ipsc->cCurrentModuleObject;
     783              : 
     784          108 :         cCurrentModuleObject = "DaylightingDevice:Shelf";
     785          108 :         int NumOfShelf = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
     786              : 
     787          108 :         if (NumOfShelf > 0) {
     788            0 :             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            0 :             for (int ShelfNum = 1; ShelfNum <= NumOfShelf; ++ShelfNum) {
     794            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     795              :                                                                          cCurrentModuleObject,
     796              :                                                                          ShelfNum,
     797            0 :                                                                          ipsc->cAlphaArgs,
     798              :                                                                          NumAlphas,
     799            0 :                                                                          ipsc->rNumericArgs,
     800              :                                                                          NumNumbers,
     801              :                                                                          IOStatus,
     802            0 :                                                                          ipsc->lNumericFieldBlanks,
     803            0 :                                                                          ipsc->lAlphaFieldBlanks,
     804            0 :                                                                          ipsc->cAlphaFieldNames,
     805            0 :                                                                          ipsc->cNumericFieldNames);
     806              :                 // Shelf name
     807            0 :                 state.dataDaylightingDevicesData->Shelf(ShelfNum).Name = ipsc->cAlphaArgs(1);
     808              : 
     809              :                 // Get window object
     810            0 :                 int SurfNum = Util::FindItemInList(ipsc->cAlphaArgs(2), state.dataSurface->Surface);
     811              : 
     812            0 :                 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            0 :                     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            0 :                     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            0 :                     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            0 :                     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            0 :                     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            0 :                     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            0 :                     state.dataDaylightingDevicesData->Shelf(ShelfNum).Window = SurfNum;
     867            0 :                     state.dataSurface->SurfDaylightingShelfInd(SurfNum) = ShelfNum;
     868              :                 }
     869              : 
     870              :                 // Get inside shelf heat transfer surface (optional)
     871            0 :                 if (ipsc->cAlphaArgs(3) != "") {
     872            0 :                     SurfNum = Util::FindItemInList(ipsc->cAlphaArgs(3), state.dataSurface->Surface);
     873              : 
     874            0 :                     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            0 :                         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            0 :                         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            0 :                         state.dataDaylightingDevicesData->Shelf(ShelfNum).InSurf = SurfNum;
     899              :                     }
     900              :                 }
     901              : 
     902              :                 // Get outside shelf attached shading surface (optional)
     903            0 :                 if (ipsc->cAlphaArgs(4) != "") {
     904            0 :                     SurfNum = Util::FindItemInList(ipsc->cAlphaArgs(4), state.dataSurface->Surface);
     905              : 
     906            0 :                     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            0 :                         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            0 :                         if (state.dataSurface->Surface(SurfNum).shadowSurfSched != nullptr) {
     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            0 :                         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            0 :                         int ConstrNum = 0;
     940              :                         // Get outside shelf construction (required if outside shelf is specified)
     941            0 :                         if (ipsc->cAlphaArgs(5) != "") {
     942            0 :                             ConstrNum = Util::FindItemInList(ipsc->cAlphaArgs(5), state.dataConstruction->Construct);
     943              : 
     944            0 :                             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            0 :                             } 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            0 :                                 state.dataDaylightingDevicesData->Shelf(ShelfNum).Construction = ConstrNum;
     960            0 :                                 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            0 :                         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            0 :                             state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor =
     982              :                                 -1.0; // Flag to have the view factor calculated during initialization
     983              :                         }
     984              : 
     985            0 :                         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            0 :                         state.dataSurface->Surface(SurfNum).BaseSurf = SurfNum;
     990            0 :                         state.dataSurface->Surface(SurfNum).HeatTransSurf = true;
     991            0 :                         state.dataSurface->AllHTSurfaceList.push_back(SurfNum);
     992              :                         // Is this needed? surfZone.ZoneHTNonWindowSurfaceList.push_back(SurfNum);
     993            0 :                         state.dataSurface->Surface(SurfNum).Construction = ConstrNum; // Kludge to allow shading surface to be a heat transfer surface
     994            0 :                         state.dataSurface->SurfActiveConstruction(SurfNum) = ConstrNum;
     995            0 :                         state.dataConstruction->Construct(ConstrNum).IsUsed = true;
     996              :                     }
     997              :                 }
     998              : 
     999            0 :                 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            0 :             if (state.dataDaylightingDevices->GetShelfInputErrorsFound) ShowFatalError(state, "Errors in DaylightingDevice:Shelf input.");
    1006              :         }
    1007          108 :     }
    1008              : 
    1009            0 :     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            0 :         Real64 constexpr N(100000.0); // Number of integration points
    1048            0 :         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            0 :         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            0 :         CalcPipeTransBeam = 0.0;
    1063              : 
    1064            0 :         T = 0.0;
    1065            0 :         i = 1.0 / N;
    1066              : 
    1067            0 :         xLimit = (std::log(pow_2(N) * myLocalTiny) / std::log(R)) / xTol;
    1068              : 
    1069            0 :         c1 = A * std::tan(Theta);
    1070            0 :         c2 = 4.0 / Constant::Pi;
    1071              : 
    1072            0 :         s = i;
    1073            0 :         while (s < (1.0 - i)) {
    1074            0 :             x = c1 / s;
    1075              : 
    1076            0 :             if (x < xLimit) {
    1077            0 :                 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            0 :                 T += dT;
    1079              :             }
    1080              : 
    1081            0 :             s += i;
    1082              :         }
    1083              : 
    1084            0 :         T /= (N - 1.0); // - 1.0, because started on i, not 0
    1085              : 
    1086            0 :         CalcPipeTransBeam = T;
    1087              : 
    1088            0 :         return CalcPipeTransBeam;
    1089              :     }
    1090              : 
    1091            0 :     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            0 :         int constexpr NPH(1000); // Number of altitude integration points
    1124              : 
    1125              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1126            0 :         Real64 FluxInc = 0.0;   // Incident solar flux
    1127            0 :         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            0 :         Real64 const dPH = 90.0 * Constant::DegToRad / NPH; // Altitude angle of sky element
    1133            0 :         Real64 PH = 0.5 * dPH;                              // Altitude angle increment
    1134              : 
    1135              :         // Integrate from 0 to Pi/2 altitude
    1136            0 :         for (int N = 1; N <= NPH; ++N) {
    1137            0 :             COSI = std::cos(Constant::PiOvr2 - PH);
    1138            0 :             SINI = std::sin(Constant::PiOvr2 - PH);
    1139              : 
    1140            0 :             Real64 P = COSI; // Angular distribution function: P = COS(Incident Angle) for diffuse isotropic
    1141              : 
    1142              :             // Calculate total TDD transmittance for given angle
    1143            0 :             trans = TransTDD(state, PipeNum, COSI, RadType::SolarBeam);
    1144              : 
    1145            0 :             FluxInc += P * SINI * dPH;
    1146            0 :             FluxTrans += trans * P * SINI * dPH;
    1147              : 
    1148            0 :             PH += dPH; // Increment the altitude angle
    1149              :         }              // N
    1150              : 
    1151            0 :         CalcTDDTransSolIso = FluxTrans / FluxInc;
    1152              : 
    1153            0 :         return CalcTDDTransSolIso;
    1154              :     }
    1155              : 
    1156            0 :     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            0 :         int constexpr NTH(18); // Number of azimuth integration points
    1189              : 
    1190              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1191            0 :         Real64 FluxInc = 0.0;   // Incident solar flux
    1192            0 :         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            0 :         CosPhi = std::cos(Constant::PiOvr2 -
    1197            0 :                           state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Tilt * Constant::DegToRad);
    1198            0 :         Theta = state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Azimuth * Constant::DegToRad;
    1199              : 
    1200            0 :         if (CosPhi > 0.01) { // Dome has a view of the horizon
    1201              :             // Integrate over the semicircle
    1202            0 :             Real64 const THMIN = Theta - Constant::PiOvr2; // Minimum azimuth integration limit
    1203              :             // Real64 const THMAX = Theta + PiOvr2; // Maximum azimuth integration limit
    1204            0 :             Real64 const dTH = 180.0 * Constant::DegToRad / NTH; // Azimuth angle increment
    1205            0 :             Real64 TH = THMIN + 0.5 * dTH;                       // Azimuth angle of sky horizon element
    1206              : 
    1207            0 :             for (int N = 1; N <= NTH; ++N) {
    1208              :                 // Calculate incident angle between dome outward normal and horizon element
    1209            0 :                 Real64 COSI = CosPhi * std::cos(TH - Theta); // Cosine of the incident angle
    1210              : 
    1211              :                 // Calculate total TDD transmittance for given angle
    1212            0 :                 Real64 trans = TransTDD(state, PipeNum, COSI, RadType::SolarBeam); // Total beam solar transmittance of TDD
    1213              : 
    1214            0 :                 FluxInc += COSI * dTH;
    1215            0 :                 FluxTrans += trans * COSI * dTH;
    1216              : 
    1217            0 :                 TH += dTH; // Increment the azimuth angle
    1218              :             }              // N
    1219              : 
    1220            0 :             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            0 :         return CalcTDDTransSolHorizon;
    1227              :     }
    1228              : 
    1229            0 :     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            0 :         DomeSurf = state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome;
    1273              : 
    1274            0 :         if (!state.dataSysVars->DetailedSkyDiffuseAlgorithm || !state.dataSurface->ShadingTransmittanceVaries ||
    1275            0 :             state.dataHeatBal->SolarDistribution == DataHeatBalance::Shadowing::Minimal) {
    1276            0 :             IsoSkyRad = state.dataSolarShading->SurfMultIsoSky(DomeSurf) * state.dataSolarShading->SurfDifShdgRatioIsoSky(DomeSurf);
    1277            0 :             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            0 :         CircumSolarRad = state.dataSolarShading->SurfMultCircumSolar(DomeSurf) *
    1284            0 :                          state.dataHeatBal->SurfSunlitFrac(state.dataGlobal->HourOfDay, state.dataGlobal->TimeStep, DomeSurf);
    1285              : 
    1286            0 :         AnisoSkyTDDMult = state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolIso * IsoSkyRad +
    1287            0 :                           TransTDD(state, PipeNum, COSI, RadType::SolarBeam) * CircumSolarRad +
    1288            0 :                           state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolHorizon * HorizonRad;
    1289              : 
    1290            0 :         if (state.dataSolarShading->SurfAnisoSkyMult(DomeSurf) > 0.0) {
    1291            0 :             CalcTDDTransSolAniso = AnisoSkyTDDMult / state.dataSolarShading->SurfAnisoSkyMult(DomeSurf);
    1292              :         } else {
    1293            0 :             CalcTDDTransSolAniso = 0.0;
    1294              :         }
    1295              : 
    1296            0 :         return CalcTDDTransSolAniso;
    1297              :     }
    1298              : 
    1299            0 :     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              :         // Return value
    1332              :         Real64 TransTDD;
    1333              : 
    1334              :         // Locals
    1335              :         // FUNCTION ARGUMENT DEFINITIONS:
    1336              : 
    1337              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1338              :         int constDome; // Construction object number for TDD:DOME
    1339              :         int constDiff; // Construction object number for TDD:DIFFUSER
    1340              :         Real64 transDome;
    1341              :         Real64 transPipe;
    1342              :         Real64 transDiff;
    1343              : 
    1344            0 :         TransTDD = 0.0;
    1345              : 
    1346              :         // Get constructions of each TDD component
    1347            0 :         constDome = state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome).Construction;
    1348            0 :         constDiff = state.dataSurface->Surface(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diffuser).Construction;
    1349              : 
    1350              :         // Get the transmittance of each component and of total TDD
    1351            0 :         switch (RadiationType) {
    1352            0 :         case RadType::VisibleBeam: {
    1353            0 :             transDome = Window::POLYF(COSI, state.dataConstruction->Construct(constDome).TransVisBeamCoef);
    1354            0 :             transPipe = InterpolatePipeTransBeam(state, COSI, state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeTransVisBeam);
    1355            0 :             transDiff = state.dataConstruction->Construct(constDiff).TransDiffVis; // May want to change to POLYF also!
    1356              : 
    1357            0 :             TransTDD = transDome * transPipe * transDiff;
    1358              : 
    1359            0 :         } break;
    1360            0 :         case RadType::SolarBeam: {
    1361            0 :             transDome = Window::POLYF(COSI, state.dataConstruction->Construct(constDome).TransSolBeamCoef);
    1362            0 :             transPipe = InterpolatePipeTransBeam(state, COSI, state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeTransSolBeam);
    1363            0 :             transDiff = state.dataConstruction->Construct(constDiff).TransDiff; // May want to change to POLYF also!
    1364              : 
    1365            0 :             TransTDD = transDome * transPipe * transDiff;
    1366              : 
    1367            0 :         } break;
    1368            0 :         case RadType::SolarAniso: {
    1369            0 :             TransTDD = CalcTDDTransSolAniso(state, PipeNum, COSI);
    1370            0 :         } break;
    1371            0 :         case RadType::SolarIso: {
    1372            0 :             TransTDD = state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolIso;
    1373            0 :         } break;
    1374            0 :         default:
    1375            0 :             break;
    1376              :         }
    1377              : 
    1378            0 :         return TransTDD;
    1379              :     }
    1380              : 
    1381            0 :     Real64 InterpolatePipeTransBeam(EnergyPlusData &state,
    1382              :                                     Real64 const COSI,               // Cosine of the incident angle
    1383              :                                     const Array1D<Real64> &transBeam // Table of beam transmittance vs. cosine angle
    1384              :     )
    1385              :     {
    1386              : 
    1387              :         // SUBROUTINE INFORMATION:
    1388              :         //       AUTHOR         Peter Graham Ellis
    1389              :         //       DATE WRITTEN   July 2003
    1390              :         //       MODIFIED       na
    1391              :         //       RE-ENGINEERED  na
    1392              : 
    1393              :         // PURPOSE OF THIS SUBROUTINE:
    1394              :         // Interpolates the beam transmittance vs. cosine angle table.
    1395              : 
    1396              :         // METHODOLOGY EMPLOYED: na
    1397              :         // REFERENCES: na
    1398              : 
    1399              :         // Using/Aliasing
    1400              :         using Fluid::FindArrayIndex; // USEd code could be copied here to eliminate dependence on FluidProperties
    1401              : 
    1402              :         // Return value
    1403              :         Real64 InterpolatePipeTransBeam;
    1404              : 
    1405              :         // Argument array dimensioning
    1406            0 :         EP_SIZE_CHECK(transBeam, NumOfAngles);
    1407              : 
    1408              :         // Locals
    1409              :         // FUNCTION ARGUMENT DEFINITIONS:
    1410              : 
    1411              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1412              :         int Lo;
    1413              :         int Hi;
    1414              :         Real64 m;
    1415              :         Real64 b;
    1416              : 
    1417            0 :         InterpolatePipeTransBeam = 0.0;
    1418              : 
    1419              :         // Linearly interpolate transBeam/COSAngle table to get value at current cosine of the angle
    1420            0 :         Lo = FindArrayIndex(COSI, state.dataDaylightingDevices->COSAngle);
    1421            0 :         Hi = Lo + 1;
    1422              : 
    1423            0 :         if (Lo > 0 && Hi <= NumOfAngles) {
    1424            0 :             m = (transBeam(Hi) - transBeam(Lo)) / (state.dataDaylightingDevices->COSAngle(Hi) - state.dataDaylightingDevices->COSAngle(Lo));
    1425            0 :             b = transBeam(Lo) - m * state.dataDaylightingDevices->COSAngle(Lo);
    1426              : 
    1427            0 :             InterpolatePipeTransBeam = m * COSI + b;
    1428              :         } else {
    1429            0 :             InterpolatePipeTransBeam = 0.0;
    1430              :         }
    1431              : 
    1432            0 :         return InterpolatePipeTransBeam;
    1433              :     }
    1434              : 
    1435            8 :     int FindTDDPipe(EnergyPlusData &state, int const WinNum)
    1436              :     {
    1437              : 
    1438              :         // SUBROUTINE INFORMATION:
    1439              :         //       AUTHOR         Peter Graham Ellis
    1440              :         //       DATE WRITTEN   May 2003
    1441              :         //       MODIFIED       na
    1442              :         //       RE-ENGINEERED  na
    1443              : 
    1444              :         // PURPOSE OF THIS SUBROUTINE:
    1445              :         // Given the TDD:DOME or TDD:DIFFUSER object number, returns TDD pipe number.
    1446              : 
    1447              :         // Return value
    1448              :         int FindTDDPipe;
    1449              : 
    1450              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1451              :         int PipeNum; // TDD pipe object number
    1452              : 
    1453            8 :         FindTDDPipe = 0;
    1454              : 
    1455            8 :         if ((int)state.dataDaylightingDevicesData->TDDPipe.size() <= 0) {
    1456            0 :             ShowFatalError(state,
    1457            0 :                            format("FindTDDPipe: Surface={}, TDD:Dome object does not reference a valid Diffuser object....needs "
    1458              :                                   "DaylightingDevice:Tubular of same name as Surface.",
    1459            0 :                                   state.dataSurface->Surface(WinNum).Name));
    1460              :         }
    1461              : 
    1462           24 :         for (PipeNum = 1; PipeNum <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++PipeNum) {
    1463           32 :             if ((WinNum == state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome) ||
    1464           16 :                 (WinNum == state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diffuser)) {
    1465            0 :                 FindTDDPipe = PipeNum;
    1466            0 :                 break;
    1467              :             }
    1468              :         } // PipeNum
    1469              : 
    1470            8 :         return FindTDDPipe;
    1471              :     }
    1472              : 
    1473       249958 :     void DistributeTDDAbsorbedSolar(EnergyPlusData &state)
    1474              :     {
    1475              : 
    1476              :         // SUBROUTINE INFORMATION:
    1477              :         //       AUTHOR         Peter Graham Ellis
    1478              :         //       DATE WRITTEN   July 2003
    1479              :         //       MODIFIED       na
    1480              :         //       RE-ENGINEERED  na
    1481              : 
    1482              :         // PURPOSE OF THIS SUBROUTINE:
    1483              :         // Sums the absorbed solar gains from TDD pipes that pass through transition zones.
    1484              : 
    1485              :         // METHODOLOGY EMPLOYED:
    1486              :         // The total absorbed solar gain is a sum of the following gains:
    1487              :         //   1. Inward bound solar absorbed by multiple pipe reflections (solar entering pipe - solar exiting pipe)
    1488              :         //   2. Outward bound solar absorbed by multiple pipe reflections due to:
    1489              :         //     a. Reflection off of diffuser surface (inside of TDD)
    1490              :         //     b. Zone diffuse interior shortwave incident on the diffuser from windows, lights, etc.
    1491              :         //   3. Inward absorbed solar in dome and diffuser glass
    1492              :         // This subroutine is called by InitIntSolarDistribution in HeatBalanceSurfaceManager.cc.
    1493              : 
    1494       249958 :         for (int PipeNum = 1; PipeNum <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++PipeNum) {
    1495            0 :             int DiffSurf = state.dataDaylightingDevicesData->TDDPipe(PipeNum).Diffuser;
    1496            0 :             Real64 transDiff = state.dataConstruction->Construct(state.dataSurface->Surface(DiffSurf).Construction).TransDiff;
    1497              : 
    1498              :             // Calculate diffuse solar reflected back up the pipe by the inside surface of the TDD:DIFFUSER
    1499              :             // All solar arriving at the diffuser is assumed to be isotropically diffuse by this point
    1500            0 :             Real64 QRefl = (state.dataHeatBal->SurfQRadSWOutIncident(DiffSurf) - state.dataHeatBal->SurfWinQRadSWwinAbsTot(DiffSurf)) *
    1501            0 :                                state.dataSurface->Surface(DiffSurf).Area -
    1502            0 :                            state.dataSurface->SurfWinTransSolar(DiffSurf);
    1503              : 
    1504              :             // Add diffuse interior shortwave reflected from zone surfaces and from zone sources, lights, etc.
    1505            0 :             QRefl += state.dataHeatBal->EnclSolQSWRad(state.dataSurface->Surface(DiffSurf).SolarEnclIndex) *
    1506            0 :                      state.dataSurface->Surface(DiffSurf).Area * transDiff;
    1507              : 
    1508            0 :             Real64 TotTDDPipeGain = state.dataSurface->SurfWinTransSolar(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome) -
    1509            0 :                                     state.dataHeatBal->SurfQRadSWOutIncident(DiffSurf) * state.dataSurface->Surface(DiffSurf).Area +
    1510            0 :                                     QRefl * (1.0 - state.dataDaylightingDevicesData->TDDPipe(PipeNum).TransSolIso / transDiff) +
    1511            0 :                                     state.dataHeatBal->SurfWinQRadSWwinAbs(state.dataDaylightingDevicesData->TDDPipe(PipeNum).Dome, 1) *
    1512            0 :                                         state.dataSurface->Surface(DiffSurf).Area / 2.0 +
    1513            0 :                                     state.dataHeatBal->SurfWinQRadSWwinAbs(DiffSurf, 1) * state.dataSurface->Surface(DiffSurf).Area /
    1514            0 :                                         2.0; // Solar entering pipe | Solar exiting pipe | Absorbed due to
    1515              :                                              // reflections on the way out | Inward absorbed solar from dome
    1516              :                                              // glass | Inward absorbed solar from diffuser glass
    1517            0 :             state.dataDaylightingDevicesData->TDDPipe(PipeNum).PipeAbsorbedSolar = max(0.0, TotTDDPipeGain); // Report variable [W]
    1518              : 
    1519            0 :             for (int TZoneNum = 1; TZoneNum <= state.dataDaylightingDevicesData->TDDPipe(PipeNum).NumOfTZones; ++TZoneNum) {
    1520              :                 // Distribute absorbed solar gain in proportion to transition zone length
    1521            0 :                 state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneHeatGain(TZoneNum) =
    1522            0 :                     TotTDDPipeGain * (state.dataDaylightingDevicesData->TDDPipe(PipeNum).TZoneLength(TZoneNum) /
    1523            0 :                                       state.dataDaylightingDevicesData->TDDPipe(PipeNum).TotLength);
    1524              :             } // TZoneNum
    1525              :         }
    1526       249958 :     }
    1527              : 
    1528            0 :     void CalcViewFactorToShelf(EnergyPlusData &state, int const ShelfNum) // Daylighting shelf object number
    1529              :     {
    1530              : 
    1531              :         // SUBROUTINE INFORMATION:
    1532              :         //       AUTHOR         Peter Graham Ellis
    1533              :         //       DATE WRITTEN   August 2003
    1534              :         //       MODIFIED       na
    1535              :         //       RE-ENGINEERED  na
    1536              : 
    1537              :         // PURPOSE OF THIS SUBROUTINE:
    1538              :         // Attempts to calculate exact analytical view factor from window to outside shelf.
    1539              : 
    1540              :         // METHODOLOGY EMPLOYED:
    1541              :         // Uses a standard analytical solution.  It is required that window and shelf have the same width, i.e.
    1542              :         // one edge (or two vertices) shared in common.  An error or warning is issued if not true.
    1543              :         // A more general routine should be implemented at some point to solve for more complicated geometries.
    1544              :         // Until then, the user has the option to specify their own solution for the view factor in the input object.
    1545              : 
    1546              :         // REFERENCES:
    1547              :         // Mills, A. F.  Heat and Mass Transfer, 1995, p. 499.  (Shape factor for adjacent rectangles.)
    1548              : 
    1549              :         // USE STATEMENTS:
    1550              : 
    1551              :         // Locals
    1552              :         // SUBROUTINE ARGUMENT DEFINITIONS:
    1553              : 
    1554              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1555              :         Real64 W; // Width, height, and length of window/shelf geometry
    1556              :         Real64 H;
    1557              :         Real64 L;
    1558              :         Real64 M; // Intermediate variables
    1559              :         Real64 N;
    1560              :         Real64 E1; // Intermediate equations
    1561              :         Real64 E2;
    1562              :         Real64 E3;
    1563              :         Real64 E4;
    1564              :         int VWin; // Vertex indices
    1565              :         int VShelf;
    1566              :         int NumMatch; // Number of vertices matched
    1567              : 
    1568            0 :         W = state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).Window).Width;
    1569            0 :         H = state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).Window).Height;
    1570              : 
    1571              :         // Find length, i.e. projection, of outside shelf
    1572            0 :         if (state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf).Width == W) {
    1573            0 :             L = state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf).Height;
    1574            0 :         } else if (state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf).Height == W) {
    1575            0 :             L = state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf).Width;
    1576              :         } else {
    1577            0 :             ShowFatalError(state,
    1578            0 :                            format("DaylightingDevice:Shelf = {}:  Width of window and outside shelf do not match.",
    1579            0 :                                   state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
    1580              :         }
    1581              : 
    1582              :         // Error if more or less than two vertices match
    1583            0 :         NumMatch = 0;
    1584            0 :         for (VWin = 1; VWin <= 4; ++VWin) {
    1585            0 :             for (VShelf = 1; VShelf <= 4; ++VShelf) {
    1586            0 :                 if (distance(state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).Window).Vertex(VWin),
    1587            0 :                              state.dataSurface->Surface(state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf).Vertex(VShelf)) == 0.0)
    1588            0 :                     ++NumMatch;
    1589              :             }
    1590              :         }
    1591              : 
    1592            0 :         if (NumMatch < 2) {
    1593            0 :             ShowWarningError(
    1594              :                 state,
    1595            0 :                 format("DaylightingDevice:Shelf = {}:  Window and outside shelf must share two vertices.  View factor calculation may be inaccurate.",
    1596            0 :                        state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
    1597            0 :         } else if (NumMatch > 2) {
    1598            0 :             ShowFatalError(state,
    1599            0 :                            format("DaylightingDevice:Shelf = {}:  Window and outside shelf share too many vertices.",
    1600            0 :                                   state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
    1601              :         }
    1602              : 
    1603              :         // Calculate exact analytical view factor from window to outside shelf
    1604            0 :         M = H / W;
    1605            0 :         N = L / W;
    1606              : 
    1607            0 :         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));
    1608            0 :         E2 = ((1.0 + pow_2(M)) * (1.0 + pow_2(N))) / (1.0 + pow_2(M) + pow_2(N));
    1609            0 :         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));
    1610            0 :         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));
    1611              : 
    1612            0 :         state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor = (1.0 / (Constant::Pi * M)) * (E1 + 0.25 * std::log(E2 * E3 * E4));
    1613            0 :     }
    1614              : 
    1615            9 :     void adjustViewFactorsWithShelf(
    1616              :         EnergyPlusData &state, Real64 &viewFactorToShelf, Real64 &viewFactorToSky, Real64 &viewFactorToGround, int WinSurf, int ShelfNum)
    1617              :     {
    1618              :         // First, make sure none of the view factors are less than zero and return if there isn't a problem or if
    1619              :         // view factor to shelf greater than one.  Both cases together would also eliminate if other views are zero
    1620              :         // which means nothing would need to be done.
    1621            9 :         if (viewFactorToSky <= 0.0) viewFactorToSky = 0.0;
    1622            9 :         if (viewFactorToGround <= 0.0) viewFactorToGround = 0.0;
    1623            9 :         if (viewFactorToShelf <= 0.0) { // No shelf impact for which to account
    1624            4 :             ShowWarningError(state,
    1625            4 :                              format("DaylightingDevice:Shelf = {}:  Window view factor to shelf was less than 0.  This should not happen.",
    1626            2 :                                     state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
    1627            4 :             ShowContinueError(state, "The view factor has been reset to zero.");
    1628            2 :             viewFactorToShelf = 0.0;
    1629            2 :             if ((viewFactorToGround + viewFactorToSky) > 1.0) { // This data came in incorrect, fix by proportional reduction
    1630            1 :                 viewFactorToGround = viewFactorToGround / (viewFactorToGround + viewFactorToSky);
    1631            1 :                 viewFactorToSky = 1.0 - viewFactorToGround;
    1632            2 :                 ShowWarningError(state,
    1633            2 :                                  format("DaylightingDevice:Shelf = {}:  The sum of the window view factors to ground and sky were greater than 1.  "
    1634              :                                         "This should not happen.",
    1635            1 :                                         state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
    1636            3 :                 ShowContinueError(
    1637              :                     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.");
    1638              :             }
    1639            2 :             return;
    1640              :         }
    1641            7 :         if (viewFactorToShelf + viewFactorToSky + viewFactorToGround <= 1.0) return; // nothing wrong here
    1642            5 :         if (viewFactorToShelf >= 1.0) { // Don't allow shelf view of greater than 1 (zero out other views)
    1643            2 :             ShowWarningError(state,
    1644            2 :                              format("DaylightingDevice:Shelf = {}:  Window view factor to shelf was greater than 1.  This should not happen.",
    1645            1 :                                     state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
    1646            2 :             ShowContinueError(state, "The view factor has been reset to 1 and the other view factors to sky and ground have been set to 0.");
    1647            1 :             viewFactorToShelf = 1.0;
    1648            1 :             viewFactorToGround = 0.0;
    1649            1 :             viewFactorToSky = 0.0;
    1650            1 :             return;
    1651              :         }
    1652              : 
    1653              :         // 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
    1654            4 :         int ShelfSurf = state.dataDaylightingDevicesData->Shelf(ShelfNum).OutSurf;
    1655            4 :         Real64 zShelfMax = state.dataSurface->Surface(ShelfSurf).Vertex(1).z;
    1656            4 :         Real64 zShelfMin = zShelfMax;
    1657           16 :         for (int vertex = 2; vertex <= state.dataSurface->Surface(ShelfSurf).Sides; ++vertex) {
    1658           12 :             if (state.dataSurface->Surface(ShelfSurf).Vertex(vertex).z > zShelfMax)
    1659            0 :                 zShelfMax = state.dataSurface->Surface(ShelfSurf).Vertex(vertex).z;
    1660           12 :             if (state.dataSurface->Surface(ShelfSurf).Vertex(vertex).z < zShelfMin)
    1661            0 :                 zShelfMin = state.dataSurface->Surface(ShelfSurf).Vertex(vertex).z;
    1662              :         }
    1663            4 :         Real64 zWinMax = state.dataSurface->Surface(WinSurf).Vertex(1).z;
    1664            4 :         Real64 zWinMin = zWinMax;
    1665           16 :         for (int vertex = 2; vertex <= state.dataSurface->Surface(WinSurf).Sides; ++vertex) {
    1666           12 :             if (state.dataSurface->Surface(WinSurf).Vertex(vertex).z > zWinMax) zWinMax = state.dataSurface->Surface(WinSurf).Vertex(vertex).z;
    1667           12 :             if (state.dataSurface->Surface(WinSurf).Vertex(vertex).z < zWinMin) zWinMin = state.dataSurface->Surface(WinSurf).Vertex(vertex).z;
    1668              :         }
    1669              : 
    1670              :         Real64 leftoverViewFactor;
    1671              :         // Now correct the view factors based on the location of the shelf with respect to the window
    1672            8 :         ShowWarningError(
    1673              :             state,
    1674            8 :             format("DaylightingDevice:Shelf = {}:  Window view factor to shelf [{:.2R}] results in a sum of view factors greater than 1.",
    1675            4 :                    state.dataDaylightingDevicesData->Shelf(ShelfNum).Name,
    1676            4 :                    state.dataDaylightingDevicesData->Shelf(ShelfNum).ViewFactor));
    1677            4 :         if (zWinMin >= zShelfMax) { // Shelf is fully below window, reduce view to ground first based on view to shelf
    1678            2 :             ShowContinueError(
    1679              :                 state,
    1680              :                 "Since the light shelf is below the window to which it is associated, the view factor of the window to the ground was reduced");
    1681            2 :             ShowContinueError(
    1682              :                 state, "and possibly also the view factor to the sky. Check you input and/or consider turning off autosizing of the view factors.");
    1683            1 :             leftoverViewFactor = 1.0 - viewFactorToShelf - viewFactorToSky;
    1684            1 :             if (leftoverViewFactor >= 0.0) {
    1685            1 :                 viewFactorToGround = leftoverViewFactor; // Other view factors okay
    1686              :             } else {
    1687            0 :                 viewFactorToGround = 0.0;
    1688            0 :                 viewFactorToSky = 1.0 - viewFactorToShelf;
    1689            0 :                 if (viewFactorToSky < 0.0) {
    1690            0 :                     viewFactorToSky = 0.0;
    1691            0 :                     viewFactorToShelf = 1.0;
    1692              :                 }
    1693              :             }
    1694              : 
    1695            3 :         } else if (zShelfMin >= zWinMax) { // Shelf is fully above window, reduce view to sky first based on view to shelf
    1696            2 :             ShowContinueError(
    1697              :                 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");
    1698            2 :             ShowContinueError(
    1699              :                 state,
    1700              :                 "and possibly also the view factor to the ground. Check you input and/or consider turning off autosizing of the view factors.");
    1701            1 :             leftoverViewFactor = 1.0 - viewFactorToShelf - viewFactorToGround;
    1702            1 :             if (leftoverViewFactor >= 0.0) {
    1703            1 :                 viewFactorToSky = leftoverViewFactor;
    1704              :             } else {
    1705            0 :                 viewFactorToSky = 0.0;
    1706            0 :                 viewFactorToGround = 1.0 - viewFactorToShelf;
    1707            0 :                 if (viewFactorToGround < 0.0) {
    1708            0 :                     viewFactorToGround = 0.0;
    1709            0 :                     viewFactorToShelf = 1.0;
    1710              :                 }
    1711              :             }
    1712              :         } else { // At least part of the shelf is somewhere in the middle of the window so we need to split out the view factors
    1713            4 :             ShowContinueError(
    1714              :                 state,
    1715              :                 "Since the light shelf is neither fully above or fully below the window to which it is associated, the view factor of the window");
    1716            4 :             ShowContinueError(
    1717              :                 state,
    1718              :                 "to the ground and sky were both potentially reduced. Check you input and/or consider turning off autosizing of the view factors.");
    1719              :             Real64 zShelfAvg;
    1720            2 :             if (((zShelfMin >= zWinMin) && (zShelfMax <= zWinMax)) || // Shelf does not go above or below the window
    1721            0 :                 ((zShelfMin < zWinMin) && (zShelfMax > zWinMax))) {   // Shelf goes both above AND below the window
    1722            2 :                 zShelfAvg = 0.5 * (zShelfMin + zShelfMax);
    1723            0 :             } else if (zShelfMin < zWinMin) { // Shelf goes partially below the window only
    1724            0 :                 Real64 fracAbove = 0.0;
    1725            0 :                 if (zShelfMax > zShelfMin) {
    1726            0 :                     fracAbove = (zShelfMax - zWinMin) / (zShelfMax - zShelfMin);
    1727            0 :                     if (fracAbove > 1.0) fracAbove = 1.0;
    1728              :                 }
    1729            0 :                 zShelfAvg = zWinMin + fracAbove * (zShelfMax - zWinMin);
    1730              :             } else { // (zShelfMax > zWinMax): Shelf goes partially above window
    1731            0 :                 Real64 fracBelow = 0.0;
    1732            0 :                 if (zShelfMax > zShelfMin) {
    1733            0 :                     fracBelow = (zWinMax - zShelfMin) / (zShelfMax - zShelfMin);
    1734              :                 }
    1735            0 :                 zShelfAvg = zWinMax - fracBelow * (zWinMax - zShelfMin);
    1736              :             }
    1737              : 
    1738              :             // Find height ratio based on shelf average height
    1739              :             Real64 heightRatio;
    1740            2 :             if (zWinMax > zWinMin) { // Window has a positive height
    1741            2 :                 heightRatio = (zShelfAvg - zWinMin) / (zWinMax - zWinMin);
    1742            2 :                 heightRatio = min(heightRatio, 1.0);
    1743            2 :                 heightRatio = max(heightRatio, 0.0);
    1744              :             } else { // Window does not have a positive height (not realistic) so set height ratio based on shelf location
    1745            0 :                 if (zShelfAvg > zWinMax) {
    1746            0 :                     heightRatio = 1.0;
    1747              :                 } else {
    1748            0 :                     heightRatio = 0.0;
    1749              :                 }
    1750              :             }
    1751              : 
    1752              :             // Take what is left over after the view to shelf is subtracted and then distribute/adjust that proportionally
    1753              :             // for the views to ground and sky based on their original weights.  Finally, account for the location of the shelf
    1754              :             // with respect to the shelf and reset the values of the actual variables used in the rest of the simulation.
    1755            2 :             leftoverViewFactor = 1.0 - viewFactorToShelf; // By previous logic above, leftover is greater than zero and less than one
    1756              :             Real64 vfGroundAdjustMax;
    1757              :             Real64 vfGroundAdjustMin;
    1758            2 :             if (viewFactorToGround > viewFactorToShelf) { // How much view to ground could be reduced potentially if shelf at bottom
    1759            1 :                 vfGroundAdjustMin = viewFactorToGround - viewFactorToShelf;
    1760              :             } else {
    1761            1 :                 vfGroundAdjustMin = 0.0;
    1762              :             }
    1763            2 :             if (viewFactorToGround > leftoverViewFactor) { // How much view to ground could be reduced potentially if shelf at top
    1764            0 :                 vfGroundAdjustMax = leftoverViewFactor;
    1765              :             } else {
    1766            2 :                 vfGroundAdjustMax = viewFactorToGround;
    1767              :             }
    1768            2 :             viewFactorToGround = vfGroundAdjustMin + heightRatio * (vfGroundAdjustMax - vfGroundAdjustMin);
    1769            2 :             viewFactorToSky = leftoverViewFactor - viewFactorToGround;
    1770              :         }
    1771            8 :         ShowWarningError(state,
    1772            8 :                          format("DaylightingDevice:Shelf = {}:  As a result of user input (see previous messages), at least one view factor but "
    1773              :                                 "possibly more than one was reduced.",
    1774            4 :                                 state.dataDaylightingDevicesData->Shelf(ShelfNum).Name));
    1775            8 :         ShowContinueError(state,
    1776              :                           "These include the view factors to the ground, the sky, and the exterior light shelf.  Note that views to other exterior "
    1777              :                           "surfaces could further complicated this.");
    1778           12 :         ShowContinueError(state, "Please consider manually calculating or adjusting view factors to avoid this problem.");
    1779              :     }
    1780              : 
    1781       249958 :     void FigureTDDZoneGains(EnergyPlusData &state)
    1782              :     {
    1783              : 
    1784              :         // SUBROUTINE INFORMATION:
    1785              :         //       AUTHOR         B. Griffith
    1786              :         //       DATE WRITTEN   Dec 2011
    1787              : 
    1788              :         // PURPOSE OF THIS SUBROUTINE:
    1789              :         // initialize zone gains at begin new environment
    1790              : 
    1791              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1792              : 
    1793       249958 :         if ((int)state.dataDaylightingDevicesData->TDDPipe.size() == 0) return;
    1794              : 
    1795            0 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataDaylightingDevices->MyEnvrnFlag) {
    1796            0 :             for (int Loop = 1; Loop <= (int)state.dataDaylightingDevicesData->TDDPipe.size(); ++Loop) {
    1797            0 :                 state.dataDaylightingDevicesData->TDDPipe(Loop).TZoneHeatGain = 0.0;
    1798              :             }
    1799            0 :             state.dataDaylightingDevices->MyEnvrnFlag = false;
    1800              :         }
    1801            0 :         if (!state.dataGlobal->BeginEnvrnFlag) state.dataDaylightingDevices->MyEnvrnFlag = true;
    1802              :     }
    1803              : 
    1804              : } // namespace Dayltg
    1805              : 
    1806              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1