LCOV - code coverage report
Current view: top level - EnergyPlus - Photovoltaics.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 20.4 % 852 174
Test Date: 2025-05-22 16:09:37 Functions: 12.9 % 31 4

            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 <cassert>
      50              : #include <cmath>
      51              : 
      52              : // ObjexxFCL Headers
      53              : #include <ObjexxFCL/Array.functions.hh>
      54              : #include <ObjexxFCL/Fmath.hh>
      55              : 
      56              : // EnergyPlus Headers
      57              : #include <EnergyPlus/Construction.hh>
      58              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59              : #include <EnergyPlus/DataEnvironment.hh>
      60              : #include <EnergyPlus/DataHVACGlobals.hh>
      61              : #include <EnergyPlus/DataHeatBalFanSys.hh>
      62              : #include <EnergyPlus/DataHeatBalSurface.hh>
      63              : #include <EnergyPlus/DataHeatBalance.hh>
      64              : #include <EnergyPlus/DataIPShortCuts.hh>
      65              : #include <EnergyPlus/DataPhotovoltaics.hh>
      66              : #include <EnergyPlus/DataPrecisionGlobals.hh>
      67              : #include <EnergyPlus/DataSurfaces.hh>
      68              : #include <EnergyPlus/General.hh>
      69              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      70              : #include <EnergyPlus/OutputProcessor.hh>
      71              : #include <EnergyPlus/PhotovoltaicThermalCollectors.hh>
      72              : #include <EnergyPlus/Photovoltaics.hh>
      73              : #include <EnergyPlus/ScheduleManager.hh>
      74              : #include <EnergyPlus/TranspiredCollector.hh>
      75              : #include <EnergyPlus/UtilityRoutines.hh>
      76              : 
      77              : namespace EnergyPlus {
      78              : 
      79              : namespace Photovoltaics {
      80              :     //       MODULE INFORMATION:
      81              :     //       AUTHOR         David Bradley
      82              :     //       DATE WRITTEN   January 2003
      83              :     //       MODIFIED       B. Griffith, dec2003 - Jan2004
      84              :     //                      added Sandia PV model loosely based on G. Barker's implementation for TRNSYS type
      85              :     //                      added Simple PV efficiency model for early design phases
      86              :     //       RE-ENGINEERED  added case statement to allow selecting and mixing between different models
      87              :     //                      moved derived types to DataPhotovoltaics
      88              :     //                      B. Griffith, Aug. 2008, refactored PV data structures and input objects to
      89              :     //                       so that there is one Generator:Photovoltaics object with 3 different model options.
      90              : 
      91              :     // PURPOSE OF THIS MODULE:
      92              :     // This module collects routines used to simulate the timestep by timestep performance of a
      93              :     // photovoltaic arrays.  The user can select between different models by choosing an a model and performance input object
      94              :     // Using the input object "PhotovoltaicPerformance:Simple" will lead to modeling the PV system using
      95              :     // crude model that just applies a power conversion efficiency factor, much simpler to specify
      96              :     // Using the input object "PhotovoltaicPerformance:EquivalentOne-Diode" will lead to modeling the PV system using
      97              :     // The PV model used as the basis for this module is Type180 from the HYDROGEMS library developed by
      98              :     // Oystein Ulleberg at the IFE Institute for Energy Technology in Norway and also work by Eckstein
      99              : 
     100              :     // Using the input object, "PhotovoltaicPerformance:SANDIA"  will lead to modeling a PV array
     101              :     //  using models developed by David King, Sandia National lab.  These models appear to provide
     102              :     //  improved prediction of PV performance at low radiance and incident angles.
     103              : 
     104              :     // METHODOLOGY EMPLOYED: This module contains routines to manage PV system models.
     105              :     //  There are two options for what model to use and this duality of modeling approaches is
     106              :     //  reflected in there being two groups of routines for each PV model, The original model is
     107              :     //  referred to as Equivalent one-diode model and has origins as a TRNSYS type180 from the Hydrogems library
     108              :     //  A newer model with more involved input has been developed by Sandia National Lab (SNL) by David King.
     109              :     //  The TRNSYS type180 model include the use of numerical routines to minimize a multivariate function
     110              : 
     111              :     // Using/Aliasing
     112              :     using namespace DataPhotovoltaics;
     113              : 
     114              :     constexpr std::string_view cPVGeneratorObjectName = "Generator:Photovoltaic";
     115              : 
     116              :     constexpr std::array<std::string_view, (int)PVModel::Num> pvModelNames = {
     117              :         "PhotovoltaicPerformance:Simple", "PhotovoltaicPerformance:EquivalentOne-Diode", "PhotovoltaicPerformance:Sandia"};
     118              :     constexpr std::array<std::string_view, (int)PVModel::Num> pvModelNamesUC = {
     119              :         "PHOTOVOLTAICPERFORMANCE:SIMPLE", "PHOTOVOLTAICPERFORMANCE:EQUIVALENTONE-DIODE", "PHOTOVOLTAICPERFORMANCE:SANDIA"};
     120              : 
     121              :     constexpr std::array<std::string_view, (int)CellIntegration::Num> cellIntegrationNames = {"Decoupled",
     122              :                                                                                               "DecoupledUllebergDynamic",
     123              :                                                                                               "IntegratedSurfaceOutsideFace",
     124              :                                                                                               "IntegratedTranspiredCollector",
     125              :                                                                                               "IntegratedExteriorVentedCavity",
     126              :                                                                                               "PhotovoltaicThermalSolarCollector"};
     127              :     constexpr std::array<std::string_view, (int)CellIntegration::Num> cellIntegrationNamesUC = {"DECOUPLED",
     128              :                                                                                                 "DECOUPLEDULLEBERGDYNAMIC",
     129              :                                                                                                 "INTEGRATEDSURFACEOUTSIDEFACE",
     130              :                                                                                                 "INTEGRATEDTRANSPIREDCOLLECTOR",
     131              :                                                                                                 "INTEGRATEDEXTERIORVENTEDCAVITY",
     132              :                                                                                                 "PHOTOVOLTAICTHERMALSOLARCOLLECTOR"};
     133              : 
     134              :     constexpr std::array<std::string_view, (int)Efficiency::Num> efficiencyNames = {"Fixed", "Scheduled"};
     135              :     constexpr std::array<std::string_view, (int)Efficiency::Num> efficiencyNamesUC = {"FIXED", "SCHEDULED"};
     136              : 
     137              :     constexpr std::array<std::string_view, (int)SiPVCells::Num> siPVCellsNames = {"CrystallineSilicon", "AmorphousSilicon"};
     138              :     constexpr std::array<std::string_view, (int)SiPVCells::Num> siPVCellsNamesUC = {"CRYSTALLINESILICON", "AMORPHOUSSILICON"};
     139              : 
     140            0 :     void SimPVGenerator(EnergyPlusData &state,
     141              :                         [[maybe_unused]] GeneratorType const GeneratorType, // type of Generator !unused1208
     142              :                         std::string const &GeneratorName,                   // user specified name of Generator
     143              :                         int &GeneratorIndex,
     144              :                         bool const RunFlag,                  // is PV ON or OFF as determined by schedules in ElecLoadCenter
     145              :                         [[maybe_unused]] Real64 const PVLoad // electrical load on the PV (not really used... PV models assume "full on" !unused1208
     146              :     )
     147              :     {
     148              : 
     149              :         // SUBROUTINE INFORMATION:
     150              :         //       AUTHOR         David Bradley
     151              :         //       DATE WRITTEN   April 2003
     152              :         //       MODIFIED       B. Griffith Jan 2004
     153              :         //                      B. Griffith Aug. 2008 Rework for new structure
     154              :         //       RE-ENGINEERED  na
     155              : 
     156              :         // PURPOSE OF THIS SUBROUTINE:
     157              :         // This subroutine is in charge of all the rest of the subroutines contained
     158              :         // in this module. provides common entry point for all the models
     159              : 
     160              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     161              :         int PVnum; // index of unit in PV array for Equivalent one-diode model
     162              : 
     163              :         // Get PV data from input file
     164            0 :         if (state.dataPhotovoltaicState->GetInputFlag) {
     165            0 :             GetPVInput(state); // for all three types of models
     166            0 :             state.dataPhotovoltaicState->GetInputFlag = false;
     167              :         }
     168              : 
     169            0 :         if (GeneratorIndex == 0) {
     170            0 :             PVnum = Util::FindItemInList(GeneratorName, state.dataPhotovoltaic->PVarray);
     171            0 :             if (PVnum == 0) {
     172            0 :                 ShowFatalError(state, format("SimPhotovoltaicGenerator: Specified PV not one of valid Photovoltaic Generators {}", GeneratorName));
     173              :             }
     174            0 :             GeneratorIndex = PVnum;
     175              :         } else {
     176            0 :             PVnum = GeneratorIndex;
     177            0 :             if (PVnum > state.dataPhotovoltaic->NumPVs || PVnum < 1) {
     178            0 :                 ShowFatalError(state,
     179            0 :                                format("SimPhotovoltaicGenerator: Invalid GeneratorIndex passed={}, Number of PVs={}, Generator name={}",
     180              :                                       PVnum,
     181            0 :                                       state.dataPhotovoltaic->NumPVs,
     182              :                                       GeneratorName));
     183              :             }
     184            0 :             if (state.dataPhotovoltaicState->CheckEquipName(PVnum)) {
     185            0 :                 if (GeneratorName != state.dataPhotovoltaic->PVarray(PVnum).Name) {
     186            0 :                     ShowFatalError(
     187              :                         state,
     188            0 :                         format("SimPhotovoltaicGenerator: Invalid GeneratorIndex passed={}, Generator name={}, stored PV Name for that index={}",
     189              :                                PVnum,
     190              :                                GeneratorName,
     191            0 :                                state.dataPhotovoltaic->PVarray(PVnum).Name));
     192              :                 }
     193            0 :                 state.dataPhotovoltaicState->CheckEquipName(PVnum) = false;
     194              :             }
     195              :         }
     196              : 
     197            0 :         switch (state.dataPhotovoltaic->PVarray(PVnum).PVModelType) {
     198            0 :         case PVModel::Simple: {
     199            0 :             CalcSimplePV(state, PVnum);
     200            0 :         } break;
     201            0 :         case PVModel::TRNSYS: {
     202              :             // 'PhotovoltaicPerformance:EquivalentOne-Diode' (aka. 5-parameter TRNSYS type 180 model)
     203            0 :             InitTRNSYSPV(state, PVnum);
     204              : 
     205            0 :             CalcTRNSYSPV(state, PVnum, RunFlag);
     206            0 :         } break;
     207            0 :         case PVModel::Sandia: {
     208              :             // 'PhotovoltaicPerformance:Sandia' (aka. King model, Sandia Nat. Labs.)
     209            0 :             CalcSandiaPV(state, PVnum, RunFlag);
     210            0 :         } break;
     211            0 :         default: {
     212            0 :             ShowFatalError(state, format("Specified generator model type not found for PV generator = {}", GeneratorName));
     213            0 :         } break;
     214              :         }
     215              : 
     216            0 :         ReportPV(state, PVnum);
     217            0 :     }
     218              : 
     219            0 :     void GetPVGeneratorResults(EnergyPlusData &state,
     220              :                                [[maybe_unused]] GeneratorType const GeneratorType, // type of Generator !unused1208
     221              :                                int const GeneratorIndex,
     222              :                                Real64 &GeneratorPower,  // electrical power
     223              :                                Real64 &GeneratorEnergy, // electrical energy
     224              :                                Real64 &ThermalPower,
     225              :                                Real64 &ThermalEnergy)
     226              :     {
     227              : 
     228              :         // SUBROUTINE INFORMATION:
     229              :         //       AUTHOR         B. Griffith
     230              :         //       DATE WRITTEN   Aug. 2008
     231              :         //       MODIFIED       na
     232              :         //       RE-ENGINEERED  na
     233              : 
     234              :         // PURPOSE OF THIS SUBROUTINE:
     235              :         // provide a "get" method to collect results for individual electric load centers.
     236              : 
     237              :         // Using/Aliasing
     238              :         using PhotovoltaicThermalCollectors::GetPVTThermalPowerProduction;
     239              : 
     240            0 :         GeneratorPower = state.dataPhotovoltaic->PVarray(GeneratorIndex).Report.DCPower;
     241            0 :         GeneratorEnergy = state.dataPhotovoltaic->PVarray(GeneratorIndex).Report.DCEnergy;
     242            0 :         auto const &thisPVarray = state.dataPhotovoltaic->PVarray(GeneratorIndex);
     243              :         // PVT may add thermal
     244            0 :         if (thisPVarray.CellIntegrationMode == CellIntegration::PVTSolarCollector) {
     245              :             // get result for thermal power generation
     246            0 :             GetPVTThermalPowerProduction(state, GeneratorIndex, ThermalPower, ThermalEnergy);
     247              :         } else {
     248            0 :             ThermalPower = 0.0;
     249            0 :             ThermalEnergy = 0.0;
     250              :         }
     251            0 :     }
     252              : 
     253              :     // *************
     254              : 
     255            2 :     void GetPVInput(EnergyPlusData &state)
     256              :     {
     257              : 
     258              :         // SUBROUTINE INFORMATION:
     259              :         //       AUTHOR         David Bradley
     260              :         //       DATE WRITTEN   January 2003
     261              :         //       MODIFIED       B.Griffith Dec. 2003 - Jan 2004 added input for Simple and Sandia PV model
     262              :         //                      B. Griffith Feb. 2008 - revised input for TRNSYS pv model for BIPV and inverter
     263              :         //                      B. Griffith Aug. 2008 - revised input for new organization and naming convention
     264              :         //       RE-ENGINEERED  na
     265              : 
     266              :         // PURPOSE OF THIS SUBROUTINE:
     267              :         // This subroutine gets the input for the Photovoltaic units saving it in
     268              :         // the data structures defined in DataPhotovoltaics.cc.
     269              : 
     270              :         // METHODOLOGY EMPLOYED:
     271              :         // subroutine structure taken from Beta2 BaseboardRadiator.cc
     272              : 
     273              :         // Using/Aliasing
     274              :         using namespace DataHeatBalance;
     275              : 
     276              :         using PhotovoltaicThermalCollectors::GetPVTmodelIndex;
     277              :         using TranspiredCollector::GetTranspiredCollectorIndex;
     278              : 
     279              :         static constexpr std::string_view routineName = "GetPVInput";
     280              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     281              :         int PVnum;     // working variable for do loop through pv arrays
     282              :         int SurfNum;   // working variable for surface id in Heat Balance domain
     283              :         int ModNum;    // working variable for do loop through Sandia model parameter input
     284              :         int NumAlphas; // Number of PV Array parameter alpha names being passed
     285              :         int NumNums;   // Number of PV Array numeric parameters are being passed
     286              :         int IOStat;
     287            2 :         bool ErrorsFound(false); // if errors detected in input
     288              :         int ThisParamObj;
     289              :         int dupPtr;
     290              : 
     291              :         // Object Data
     292            2 :         Array1D<SimplePVParamsStruct> tmpSimpleModuleParams;       // temporary, for processing input data
     293            2 :         Array1D<TRNSYSPVModuleParamsStruct> tmpTRNSYSModuleParams; // temporary, for processing input data
     294            2 :         Array1D<SNLModuleParamsStuct> tmpSNLModuleParams;          // temporary, for processing input data
     295              : 
     296            2 :         auto &s_ipsc = state.dataIPShortCut;
     297              : 
     298              :         // count how many photovoltaic arrays of different types are in the .idf
     299            2 :         state.dataPhotovoltaic->NumPVs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cPVGeneratorObjectName);
     300            4 :         state.dataPhotovoltaic->NumSimplePVModuleTypes =
     301            2 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pvModelNames[(int)PVModel::Simple]);
     302            4 :         state.dataPhotovoltaic->Num1DiodePVModuleTypes =
     303            2 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pvModelNames[(int)PVModel::TRNSYS]);
     304            4 :         state.dataPhotovoltaic->NumSNLPVModuleTypes =
     305            2 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, pvModelNames[(int)PVModel::Sandia]);
     306              : 
     307            2 :         if (state.dataPhotovoltaic->NumPVs <= 0) {
     308            0 :             ShowSevereError(state, format("Did not find any {}", cPVGeneratorObjectName));
     309            0 :             return;
     310              :         }
     311              : 
     312            2 :         if (!allocated(state.dataPhotovoltaic->PVarray)) state.dataPhotovoltaic->PVarray.allocate(state.dataPhotovoltaic->NumPVs);
     313            2 :         state.dataPhotovoltaicState->CheckEquipName.dimension(state.dataPhotovoltaic->NumPVs, true);
     314              : 
     315            2 :         s_ipsc->cCurrentModuleObject = cPVGeneratorObjectName;
     316            4 :         for (PVnum = 1; PVnum <= state.dataPhotovoltaic->NumPVs; ++PVnum) {
     317            6 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     318            2 :                                                                      s_ipsc->cCurrentModuleObject,
     319              :                                                                      PVnum,
     320            2 :                                                                      s_ipsc->cAlphaArgs,
     321              :                                                                      NumAlphas,
     322            2 :                                                                      s_ipsc->rNumericArgs,
     323              :                                                                      NumNums,
     324              :                                                                      IOStat,
     325              :                                                                      _,
     326            2 :                                                                      s_ipsc->lAlphaFieldBlanks,
     327            2 :                                                                      s_ipsc->cAlphaFieldNames,
     328            2 :                                                                      s_ipsc->cNumericFieldNames);
     329              : 
     330            2 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
     331              : 
     332            2 :             Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound);
     333            2 :             state.dataPhotovoltaic->PVarray(PVnum).Name = s_ipsc->cAlphaArgs(1);
     334              : 
     335            2 :             state.dataPhotovoltaic->PVarray(PVnum).SurfaceName = s_ipsc->cAlphaArgs(2);
     336            2 :             state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr = Util::FindItemInList(s_ipsc->cAlphaArgs(2), state.dataSurface->Surface);
     337              :             // required-surface
     338            2 :             if (s_ipsc->lAlphaFieldBlanks(2)) {
     339            0 :                 ShowSevereError(state, format("Invalid {} = {}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
     340            0 :                 ShowContinueError(state, format("Entered in {} = {}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     341            0 :                 ShowContinueError(state, "Surface name cannot be blank");
     342            0 :                 ErrorsFound = true;
     343              :             }
     344            2 :             if (state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr == 0) {
     345            0 :                 ShowSevereError(state, format("Invalid {} = {}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
     346            0 :                 ShowContinueError(state, format("Entered in {} = {}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     347            0 :                 ErrorsFound = true;
     348              :             } else {
     349              :                 // Found one -- make sure has right parameters for PV
     350            2 :                 SurfNum = state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr;
     351            2 :                 state.dataSurface->SurfIsPV(SurfNum) = true;
     352              : 
     353            2 :                 if (!state.dataSurface->Surface(SurfNum).ExtSolar) {
     354            0 :                     ShowWarningError(state, format("Invalid {} = {}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
     355            0 :                     ShowContinueError(state, format("Entered in {} = {}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     356            0 :                     ShowContinueError(state, "Surface is not exposed to solar, check surface boundary condition");
     357              :                 }
     358            2 :                 state.dataPhotovoltaic->PVarray(PVnum).Zone = GetPVZone(state, state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr);
     359              : 
     360              :                 // check surface orientation, warn if upside down
     361            2 :                 if ((state.dataSurface->Surface(SurfNum).Tilt < -95.0) || (state.dataSurface->Surface(SurfNum).Tilt > 95.0)) {
     362            0 :                     ShowWarningError(state, format("Suspected input problem with {} = {}", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
     363            0 :                     ShowContinueError(state, format("Entered in {} = {}", s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
     364            0 :                     ShowContinueError(state, "Surface used for solar collector faces down");
     365            0 :                     ShowContinueError(
     366            0 :                         state, format("Surface tilt angle (degrees from ground outward normal) = {:.2R}", state.dataSurface->Surface(SurfNum).Tilt));
     367              :                 }
     368              :             }
     369              : 
     370            2 :             if (s_ipsc->lAlphaFieldBlanks(3)) {
     371            0 :                 ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
     372            0 :                 ErrorsFound = true;
     373            2 :             } else if ((state.dataPhotovoltaic->PVarray(PVnum).PVModelType =
     374            4 :                             static_cast<PVModel>(getEnumValue(pvModelNamesUC, s_ipsc->cAlphaArgs(3)))) == PVModel::Invalid) {
     375            0 :                 ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
     376            0 :                 ErrorsFound = true;
     377              :             }
     378              : 
     379            2 :             state.dataPhotovoltaic->PVarray(PVnum).PerfObjName = s_ipsc->cAlphaArgs(4); // check later once perf objects are loaded
     380              : 
     381            2 :             if (s_ipsc->lAlphaFieldBlanks(5)) {
     382            0 :                 ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5));
     383            0 :                 ErrorsFound = true;
     384            2 :             } else if ((state.dataPhotovoltaic->PVarray(PVnum).CellIntegrationMode =
     385            4 :                             static_cast<CellIntegration>(getEnumValue(cellIntegrationNamesUC, s_ipsc->cAlphaArgs(5)))) == CellIntegration::Invalid) {
     386            0 :                 ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5));
     387            0 :                 ErrorsFound = true;
     388              :             }
     389              : 
     390            2 :             state.dataPhotovoltaic->PVarray(PVnum).NumSeriesNParall = s_ipsc->rNumericArgs(1);
     391            2 :             state.dataPhotovoltaic->PVarray(PVnum).NumModNSeries = s_ipsc->rNumericArgs(2);
     392              : 
     393              :         } // main PV array objects
     394              : 
     395              :         // search for duplicate PV arrays on integrated heat transfer surfaces, accumulating source terms across arrays is not supported
     396            4 :         for (PVnum = 1; PVnum <= state.dataPhotovoltaic->NumPVs; ++PVnum) {
     397            2 :             switch (state.dataPhotovoltaic->PVarray(PVnum).CellIntegrationMode) {
     398            0 :             case CellIntegration::SurfaceOutsideFace:
     399              :             case CellIntegration::TranspiredCollector:
     400              :             case CellIntegration::ExteriorVentedCavity: {
     401            0 :                 dupPtr = Util::FindItemInList(state.dataPhotovoltaic->PVarray(PVnum).SurfaceName,
     402            0 :                                               state.dataPhotovoltaic->PVarray({PVnum + 1, state.dataPhotovoltaic->NumPVs}),
     403              :                                               &PVArrayStruct::SurfaceName);
     404            0 :                 if (dupPtr != 0) dupPtr += PVnum; // to correct for shortened array in find item
     405            0 :                 if (dupPtr != 0) {
     406            0 :                     auto &thisPVarray = state.dataPhotovoltaic->PVarray(dupPtr);
     407            0 :                     if (thisPVarray.CellIntegrationMode == CellIntegration::SurfaceOutsideFace) {
     408            0 :                         ShowSevereError(state, format("{}: problem detected with multiple PV arrays.", s_ipsc->cCurrentModuleObject));
     409            0 :                         ShowContinueError(state, "When using IntegratedSurfaceOutsideFace heat transfer mode, only one PV array can be coupled");
     410            0 :                         ShowContinueError(state,
     411            0 :                                           format("Both {} and {} are using surface {}",
     412            0 :                                                  state.dataPhotovoltaic->PVarray(PVnum).Name,
     413            0 :                                                  thisPVarray.Name,
     414            0 :                                                  state.dataPhotovoltaic->PVarray(PVnum).SurfaceName));
     415            0 :                         ErrorsFound = true;
     416            0 :                     } else if (thisPVarray.CellIntegrationMode == CellIntegration::TranspiredCollector) {
     417            0 :                         ShowSevereError(state, format("{}: problem detected with multiple PV arrays.", s_ipsc->cCurrentModuleObject));
     418            0 :                         ShowContinueError(state, "When using IntegratedTranspiredCollector heat transfer mode, only one PV array can be coupled");
     419            0 :                         ShowContinueError(state,
     420            0 :                                           format("Both {} and {} are using UTSC surface = {}",
     421            0 :                                                  state.dataPhotovoltaic->PVarray(PVnum).Name,
     422            0 :                                                  thisPVarray.Name,
     423            0 :                                                  state.dataPhotovoltaic->PVarray(PVnum).SurfaceName));
     424            0 :                         ErrorsFound = true;
     425            0 :                     } else if (thisPVarray.CellIntegrationMode == CellIntegration::ExteriorVentedCavity) {
     426            0 :                         ShowSevereError(state, format("{}: problem detected with multiple PV arrays.", s_ipsc->cCurrentModuleObject));
     427            0 :                         ShowContinueError(state, "When using IntegratedExteriorVentedCavity heat transfer mode, only one PV array can be coupled");
     428            0 :                         ShowContinueError(state,
     429            0 :                                           format("Both {} and {} are using exterior vented surface = {}",
     430            0 :                                                  state.dataPhotovoltaic->PVarray(PVnum).Name,
     431            0 :                                                  thisPVarray.Name,
     432            0 :                                                  state.dataPhotovoltaic->PVarray(PVnum).SurfaceName));
     433            0 :                         ErrorsFound = true;
     434            0 :                     } else if (thisPVarray.CellIntegrationMode == CellIntegration::PVTSolarCollector) {
     435            0 :                         ShowSevereError(
     436              :                             state,
     437            0 :                             format("Problem detected with multiple PV arrays for={}. When using PhotovoltaicThermalSolarCollector heat transfer "
     438              :                                    "mode, only one PV array can be coupled. Both this PV array={} and this PV array={} are using PVT surface={}",
     439            0 :                                    s_ipsc->cCurrentModuleObject,
     440            0 :                                    state.dataPhotovoltaic->PVarray(PVnum).Name,
     441            0 :                                    thisPVarray.Name,
     442            0 :                                    state.dataPhotovoltaic->PVarray(PVnum).SurfaceName));
     443            0 :                         ErrorsFound = true;
     444              :                     }
     445              :                 }
     446            0 :             } break;
     447            2 :             default:
     448            2 :                 break;
     449              :             }
     450              :         }
     451              : 
     452            2 :         if (state.dataPhotovoltaic->NumSimplePVModuleTypes > 0) {
     453            1 :             tmpSimpleModuleParams.allocate(state.dataPhotovoltaic->NumSimplePVModuleTypes);
     454            1 :             s_ipsc->cCurrentModuleObject = pvModelNames[(int)PVModel::Simple];
     455            2 :             for (ModNum = 1; ModNum <= state.dataPhotovoltaic->NumSimplePVModuleTypes; ++ModNum) {
     456            3 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     457            1 :                                                                          s_ipsc->cCurrentModuleObject,
     458              :                                                                          ModNum,
     459            1 :                                                                          s_ipsc->cAlphaArgs,
     460              :                                                                          NumAlphas,
     461            1 :                                                                          s_ipsc->rNumericArgs,
     462              :                                                                          NumNums,
     463              :                                                                          IOStat,
     464              :                                                                          _,
     465            1 :                                                                          s_ipsc->lAlphaFieldBlanks,
     466            1 :                                                                          s_ipsc->cAlphaFieldNames,
     467            1 :                                                                          s_ipsc->cNumericFieldNames);
     468              : 
     469            1 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
     470              : 
     471            1 :                 if (Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound)) {
     472            0 :                     continue;
     473              :                 }
     474            1 :                 tmpSimpleModuleParams(ModNum).Name = s_ipsc->cAlphaArgs(1);
     475            1 :                 tmpSimpleModuleParams(ModNum).ActiveFraction = s_ipsc->rNumericArgs(1);
     476              : 
     477            1 :                 if (s_ipsc->lAlphaFieldBlanks(2)) {
     478            0 :                     ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
     479            0 :                     ErrorsFound = true;
     480            2 :                 } else if ((tmpSimpleModuleParams(ModNum).EfficencyInputMode =
     481            1 :                                 static_cast<Efficiency>(getEnumValue(efficiencyNamesUC, s_ipsc->cAlphaArgs(2)))) == Efficiency::Invalid) {
     482            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
     483            0 :                     ErrorsFound = true;
     484              :                 }
     485            1 :                 tmpSimpleModuleParams(ModNum).PVEfficiency = s_ipsc->rNumericArgs(2);
     486              : 
     487            1 :                 if (tmpSimpleModuleParams(ModNum).EfficencyInputMode == Efficiency::Scheduled) {
     488            0 :                     if (s_ipsc->lAlphaFieldBlanks(3)) {
     489            0 :                         ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
     490            0 :                         ErrorsFound = true;
     491            0 :                     } else if ((tmpSimpleModuleParams(ModNum).effSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(3))) == nullptr) {
     492            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
     493            0 :                         ErrorsFound = true;
     494              :                     }
     495              :                 }
     496              :             }
     497              :         }
     498              : 
     499            2 :         if (state.dataPhotovoltaic->Num1DiodePVModuleTypes > 0) {
     500            1 :             tmpTRNSYSModuleParams.allocate(state.dataPhotovoltaic->Num1DiodePVModuleTypes);
     501            1 :             s_ipsc->cCurrentModuleObject = pvModelNames[(int)PVModel::TRNSYS];
     502            2 :             for (ModNum = 1; ModNum <= state.dataPhotovoltaic->Num1DiodePVModuleTypes; ++ModNum) {
     503            3 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     504            1 :                                                                          s_ipsc->cCurrentModuleObject,
     505              :                                                                          ModNum,
     506            1 :                                                                          s_ipsc->cAlphaArgs,
     507              :                                                                          NumAlphas,
     508            1 :                                                                          s_ipsc->rNumericArgs,
     509              :                                                                          NumNums,
     510              :                                                                          IOStat,
     511              :                                                                          _,
     512            1 :                                                                          s_ipsc->lAlphaFieldBlanks,
     513            1 :                                                                          s_ipsc->cAlphaFieldNames,
     514            1 :                                                                          s_ipsc->cNumericFieldNames);
     515              : 
     516            1 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
     517            1 :                 if (Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound)) {
     518            0 :                     continue;
     519              :                 }
     520            1 :                 tmpTRNSYSModuleParams(ModNum).Name = s_ipsc->cAlphaArgs(1);
     521              : 
     522            1 :                 if (s_ipsc->lAlphaFieldBlanks(2)) {
     523            0 :                     ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
     524            0 :                     ErrorsFound = true;
     525            1 :                 } else if ((tmpTRNSYSModuleParams(ModNum).CellType = static_cast<SiPVCells>(getEnumValue(siPVCellsNamesUC, s_ipsc->cAlphaArgs(2)))) ==
     526              :                            SiPVCells::Invalid) {
     527            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2));
     528            0 :                     ErrorsFound = true;
     529              :                 }
     530              : 
     531            1 :                 tmpTRNSYSModuleParams(ModNum).CellsInSeries = int(s_ipsc->rNumericArgs(1));
     532            1 :                 tmpTRNSYSModuleParams(ModNum).Area = s_ipsc->rNumericArgs(2);
     533            1 :                 tmpTRNSYSModuleParams(ModNum).TauAlpha = s_ipsc->rNumericArgs(3);
     534            1 :                 tmpTRNSYSModuleParams(ModNum).SemiConductorBandgap = s_ipsc->rNumericArgs(4);
     535            1 :                 tmpTRNSYSModuleParams(ModNum).ShuntResistance = s_ipsc->rNumericArgs(5);
     536            1 :                 tmpTRNSYSModuleParams(ModNum).RefIsc = s_ipsc->rNumericArgs(6);
     537            1 :                 tmpTRNSYSModuleParams(ModNum).RefVoc = s_ipsc->rNumericArgs(7);
     538            1 :                 tmpTRNSYSModuleParams(ModNum).RefTemperature = s_ipsc->rNumericArgs(8) + Constant::Kelvin;
     539            1 :                 tmpTRNSYSModuleParams(ModNum).RefInsolation = s_ipsc->rNumericArgs(9);
     540            1 :                 tmpTRNSYSModuleParams(ModNum).Imp = s_ipsc->rNumericArgs(10);
     541            1 :                 tmpTRNSYSModuleParams(ModNum).Vmp = s_ipsc->rNumericArgs(11);
     542            1 :                 tmpTRNSYSModuleParams(ModNum).TempCoefIsc = s_ipsc->rNumericArgs(12);
     543            1 :                 tmpTRNSYSModuleParams(ModNum).TempCoefVoc = s_ipsc->rNumericArgs(13);
     544            1 :                 tmpTRNSYSModuleParams(ModNum).NOCTAmbTemp = s_ipsc->rNumericArgs(14) + Constant::Kelvin;
     545            1 :                 tmpTRNSYSModuleParams(ModNum).NOCTCellTemp = s_ipsc->rNumericArgs(15) + Constant::Kelvin;
     546            1 :                 tmpTRNSYSModuleParams(ModNum).NOCTInsolation = s_ipsc->rNumericArgs(16);
     547            1 :                 tmpTRNSYSModuleParams(ModNum).HeatLossCoef = s_ipsc->rNumericArgs(17);
     548            1 :                 tmpTRNSYSModuleParams(ModNum).HeatCapacity = s_ipsc->rNumericArgs(18);
     549              :             }
     550              :         }
     551              : 
     552            2 :         if (state.dataPhotovoltaic->NumSNLPVModuleTypes > 0) {
     553            0 :             tmpSNLModuleParams.allocate(state.dataPhotovoltaic->NumSNLPVModuleTypes);
     554            0 :             s_ipsc->cCurrentModuleObject = pvModelNames[(int)PVModel::Sandia];
     555            0 :             for (ModNum = 1; ModNum <= state.dataPhotovoltaic->NumSNLPVModuleTypes; ++ModNum) {
     556              : 
     557            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     558            0 :                                                                          s_ipsc->cCurrentModuleObject,
     559              :                                                                          ModNum,
     560            0 :                                                                          s_ipsc->cAlphaArgs,
     561              :                                                                          NumAlphas,
     562            0 :                                                                          s_ipsc->rNumericArgs,
     563              :                                                                          NumNums,
     564              :                                                                          IOStat,
     565              :                                                                          _,
     566            0 :                                                                          s_ipsc->lAlphaFieldBlanks,
     567            0 :                                                                          s_ipsc->cAlphaFieldNames,
     568            0 :                                                                          s_ipsc->cNumericFieldNames);
     569            0 :                 if (Util::IsNameEmpty(state, s_ipsc->cAlphaArgs(1), s_ipsc->cCurrentModuleObject, ErrorsFound)) {
     570            0 :                     continue;
     571              :                 }
     572              : 
     573            0 :                 tmpSNLModuleParams(ModNum).name = s_ipsc->cAlphaArgs(1);
     574            0 :                 tmpSNLModuleParams(ModNum).Acoll = s_ipsc->rNumericArgs(1);
     575            0 :                 tmpSNLModuleParams(ModNum).NcellSer = s_ipsc->rNumericArgs(2);
     576            0 :                 tmpSNLModuleParams(ModNum).NparSerCells = s_ipsc->rNumericArgs(3);
     577            0 :                 tmpSNLModuleParams(ModNum).Isc0 = s_ipsc->rNumericArgs(4);
     578            0 :                 tmpSNLModuleParams(ModNum).Voc0 = s_ipsc->rNumericArgs(5);
     579            0 :                 tmpSNLModuleParams(ModNum).Imp0 = s_ipsc->rNumericArgs(6);
     580            0 :                 tmpSNLModuleParams(ModNum).Vmp0 = s_ipsc->rNumericArgs(7);
     581            0 :                 tmpSNLModuleParams(ModNum).aIsc = s_ipsc->rNumericArgs(8);
     582            0 :                 tmpSNLModuleParams(ModNum).aImp = s_ipsc->rNumericArgs(9);
     583            0 :                 tmpSNLModuleParams(ModNum).c_0 = s_ipsc->rNumericArgs(10);
     584            0 :                 tmpSNLModuleParams(ModNum).c_1 = s_ipsc->rNumericArgs(11);
     585            0 :                 tmpSNLModuleParams(ModNum).BVoc0 = s_ipsc->rNumericArgs(12);
     586            0 :                 tmpSNLModuleParams(ModNum).mBVoc = s_ipsc->rNumericArgs(13);
     587            0 :                 tmpSNLModuleParams(ModNum).BVmp0 = s_ipsc->rNumericArgs(14);
     588            0 :                 tmpSNLModuleParams(ModNum).mBVmp = s_ipsc->rNumericArgs(15);
     589            0 :                 tmpSNLModuleParams(ModNum).DiodeFactor = s_ipsc->rNumericArgs(16);
     590            0 :                 tmpSNLModuleParams(ModNum).c_2 = s_ipsc->rNumericArgs(17);
     591            0 :                 tmpSNLModuleParams(ModNum).c_3 = s_ipsc->rNumericArgs(18);
     592            0 :                 tmpSNLModuleParams(ModNum).a_0 = s_ipsc->rNumericArgs(19);
     593            0 :                 tmpSNLModuleParams(ModNum).a_1 = s_ipsc->rNumericArgs(20);
     594            0 :                 tmpSNLModuleParams(ModNum).a_2 = s_ipsc->rNumericArgs(21);
     595            0 :                 tmpSNLModuleParams(ModNum).a_3 = s_ipsc->rNumericArgs(22);
     596            0 :                 tmpSNLModuleParams(ModNum).a_4 = s_ipsc->rNumericArgs(23);
     597            0 :                 tmpSNLModuleParams(ModNum).b_0 = s_ipsc->rNumericArgs(24);
     598            0 :                 tmpSNLModuleParams(ModNum).b_1 = s_ipsc->rNumericArgs(25);
     599            0 :                 tmpSNLModuleParams(ModNum).b_2 = s_ipsc->rNumericArgs(26);
     600            0 :                 tmpSNLModuleParams(ModNum).b_3 = s_ipsc->rNumericArgs(27);
     601            0 :                 tmpSNLModuleParams(ModNum).b_4 = s_ipsc->rNumericArgs(28);
     602            0 :                 tmpSNLModuleParams(ModNum).b_5 = s_ipsc->rNumericArgs(29);
     603            0 :                 tmpSNLModuleParams(ModNum).DT0 = s_ipsc->rNumericArgs(30);
     604            0 :                 tmpSNLModuleParams(ModNum).fd = s_ipsc->rNumericArgs(31);
     605            0 :                 tmpSNLModuleParams(ModNum).a = s_ipsc->rNumericArgs(32);
     606            0 :                 tmpSNLModuleParams(ModNum).b = s_ipsc->rNumericArgs(33);
     607            0 :                 tmpSNLModuleParams(ModNum).c_4 = s_ipsc->rNumericArgs(34);
     608            0 :                 tmpSNLModuleParams(ModNum).c_5 = s_ipsc->rNumericArgs(35);
     609            0 :                 tmpSNLModuleParams(ModNum).Ix0 = s_ipsc->rNumericArgs(36);
     610            0 :                 tmpSNLModuleParams(ModNum).Ixx0 = s_ipsc->rNumericArgs(37);
     611            0 :                 tmpSNLModuleParams(ModNum).c_6 = s_ipsc->rNumericArgs(38);
     612            0 :                 tmpSNLModuleParams(ModNum).c_7 = s_ipsc->rNumericArgs(39);
     613              :             }
     614              :         }
     615              : 
     616              :         // now fill collector performance data into main PV structure
     617            4 :         for (PVnum = 1; PVnum <= state.dataPhotovoltaic->NumPVs; ++PVnum) {
     618              : 
     619            2 :             switch (state.dataPhotovoltaic->PVarray(PVnum).PVModelType) {
     620            1 :             case PVModel::Simple: {
     621            1 :                 ThisParamObj = Util::FindItemInList(state.dataPhotovoltaic->PVarray(PVnum).PerfObjName, tmpSimpleModuleParams);
     622            1 :                 if (ThisParamObj > 0) {
     623            1 :                     state.dataPhotovoltaic->PVarray(PVnum).SimplePVModule = tmpSimpleModuleParams(ThisParamObj); // entire structure assignment
     624              : 
     625              :                     // do one-time setups on input data
     626            1 :                     state.dataPhotovoltaic->PVarray(PVnum).SimplePVModule.AreaCol =
     627            1 :                         state.dataSurface->Surface(state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr).Area *
     628            1 :                         state.dataPhotovoltaic->PVarray(PVnum).SimplePVModule.ActiveFraction;
     629              :                 } else {
     630            0 :                     ShowSevereError(state, format("Invalid PV performance object name of {}", state.dataPhotovoltaic->PVarray(PVnum).PerfObjName));
     631            0 :                     ShowContinueError(state, format("Entered in {} = {}", cPVGeneratorObjectName, state.dataPhotovoltaic->PVarray(PVnum).Name));
     632            0 :                     ErrorsFound = true;
     633              :                 }
     634            1 :             } break;
     635            1 :             case PVModel::TRNSYS: {
     636            1 :                 ThisParamObj = Util::FindItemInList(state.dataPhotovoltaic->PVarray(PVnum).PerfObjName, tmpTRNSYSModuleParams);
     637            1 :                 if (ThisParamObj > 0) {
     638            1 :                     state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule = tmpTRNSYSModuleParams(ThisParamObj); // entire structure assignment
     639              :                 } else {
     640            0 :                     ShowSevereError(state, format("Invalid PV performance object name of {}", state.dataPhotovoltaic->PVarray(PVnum).PerfObjName));
     641            0 :                     ShowContinueError(state, format("Entered in {} = {}", cPVGeneratorObjectName, state.dataPhotovoltaic->PVarray(PVnum).Name));
     642            0 :                     ErrorsFound = true;
     643              :                 }
     644            1 :             } break;
     645            0 :             case PVModel::Sandia: {
     646              :                 ThisParamObj =
     647            0 :                     Util::FindItemInList(state.dataPhotovoltaic->PVarray(PVnum).PerfObjName, tmpSNLModuleParams, &SNLModuleParamsStuct::name);
     648            0 :                 if (ThisParamObj > 0) {
     649            0 :                     state.dataPhotovoltaic->PVarray(PVnum).SNLPVModule = tmpSNLModuleParams(ThisParamObj); // entire structure assignment
     650              :                 } else {
     651            0 :                     ShowSevereError(state, format("Invalid PV performance object name of {}", state.dataPhotovoltaic->PVarray(PVnum).PerfObjName));
     652            0 :                     ShowContinueError(state, format("Entered in {} = {}", cPVGeneratorObjectName, state.dataPhotovoltaic->PVarray(PVnum).Name));
     653            0 :                     ErrorsFound = true;
     654              :                 }
     655            0 :             } break;
     656            0 :             default:
     657            0 :                 break;
     658              :             }
     659              : 
     660              :             // set up report variables CurrentModuleObject='Photovoltaics'
     661            4 :             SetupOutputVariable(state,
     662              :                                 "Generator Produced DC Electricity Rate",
     663              :                                 Constant::Units::W,
     664            2 :                                 state.dataPhotovoltaic->PVarray(PVnum).Report.DCPower,
     665              :                                 OutputProcessor::TimeStepType::System,
     666              :                                 OutputProcessor::StoreType::Average,
     667            2 :                                 state.dataPhotovoltaic->PVarray(PVnum).Name);
     668            4 :             SetupOutputVariable(state,
     669              :                                 "Generator Produced DC Electricity Energy",
     670              :                                 Constant::Units::J,
     671            2 :                                 state.dataPhotovoltaic->PVarray(PVnum).Report.DCEnergy,
     672              :                                 OutputProcessor::TimeStepType::System,
     673              :                                 OutputProcessor::StoreType::Sum,
     674            2 :                                 state.dataPhotovoltaic->PVarray(PVnum).Name,
     675              :                                 Constant::eResource::ElectricityProduced,
     676              :                                 OutputProcessor::Group::Plant,
     677              :                                 OutputProcessor::EndUseCat::Photovoltaic);
     678            4 :             SetupOutputVariable(state,
     679              :                                 "Generator PV Array Efficiency",
     680              :                                 Constant::Units::None,
     681            2 :                                 state.dataPhotovoltaic->PVarray(PVnum).Report.ArrayEfficiency,
     682              :                                 OutputProcessor::TimeStepType::System,
     683              :                                 OutputProcessor::StoreType::Average,
     684            2 :                                 state.dataPhotovoltaic->PVarray(PVnum).Name);
     685              : 
     686              :             // CurrentModuleObject='Equiv1Diode or Sandia Photovoltaics'
     687            3 :             if ((state.dataPhotovoltaic->PVarray(PVnum).PVModelType == PVModel::TRNSYS) ||
     688            1 :                 (state.dataPhotovoltaic->PVarray(PVnum).PVModelType == PVModel::Sandia)) {
     689            2 :                 SetupOutputVariable(state,
     690              :                                     "Generator PV Cell Temperature",
     691              :                                     Constant::Units::C,
     692            1 :                                     state.dataPhotovoltaic->PVarray(PVnum).Report.CellTemp,
     693              :                                     OutputProcessor::TimeStepType::System,
     694              :                                     OutputProcessor::StoreType::Average,
     695            1 :                                     state.dataPhotovoltaic->PVarray(PVnum).Name);
     696            2 :                 SetupOutputVariable(state,
     697              :                                     "Generator PV Short Circuit Current",
     698              :                                     Constant::Units::A,
     699            1 :                                     state.dataPhotovoltaic->PVarray(PVnum).Report.ArrayIsc,
     700              :                                     OutputProcessor::TimeStepType::System,
     701              :                                     OutputProcessor::StoreType::Average,
     702            1 :                                     state.dataPhotovoltaic->PVarray(PVnum).Name);
     703            2 :                 SetupOutputVariable(state,
     704              :                                     "Generator PV Open Circuit Voltage",
     705              :                                     Constant::Units::V,
     706            1 :                                     state.dataPhotovoltaic->PVarray(PVnum).Report.ArrayVoc,
     707              :                                     OutputProcessor::TimeStepType::System,
     708              :                                     OutputProcessor::StoreType::Average,
     709            1 :                                     state.dataPhotovoltaic->PVarray(PVnum).Name);
     710              :             }
     711              : 
     712              :             // do some checks and setup
     713            2 :             if (state.dataPhotovoltaic->PVarray(PVnum).CellIntegrationMode == CellIntegration::SurfaceOutsideFace) {
     714              :                 // check that surface is HeatTransfer and a Construction with Internal Source was used
     715            0 :                 if (!state.dataSurface->Surface(state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr).HeatTransSurf) {
     716            0 :                     ShowSevereError(state,
     717            0 :                                     format("Must use a surface with heat transfer for IntegratedSurfaceOutsideFace mode in {}",
     718            0 :                                            state.dataPhotovoltaic->PVarray(PVnum).Name));
     719            0 :                     ErrorsFound = true;
     720            0 :                 } else if (!state.dataConstruction
     721            0 :                                 ->Construct(state.dataSurface->Surface(state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr).Construction)
     722            0 :                                 .SourceSinkPresent) {
     723            0 :                     ShowSevereError(state,
     724            0 :                                     format("Must use a surface with internal source construction for IntegratedSurfaceOutsideFace mode in {}",
     725            0 :                                            state.dataPhotovoltaic->PVarray(PVnum).Name));
     726            0 :                     ErrorsFound = true;
     727              :                 }
     728              :             }
     729              : 
     730            2 :             if (state.dataPhotovoltaic->PVarray(PVnum).CellIntegrationMode == CellIntegration::TranspiredCollector) {
     731            0 :                 GetTranspiredCollectorIndex(state, state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr, state.dataPhotovoltaic->PVarray(PVnum).UTSCPtr);
     732              :             }
     733              : 
     734            2 :             if (state.dataPhotovoltaic->PVarray(PVnum).CellIntegrationMode == CellIntegration::ExteriorVentedCavity) {
     735            0 :                 GetExtVentedCavityIndex(
     736            0 :                     state, state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr, state.dataPhotovoltaic->PVarray(PVnum).ExtVentCavPtr);
     737              :             }
     738              : 
     739            2 :             if (state.dataPhotovoltaic->PVarray(PVnum).CellIntegrationMode == CellIntegration::PVTSolarCollector) {
     740            2 :                 state.dataPhotovoltaic->PVarray(PVnum).PVTPtr = GetPVTmodelIndex(state, state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr);
     741              :             }
     742              :         }
     743              : 
     744            2 :         if (ErrorsFound) {
     745            0 :             ShowFatalError(state, "Errors found in getting photovoltaic input");
     746              :         }
     747            2 :     }
     748              : 
     749            5 :     int GetPVZone(EnergyPlusData &state, int const SurfNum)
     750              :     {
     751              :         // SUBROUTINE INFORMATION:
     752              :         //       AUTHOR         Rick Strand
     753              :         //       DATE WRITTEN   Sept 2017
     754              : 
     755              :         // PURPOSE OF THIS SUBROUTINE:
     756              :         // Get the zone number for this PV array for use when zone multipliers are applied
     757              : 
     758            5 :         int GetPVZone(0);
     759              : 
     760            5 :         if (SurfNum > 0) {
     761            5 :             GetPVZone = state.dataSurface->Surface(SurfNum).Zone;
     762            5 :             if (GetPVZone == 0) { // might need to get the zone number from the name
     763            3 :                 GetPVZone = Util::FindItemInList(state.dataSurface->Surface(SurfNum).ZoneName, state.dataHeatBal->Zone, state.dataGlobal->NumOfZones);
     764              :             }
     765              :         }
     766              : 
     767            5 :         return GetPVZone;
     768              :     }
     769              : 
     770              :     // **************************************
     771              : 
     772            0 :     void CalcSimplePV(EnergyPlusData &state, int const thisPV)
     773              :     {
     774              : 
     775              :         // SUBROUTINE INFORMATION:
     776              :         //       AUTHOR         B. Griffith
     777              :         //       DATE WRITTEN   Jan. 2004
     778              :         //       MODIFIED       B. Griffith, Aug. 2008
     779              :         //       RE-ENGINEERED  na
     780              : 
     781              :         // PURPOSE OF THIS SUBROUTINE:
     782              :         // calculate the electricity production using a simple PV model
     783              : 
     784              :         // Using/Aliasing
     785            0 :         Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
     786              : 
     787              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     788              :         int ThisSurf; // working index ptr to Surface arrays
     789              :         Real64 Eff;   // working variable for solar electric efficiency
     790              : 
     791            0 :         ThisSurf = state.dataPhotovoltaic->PVarray(thisPV).SurfacePtr;
     792              : 
     793            0 :         if (state.dataHeatBal->SurfQRadSWOutIncident(ThisSurf) > DataPhotovoltaics::MinIrradiance) {
     794              : 
     795              :             // get efficiency
     796            0 :             switch (state.dataPhotovoltaic->PVarray(thisPV).SimplePVModule.EfficencyInputMode) {
     797            0 :             case Efficiency::Fixed: {
     798            0 :                 Eff = state.dataPhotovoltaic->PVarray(thisPV).SimplePVModule.PVEfficiency;
     799            0 :             } break;
     800            0 :             case Efficiency::Scheduled: { // get from schedule
     801            0 :                 Eff = state.dataPhotovoltaic->PVarray(thisPV).SimplePVModule.effSched->getCurrentVal();
     802            0 :                 state.dataPhotovoltaic->PVarray(thisPV).SimplePVModule.PVEfficiency = Eff;
     803            0 :             } break;
     804            0 :             default: {
     805            0 :                 Eff = 0.0; // Suppress uninitialized warning
     806            0 :                 ShowSevereError(state, "caught bad Mode in Generator:Photovoltaic:Simple use FIXED or SCHEDULED efficiency mode");
     807            0 :             } break;
     808              :             }
     809              : 
     810            0 :             state.dataPhotovoltaic->PVarray(thisPV).Report.DCPower =
     811            0 :                 state.dataPhotovoltaic->PVarray(thisPV).SimplePVModule.AreaCol * Eff *
     812            0 :                 state.dataHeatBal->SurfQRadSWOutIncident(
     813              :                     ThisSurf); // active solar cellsurface net area | solar conversion efficiency | solar incident
     814              : 
     815              :             // store sink term in appropriate place for surface heat transfer integration
     816            0 :             state.dataPhotovoltaic->PVarray(thisPV).SurfaceSink = state.dataPhotovoltaic->PVarray(thisPV).Report.DCPower;
     817              : 
     818              :             // array energy, power * timestep
     819            0 :             state.dataPhotovoltaic->PVarray(thisPV).Report.DCEnergy = state.dataPhotovoltaic->PVarray(thisPV).Report.DCPower * TimeStepSysSec;
     820            0 :             state.dataPhotovoltaic->PVarray(thisPV).Report.ArrayEfficiency = Eff;
     821              :         } else { // not enough incident solar, zero things out
     822              : 
     823            0 :             state.dataPhotovoltaic->PVarray(thisPV).SurfaceSink = 0.0;
     824            0 :             state.dataPhotovoltaic->PVarray(thisPV).Report.DCEnergy = 0.0;
     825            0 :             state.dataPhotovoltaic->PVarray(thisPV).Report.DCPower = 0.0;
     826            0 :             state.dataPhotovoltaic->PVarray(thisPV).Report.ArrayEfficiency = 0.0;
     827              :         }
     828            0 :     }
     829              : 
     830            3 :     void ReportPV(EnergyPlusData &state, int const PVnum)
     831              :     {
     832              : 
     833              :         // SUBROUTINE INFORMATION:
     834              :         //       AUTHOR         B. Griffith
     835              :         //       DATE WRITTEN   Jan. 2004
     836              :         //       MODIFIED       B. Griffith, Aug. 2008
     837              : 
     838              :         // PURPOSE OF THIS SUBROUTINE:
     839              :         // collect statements that assign to variables tied to output variables
     840              : 
     841              :         // Using/Aliasing
     842            3 :         Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
     843              :         using TranspiredCollector::SetUTSCQdotSource;
     844              : 
     845              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     846              :         int thisZone; // working index for zones
     847              : 
     848            3 :         state.dataPhotovoltaic->PVarray(PVnum).Report.DCEnergy = state.dataPhotovoltaic->PVarray(PVnum).Report.DCPower * TimeStepSysSec;
     849              : 
     850              :         // add check for multiplier.  if surface is attached to a zone that is on a multiplier
     851              :         // then PV production should be multiplied out as well
     852              : 
     853            3 :         thisZone = state.dataPhotovoltaic->PVarray(PVnum).Zone;
     854            3 :         if (thisZone != 0) { // might need to apply multiplier
     855            2 :             state.dataPhotovoltaic->PVarray(PVnum).Report.DCEnergy *=
     856            2 :                 (state.dataHeatBal->Zone(thisZone).Multiplier * state.dataHeatBal->Zone(thisZone).ListMultiplier);
     857            2 :             state.dataPhotovoltaic->PVarray(PVnum).Report.DCPower *=
     858            2 :                 (state.dataHeatBal->Zone(thisZone).Multiplier * state.dataHeatBal->Zone(thisZone).ListMultiplier);
     859              :         }
     860              : 
     861            3 :         switch (state.dataPhotovoltaic->PVarray(PVnum).CellIntegrationMode) {
     862              :             // SurfaceSink is not multiplied...
     863            0 :         case CellIntegration::SurfaceOutsideFace: {
     864            0 :             state.dataHeatBalFanSys->QPVSysSource(state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr) =
     865            0 :                 -1.0 * state.dataPhotovoltaic->PVarray(PVnum).SurfaceSink;
     866            0 :         } break;
     867            0 :         case CellIntegration::TranspiredCollector: {
     868            0 :             SetUTSCQdotSource(state, state.dataPhotovoltaic->PVarray(PVnum).UTSCPtr, -1.0 * state.dataPhotovoltaic->PVarray(PVnum).SurfaceSink);
     869            0 :         } break;
     870            0 :         case CellIntegration::ExteriorVentedCavity: {
     871            0 :             SetVentedModuleQdotSource(
     872            0 :                 state, state.dataPhotovoltaic->PVarray(PVnum).ExtVentCavPtr, -1.0 * state.dataPhotovoltaic->PVarray(PVnum).SurfaceSink);
     873            0 :         } break;
     874            0 :         case CellIntegration::PVTSolarCollector: {
     875            0 :             PhotovoltaicThermalCollectors::SetPVTQdotSource(
     876            0 :                 state, state.dataPhotovoltaic->PVarray(PVnum).PVTPtr, -1.0 * state.dataPhotovoltaic->PVarray(PVnum).SurfaceSink);
     877            0 :         } break;
     878            3 :         default:
     879            3 :             break;
     880              :         }
     881            3 :     }
     882              : 
     883              :     // *************
     884              : 
     885            0 :     void CalcSandiaPV(EnergyPlusData &state,
     886              :                       int const PVnum,   // ptr to current PV system
     887              :                       bool const RunFlag // controls if generator is scheduled *ON*
     888              :     )
     889              :     {
     890              : 
     891              :         // SUBROUTINE INFORMATION:
     892              :         //       AUTHOR         B. Griffith , (derived from Greg Barker's TRNSYS type101 for SANDIA PV model)
     893              :         //       DATE WRITTEN   Jan 2004
     894              :         //       MODIFIED       B. Griffith, Aug. 2008 reworked for new, single-PV-generator data structure
     895              :         //       RE-ENGINEERED  na
     896              : 
     897              :         // PURPOSE OF THIS SUBROUTINE:
     898              :         // Calculate various PV system performance indices at the current timestep
     899              : 
     900              :         // METHODOLOGY EMPLOYED:
     901              :         //  adapted code from a set of F77 routines by G. Barker that implement the model
     902              :         //  This routines works on a single photovoltaic object of the type 'GENERATOR:PV:SANDIA'
     903              :         //  Each major model equation has its own function (in this module)
     904              : 
     905              :         // REFERENCES:
     906              :         // King, David L. . Photovoltaic module and array performance characterization methods for all
     907              :         //   system operating conditions. Pro. NREL/SNL Photovoltaics Program Review, AIP Press, Lakewood CO
     908              :         //   Sandia National Laboratories
     909              : 
     910              :         // Davis, M.W., A.H. Fanney, and B.P. Dougherty. Measured versus predicted performance of Building
     911              :         //    integrated photovoltaics. Solar 2002, Sunrise on the Reliable Energy Economy, June 15-19, 2002 Reno, NV
     912              : 
     913              :         // Using/Aliasing
     914              :         using PhotovoltaicThermalCollectors::GetPVTTsColl;
     915              :         using TranspiredCollector::GetUTSCTsColl;
     916              : 
     917              :         int ThisSurf; // working variable for indexing surfaces
     918              :         Real64 Ee;
     919              : 
     920            0 :         ThisSurf = state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr;
     921            0 :         auto &thisPVarray = state.dataPhotovoltaic->PVarray(PVnum);
     922              : 
     923              :         //   get input from elsewhere in Energyplus for the current point in the simulation
     924            0 :         thisPVarray.SNLPVinto.IcBeam = state.dataHeatBal->SurfQRadSWOutIncidentBeam(ThisSurf); //(W/m2)from DataHeatBalance
     925            0 :         thisPVarray.SNLPVinto.IcDiffuse =
     926            0 :             state.dataHeatBal->SurfQRadSWOutIncident(ThisSurf) - state.dataHeatBal->SurfQRadSWOutIncidentBeam(ThisSurf); //(W/ m2)(was kJ/hr m2)
     927            0 :         thisPVarray.SNLPVinto.IncidenceAngle =
     928            0 :             std::acos(state.dataHeatBal->SurfCosIncidenceAngle(ThisSurf)) / Constant::DegToRad;         // (deg) from dataHeatBalance
     929            0 :         thisPVarray.SNLPVinto.ZenithAngle = std::acos(state.dataEnvrn->SOLCOS(3)) / Constant::DegToRad; //(degrees),
     930            0 :         thisPVarray.SNLPVinto.Tamb = state.dataSurface->SurfOutDryBulbTemp(ThisSurf);                   //(deg. C)
     931            0 :         thisPVarray.SNLPVinto.WindSpeed = state.dataSurface->SurfOutWindSpeed(ThisSurf);                // (m/s)
     932            0 :         thisPVarray.SNLPVinto.Altitude = state.dataEnvrn->Elevation;                                    // from DataEnvironment via USE
     933              : 
     934            0 :         if (((thisPVarray.SNLPVinto.IcBeam + thisPVarray.SNLPVinto.IcDiffuse) > DataPhotovoltaics::MinIrradiance) && (RunFlag)) {
     935              : 
     936              :             // first determine PV cell temperatures depending on model
     937            0 :             switch (thisPVarray.CellIntegrationMode) {
     938            0 :             case CellIntegration::Decoupled: { // Sandia module temperature model for rack mounted PVs
     939              :                 // Calculate back-of-module temperature:
     940            0 :                 thisPVarray.SNLPVCalc.Tback = SandiaModuleTemperature(thisPVarray.SNLPVinto.IcBeam,
     941              :                                                                       thisPVarray.SNLPVinto.IcDiffuse,
     942              :                                                                       thisPVarray.SNLPVinto.WindSpeed,
     943              :                                                                       thisPVarray.SNLPVinto.Tamb,
     944              :                                                                       thisPVarray.SNLPVModule.fd,
     945              :                                                                       thisPVarray.SNLPVModule.a,
     946              :                                                                       thisPVarray.SNLPVModule.b);
     947              : 
     948              :                 // Calculate cell temperature:
     949            0 :                 thisPVarray.SNLPVCalc.Tcell = SandiaTcellFromTmodule(thisPVarray.SNLPVCalc.Tback,
     950              :                                                                      thisPVarray.SNLPVinto.IcBeam,
     951              :                                                                      thisPVarray.SNLPVinto.IcDiffuse,
     952              :                                                                      thisPVarray.SNLPVModule.fd,
     953              :                                                                      thisPVarray.SNLPVModule.DT0);
     954              : 
     955            0 :             } break;
     956            0 :             case CellIntegration::SurfaceOutsideFace: {
     957              :                 // get back-of-module temperature from elsewhere in EnergyPlus
     958            0 :                 thisPVarray.SNLPVCalc.Tback = state.dataHeatBalSurf->SurfTempOut(thisPVarray.SurfacePtr);
     959              : 
     960            0 :                 thisPVarray.SNLPVCalc.Tcell = SandiaTcellFromTmodule(thisPVarray.SNLPVCalc.Tback,
     961              :                                                                      thisPVarray.SNLPVinto.IcBeam,
     962              :                                                                      thisPVarray.SNLPVinto.IcDiffuse,
     963              :                                                                      thisPVarray.SNLPVModule.fd,
     964              :                                                                      thisPVarray.SNLPVModule.DT0);
     965              : 
     966            0 :             } break;
     967            0 :             case CellIntegration::TranspiredCollector: {
     968            0 :                 GetUTSCTsColl(state, thisPVarray.UTSCPtr, thisPVarray.SNLPVCalc.Tback);
     969              : 
     970            0 :                 thisPVarray.SNLPVCalc.Tcell = SandiaTcellFromTmodule(thisPVarray.SNLPVCalc.Tback,
     971              :                                                                      thisPVarray.SNLPVinto.IcBeam,
     972              :                                                                      thisPVarray.SNLPVinto.IcDiffuse,
     973              :                                                                      thisPVarray.SNLPVModule.fd,
     974              :                                                                      thisPVarray.SNLPVModule.DT0);
     975              : 
     976            0 :             } break;
     977            0 :             case CellIntegration::ExteriorVentedCavity: {
     978            0 :                 GetExtVentedCavityTsColl(state, thisPVarray.ExtVentCavPtr, thisPVarray.SNLPVCalc.Tback);
     979              : 
     980            0 :                 thisPVarray.SNLPVCalc.Tcell = SandiaTcellFromTmodule(thisPVarray.SNLPVCalc.Tback,
     981              :                                                                      thisPVarray.SNLPVinto.IcBeam,
     982              :                                                                      thisPVarray.SNLPVinto.IcDiffuse,
     983              :                                                                      thisPVarray.SNLPVModule.fd,
     984              :                                                                      thisPVarray.SNLPVModule.DT0);
     985              : 
     986            0 :             } break;
     987            0 :             case CellIntegration::PVTSolarCollector: {
     988            0 :                 GetPVTTsColl(state, thisPVarray.PVTPtr, thisPVarray.SNLPVCalc.Tback);
     989            0 :                 thisPVarray.SNLPVCalc.Tcell = SandiaTcellFromTmodule(thisPVarray.SNLPVCalc.Tback,
     990              :                                                                      thisPVarray.SNLPVinto.IcBeam,
     991              :                                                                      thisPVarray.SNLPVinto.IcDiffuse,
     992              :                                                                      thisPVarray.SNLPVModule.fd,
     993              :                                                                      thisPVarray.SNLPVModule.DT0);
     994            0 :             } break;
     995            0 :             default: {
     996            0 :                 ShowSevereError(state, format("Sandia PV Simulation Temperature Modeling Mode Error in {}", thisPVarray.Name));
     997            0 :             } break;
     998              :             }
     999              : 
    1000              :             // Calculate Air Mass function
    1001            0 :             thisPVarray.SNLPVCalc.AMa = AbsoluteAirMass(thisPVarray.SNLPVinto.ZenithAngle, thisPVarray.SNLPVinto.Altitude);
    1002              : 
    1003              :             // Calculate F1 polynomial function:
    1004            0 :             thisPVarray.SNLPVCalc.F1 = SandiaF1(thisPVarray.SNLPVCalc.AMa,
    1005              :                                                 thisPVarray.SNLPVModule.a_0,
    1006              :                                                 thisPVarray.SNLPVModule.a_1,
    1007              :                                                 thisPVarray.SNLPVModule.a_2,
    1008              :                                                 thisPVarray.SNLPVModule.a_3,
    1009              :                                                 thisPVarray.SNLPVModule.a_4);
    1010              : 
    1011              :             // Calculate F2 polynomial function:
    1012            0 :             thisPVarray.SNLPVCalc.F2 = SandiaF2(thisPVarray.SNLPVinto.IncidenceAngle,
    1013              :                                                 thisPVarray.SNLPVModule.b_0,
    1014              :                                                 thisPVarray.SNLPVModule.b_1,
    1015              :                                                 thisPVarray.SNLPVModule.b_2,
    1016              :                                                 thisPVarray.SNLPVModule.b_3,
    1017              :                                                 thisPVarray.SNLPVModule.b_4,
    1018              :                                                 thisPVarray.SNLPVModule.b_5);
    1019              : 
    1020              :             // Calculate short-circuit current function:
    1021            0 :             thisPVarray.SNLPVCalc.Isc = SandiaIsc(thisPVarray.SNLPVCalc.Tcell,
    1022              :                                                   thisPVarray.SNLPVModule.Isc0,
    1023              :                                                   thisPVarray.SNLPVinto.IcBeam,
    1024              :                                                   thisPVarray.SNLPVinto.IcDiffuse,
    1025              :                                                   thisPVarray.SNLPVCalc.F1,
    1026              :                                                   thisPVarray.SNLPVCalc.F2,
    1027              :                                                   thisPVarray.SNLPVModule.fd,
    1028              :                                                   thisPVarray.SNLPVModule.aIsc);
    1029              : 
    1030              :             // Calculate effective irradiance function:
    1031            0 :             Ee = SandiaEffectiveIrradiance(
    1032              :                 thisPVarray.SNLPVCalc.Tcell, thisPVarray.SNLPVCalc.Isc, thisPVarray.SNLPVModule.Isc0, thisPVarray.SNLPVModule.aIsc);
    1033              :             // Calculate Imp function:
    1034            0 :             thisPVarray.SNLPVCalc.Imp = SandiaImp(thisPVarray.SNLPVCalc.Tcell,
    1035              :                                                   Ee,
    1036              :                                                   thisPVarray.SNLPVModule.Imp0,
    1037              :                                                   thisPVarray.SNLPVModule.aImp,
    1038              :                                                   thisPVarray.SNLPVModule.c_0,
    1039              :                                                   thisPVarray.SNLPVModule.c_1);
    1040              : 
    1041              :             // Calculate Voc function:
    1042            0 :             thisPVarray.SNLPVCalc.Voc = SandiaVoc(thisPVarray.SNLPVCalc.Tcell,
    1043              :                                                   Ee,
    1044              :                                                   thisPVarray.SNLPVModule.Voc0,
    1045              :                                                   thisPVarray.SNLPVModule.NcellSer,
    1046              :                                                   thisPVarray.SNLPVModule.DiodeFactor,
    1047              :                                                   thisPVarray.SNLPVModule.BVoc0,
    1048              :                                                   thisPVarray.SNLPVModule.mBVoc);
    1049              : 
    1050              :             // Calculate Vmp: voltage at maximum powerpoint
    1051            0 :             thisPVarray.SNLPVCalc.Vmp = SandiaVmp(thisPVarray.SNLPVCalc.Tcell,
    1052              :                                                   Ee,
    1053              :                                                   thisPVarray.SNLPVModule.Vmp0,
    1054              :                                                   thisPVarray.SNLPVModule.NcellSer,
    1055              :                                                   thisPVarray.SNLPVModule.DiodeFactor,
    1056              :                                                   thisPVarray.SNLPVModule.BVmp0,
    1057              :                                                   thisPVarray.SNLPVModule.mBVmp,
    1058              :                                                   thisPVarray.SNLPVModule.c_2,
    1059              :                                                   thisPVarray.SNLPVModule.c_3);
    1060              : 
    1061              :             // Calculate Ix function:
    1062            0 :             thisPVarray.SNLPVCalc.Ix = SandiaIx(thisPVarray.SNLPVCalc.Tcell,
    1063              :                                                 Ee,
    1064              :                                                 thisPVarray.SNLPVModule.Ix0,
    1065              :                                                 thisPVarray.SNLPVModule.aIsc,
    1066              :                                                 thisPVarray.SNLPVModule.aImp,
    1067              :                                                 thisPVarray.SNLPVModule.c_4,
    1068              :                                                 thisPVarray.SNLPVModule.c_5);
    1069              : 
    1070              :             // Calculate Vx function:
    1071            0 :             thisPVarray.SNLPVCalc.Vx = thisPVarray.SNLPVCalc.Voc / 2.0;
    1072              : 
    1073              :             // Calculate Ixx function:
    1074            0 :             thisPVarray.SNLPVCalc.Ixx = SandiaIxx(thisPVarray.SNLPVCalc.Tcell,
    1075              :                                                   Ee,
    1076              :                                                   thisPVarray.SNLPVModule.Ixx0,
    1077              :                                                   thisPVarray.SNLPVModule.aImp,
    1078              :                                                   thisPVarray.SNLPVModule.c_6,
    1079              :                                                   thisPVarray.SNLPVModule.c_7);
    1080              :             // Calculate Vxx :
    1081            0 :             thisPVarray.SNLPVCalc.Vxx = 0.5 * (thisPVarray.SNLPVCalc.Voc + thisPVarray.SNLPVCalc.Vmp);
    1082              : 
    1083              :             // Calculate Pmp, single module: power at maximum powerpoint
    1084            0 :             thisPVarray.SNLPVCalc.Pmp = thisPVarray.SNLPVCalc.Imp * thisPVarray.SNLPVCalc.Vmp; // W
    1085              : 
    1086              :             // Calculate PV efficiency at maximum power point
    1087            0 :             thisPVarray.SNLPVCalc.EffMax =
    1088            0 :                 thisPVarray.SNLPVCalc.Pmp / (thisPVarray.SNLPVinto.IcBeam + thisPVarray.SNLPVinto.IcDiffuse) / thisPVarray.SNLPVModule.Acoll;
    1089              : 
    1090              :             // Scale to NumStrings and NumSeries:
    1091            0 :             thisPVarray.SNLPVCalc.Pmp *= thisPVarray.NumSeriesNParall * thisPVarray.NumModNSeries;
    1092            0 :             thisPVarray.SNLPVCalc.Imp *= thisPVarray.NumModNSeries;
    1093            0 :             thisPVarray.SNLPVCalc.Vmp *= thisPVarray.NumModNSeries;
    1094            0 :             thisPVarray.SNLPVCalc.Isc *= thisPVarray.NumSeriesNParall;
    1095            0 :             thisPVarray.SNLPVCalc.Voc *= thisPVarray.NumModNSeries;
    1096            0 :             thisPVarray.SNLPVCalc.Ix *= thisPVarray.NumSeriesNParall;
    1097            0 :             thisPVarray.SNLPVCalc.Ixx *= thisPVarray.NumSeriesNParall;
    1098            0 :             thisPVarray.SNLPVCalc.Vx *= thisPVarray.NumModNSeries;
    1099            0 :             thisPVarray.SNLPVCalc.Vxx *= thisPVarray.NumModNSeries;
    1100            0 :             thisPVarray.SNLPVCalc.SurfaceSink = thisPVarray.SNLPVCalc.Pmp;
    1101              :         } else { // Ibeam+Idiff < MaxIrradiance or not RunFlag
    1102              :             // so zero things.
    1103            0 :             thisPVarray.SNLPVCalc.Vmp = 0.0;
    1104            0 :             thisPVarray.SNLPVCalc.Imp = 0.0;
    1105            0 :             thisPVarray.SNLPVCalc.Pmp = 0.0;
    1106            0 :             thisPVarray.SNLPVCalc.EffMax = 0.0;
    1107            0 :             thisPVarray.SNLPVCalc.Isc = 0.0;
    1108            0 :             thisPVarray.SNLPVCalc.Voc = 0.0;
    1109            0 :             thisPVarray.SNLPVCalc.Tcell = thisPVarray.SNLPVinto.Tamb;
    1110            0 :             thisPVarray.SNLPVCalc.Tback = thisPVarray.SNLPVinto.Tamb;
    1111            0 :             thisPVarray.SNLPVCalc.AMa = 999.0;
    1112            0 :             thisPVarray.SNLPVCalc.F1 = 0.0;
    1113            0 :             thisPVarray.SNLPVCalc.F2 = 0.0;
    1114            0 :             thisPVarray.SNLPVCalc.Ix = 0.0;
    1115            0 :             thisPVarray.SNLPVCalc.Vx = 0.0;
    1116            0 :             thisPVarray.SNLPVCalc.Ixx = 0.0;
    1117            0 :             thisPVarray.SNLPVCalc.Vxx = 0.0;
    1118            0 :             thisPVarray.SNLPVCalc.SurfaceSink = 0.0;
    1119              :         } // Ibeam+Idiff > MinIrradiance and runflag
    1120              : 
    1121              :         // update calculations to report variables
    1122            0 :         thisPVarray.Report.DCPower = thisPVarray.SNLPVCalc.Pmp;
    1123            0 :         thisPVarray.Report.ArrayIsc = thisPVarray.SNLPVCalc.Isc;
    1124            0 :         thisPVarray.Report.ArrayVoc = thisPVarray.SNLPVCalc.Voc;
    1125            0 :         thisPVarray.Report.CellTemp = thisPVarray.SNLPVCalc.Tcell;
    1126            0 :         thisPVarray.Report.ArrayEfficiency = thisPVarray.SNLPVCalc.EffMax;
    1127            0 :         thisPVarray.SurfaceSink = thisPVarray.SNLPVCalc.SurfaceSink;
    1128            0 :     }
    1129              : 
    1130              :     // ********************
    1131              :     // begin routines for Equivalent one-diode model by Bradley/Ulleberg
    1132              : 
    1133            0 :     void InitTRNSYSPV(EnergyPlusData &state, int const PVnum) // the number of the GENERATOR:PHOTOVOLTAICS (passed in)
    1134              :     {
    1135              : 
    1136              :         // SUBROUTINE INFORMATION:
    1137              :         //       AUTHOR         David Bradley
    1138              :         //       DATE WRITTEN   April 2003
    1139              :         //       MODIFIED       BG March 2007 reworked for CR7109 (reverse DD testing)
    1140              :         //                      B. Griffith, Aug. 2008 reworked for new, single-PV-generator data structure
    1141              :         //       RE-ENGINEERED  na
    1142              : 
    1143              :         // PURPOSE OF THIS SUBROUTINE:
    1144              :         // This subroutine initializes the PV arrays during simulation. It performs both start of
    1145              :         // simulation initializations and start of timestep initializations. The structure of the
    1146              :         // subroutine was taken from InitBaseboard.
    1147              : 
    1148              :         // Using/Aliasing
    1149              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1150              :         Real64 TimeElapsed; // Fraction of the current hour that has elapsed (h)
    1151              : 
    1152              :         // perform the one time initializations
    1153            0 :         if (state.dataPhotovoltaicState->MyOneTimeFlag) {
    1154              :             // initialize the environment and sizing flags
    1155            0 :             state.dataPhotovoltaicState->MyEnvrnFlag.dimension(state.dataPhotovoltaic->NumPVs, true);
    1156            0 :             state.dataPhotovoltaicState->MyOneTimeFlag = false;
    1157              :         }
    1158              : 
    1159              :         // Do the Begin Environment initializations
    1160            0 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataPhotovoltaicState->MyEnvrnFlag(PVnum)) {
    1161            0 :             state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.CellTempK =
    1162            0 :                 state.dataSurface->SurfOutDryBulbTemp(state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr) + Constant::Kelvin;
    1163            0 :             state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.LastCellTempK =
    1164            0 :                 state.dataSurface->SurfOutDryBulbTemp(state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr) + Constant::Kelvin;
    1165            0 :             state.dataPhotovoltaicState->MyEnvrnFlag(PVnum) = false;
    1166              :         }
    1167              : 
    1168            0 :         if (!state.dataGlobal->BeginEnvrnFlag) {
    1169            0 :             state.dataPhotovoltaicState->MyEnvrnFlag(PVnum) = true;
    1170              :         }
    1171              : 
    1172              :         // Do the beginning of every time step initializations
    1173            0 :         TimeElapsed =
    1174            0 :             state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
    1175            0 :         if (state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.TimeElapsed != TimeElapsed) {
    1176              :             // The simulation has advanced to the next system timestep.  Save conditions from the end of the previous system
    1177            0 :             state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.LastCellTempK = state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.CellTempK;
    1178            0 :             state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.TimeElapsed = TimeElapsed;
    1179              :         }
    1180              : 
    1181            0 :         if (any_gt(state.dataHeatBal->SurfQRadSWOutIncident, 0.0)) {
    1182              :             //  Determine the amount of radiation incident on each PV
    1183            0 :             state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.Insolation =
    1184            0 :                 state.dataHeatBal->SurfQRadSWOutIncident(state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr); //[W/m2]
    1185              :         } else {
    1186            0 :             state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.Insolation = 0.0;
    1187              :         }
    1188            0 :     }
    1189              : 
    1190              :     // *************
    1191              : 
    1192            0 :     void CalcTRNSYSPV(EnergyPlusData &state,
    1193              :                       int const PVnum,   // BTG added intent
    1194              :                       bool const RunFlag // BTG added intent    !flag tells whether the PV is ON or OFF
    1195              :     )
    1196              :     {
    1197              : 
    1198              :         // SUBROUTINE INFORMATION:
    1199              :         //       AUTHOR         D. Bradley
    1200              :         //       DATE WRITTEN   April 2003
    1201              :         //       MODIFIED       B. Griffith, February 2008-- added support for inverter
    1202              :         //                      multipliers, and building integrated heat transfer
    1203              :         //                      B. Griffith, Aug. 2008 reworked for new, single-PV-generator data structure
    1204              :         //       RE-ENGINEERED  na
    1205              : 
    1206              :         // PURPOSE OF THIS SUBROUTINE:
    1207              :         // This subroutine simulates the PV performance.
    1208              : 
    1209              :         using PhotovoltaicThermalCollectors::GetPVTTsColl;
    1210              :         using TranspiredCollector::GetUTSCTsColl;
    1211              : 
    1212            0 :         Real64 constexpr EPS(0.001);
    1213            0 :         Real64 constexpr ERR(0.001);
    1214            0 :         Real64 constexpr MinInsolation(30.0);
    1215            0 :         int constexpr KMAX(100);
    1216            0 :         Real64 constexpr EtaIni(0.10); // initial value of eta
    1217              :         Real64 DummyErr;
    1218              :         Real64 ETA;
    1219              :         Real64 Tambient;
    1220              :         Real64 EtaOld;
    1221              :         Real64 ILRef;
    1222              :         Real64 AARef;
    1223              :         Real64 IORef;
    1224              :         Real64 SeriesResistance;
    1225              :         Real64 IL;
    1226              :         Real64 AA;
    1227              :         Real64 IO;
    1228              :         Real64 ISCG1;
    1229              :         Real64 ISC;
    1230              :         Real64 VOCG1;
    1231              :         Real64 VOC;
    1232              :         Real64 VLEFT;
    1233              :         Real64 VRIGHT;
    1234              :         Real64 VM;
    1235              :         Real64 IM;
    1236              :         Real64 PM;
    1237              :         Real64 IA;
    1238              :         Real64 ISCA;
    1239              :         Real64 VA;
    1240              :         Real64 VOCA;
    1241              :         Real64 PA;
    1242            0 :         Real64 CellTemp(0.0); // cell temperature in Kelvin
    1243              :         Real64 CellTempC;     // cell temperature in degrees C
    1244              : 
    1245              :         // if the cell temperature mode is 2, convert the timestep to seconds
    1246            0 :         if (state.dataPhotovoltaicState->firstTime &&
    1247            0 :             state.dataPhotovoltaic->PVarray(PVnum).CellIntegrationMode == CellIntegration::DecoupledUllebergDynamic) {
    1248            0 :             state.dataPhotovoltaicState->PVTimeStep = double(state.dataGlobal->MinutesInTimeStep) * 60.0; // Seconds per time step
    1249              :         }
    1250            0 :         state.dataPhotovoltaicState->firstTime = false;
    1251              : 
    1252              :         // place the shunt resistance into its common block
    1253            0 :         state.dataPhotovoltaic->ShuntResistance = state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.ShuntResistance;
    1254              : 
    1255              :         // convert ambient temperature from C to K
    1256            0 :         Tambient = state.dataSurface->SurfOutDryBulbTemp(state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr) + Constant::Kelvin;
    1257              : 
    1258            0 :         auto const &thisPVarray = state.dataPhotovoltaic->PVarray(PVnum);
    1259              : 
    1260            0 :         if ((state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.Insolation > MinInsolation) && (RunFlag)) {
    1261              : 
    1262              :             // set initial values for eta iteration loop
    1263            0 :             DummyErr = 2.0 * ERR;
    1264            0 :             EtaOld = EtaIni;
    1265              :             int K;
    1266              : 
    1267              :             // Begin DO WHILE loop - until the error tolerance is reached.
    1268            0 :             ETA = 0.0;
    1269            0 :             while (DummyErr > ERR) {
    1270            0 :                 switch (state.dataPhotovoltaic->PVarray(PVnum).CellIntegrationMode) {
    1271            0 :                 case CellIntegration::Decoupled: {
    1272              :                     //  cell temperature based on energy balance
    1273            0 :                     state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.HeatLossCoef =
    1274            0 :                         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.TauAlpha *
    1275            0 :                         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.NOCTInsolation /
    1276            0 :                         (state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.NOCTCellTemp -
    1277            0 :                          state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.NOCTAmbTemp);
    1278            0 :                     CellTemp = Tambient + (state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.Insolation *
    1279            0 :                                            state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.TauAlpha /
    1280            0 :                                            state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.HeatLossCoef) *
    1281            0 :                                               (1.0 - ETA / state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.TauAlpha);
    1282            0 :                 } break;
    1283            0 :                 case CellIntegration::DecoupledUllebergDynamic: {
    1284              :                     //  cell temperature based on energy balance with thermal capacity effects
    1285            0 :                     CellTemp =
    1286            0 :                         Tambient +
    1287            0 :                         (state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.LastCellTempK - Tambient) *
    1288            0 :                             std::exp(-state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.HeatLossCoef /
    1289            0 :                                      state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.HeatCapacity * state.dataPhotovoltaicState->PVTimeStep) +
    1290            0 :                         (state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.TauAlpha - ETA) *
    1291            0 :                             state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.Insolation /
    1292            0 :                             state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.HeatLossCoef *
    1293            0 :                             (1.0 -
    1294            0 :                              std::exp(-state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.HeatLossCoef /
    1295            0 :                                       state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.HeatCapacity * state.dataPhotovoltaicState->PVTimeStep));
    1296            0 :                 } break;
    1297            0 :                 case CellIntegration::SurfaceOutsideFace: {
    1298            0 :                     CellTemp = state.dataHeatBalSurf->SurfTempOut(state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr) + Constant::Kelvin;
    1299            0 :                 } break;
    1300            0 :                 case CellIntegration::TranspiredCollector: {
    1301            0 :                     GetUTSCTsColl(state, state.dataPhotovoltaic->PVarray(PVnum).UTSCPtr, CellTemp);
    1302            0 :                     CellTemp += Constant::Kelvin;
    1303            0 :                 } break;
    1304            0 :                 case CellIntegration::ExteriorVentedCavity: {
    1305            0 :                     GetExtVentedCavityTsColl(state, state.dataPhotovoltaic->PVarray(PVnum).ExtVentCavPtr, CellTemp);
    1306            0 :                     CellTemp += Constant::Kelvin;
    1307            0 :                 } break;
    1308            0 :                 case CellIntegration::PVTSolarCollector: {
    1309            0 :                     GetPVTTsColl(state, thisPVarray.PVTPtr, CellTemp);
    1310            0 :                     CellTemp += Constant::Kelvin;
    1311            0 :                 } break;
    1312            0 :                 default:
    1313            0 :                     break;
    1314              :                 }
    1315              : 
    1316              :                 //  reference parameters
    1317            0 :                 ILRef = state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.RefIsc;
    1318            0 :                 AARef = (state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.TempCoefVoc *
    1319            0 :                              state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.RefTemperature -
    1320            0 :                          state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.RefVoc +
    1321            0 :                          state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.SemiConductorBandgap *
    1322            0 :                              state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.CellsInSeries) /
    1323            0 :                         (state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.TempCoefIsc *
    1324            0 :                              state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.RefTemperature / ILRef -
    1325              :                          3.0);
    1326            0 :                 IORef = ILRef * std::exp(-state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.RefVoc / AARef);
    1327              : 
    1328              :                 //  series resistance
    1329            0 :                 SeriesResistance =
    1330            0 :                     (AARef * std::log(1.0 - state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.Imp / ILRef) -
    1331            0 :                      state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.Vmp + state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.RefVoc) /
    1332            0 :                     state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.Imp;
    1333              : 
    1334              :                 //  temperature dependence
    1335            0 :                 IL = state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.Insolation /
    1336            0 :                      state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.RefInsolation *
    1337            0 :                      (ILRef + state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.TempCoefIsc *
    1338            0 :                                   (CellTemp - state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.RefTemperature));
    1339            0 :                 Real64 const cell_temp_ratio(CellTemp / state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.RefTemperature);
    1340            0 :                 AA = AARef * cell_temp_ratio;
    1341            0 :                 IO = IORef * pow_3(cell_temp_ratio) *
    1342            0 :                      std::exp(state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.SemiConductorBandgap *
    1343            0 :                               state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.CellsInSeries / AARef *
    1344            0 :                               (1.0 - state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.RefTemperature / CellTemp));
    1345              : 
    1346              :                 //  compute short circuit current and open circuit voltage
    1347              : 
    1348              :                 //   NEWTON --> ISC  (STARTVALUE: ISCG1 - BASED ON IL=ISC)
    1349            0 :                 ISCG1 = IL;
    1350            0 :                 NEWTON(state, ISC, FUN, FI, ISC, DataPrecisionGlobals::constant_zero, IO, IL, SeriesResistance, AA, ISCG1, EPS);
    1351              : 
    1352              :                 //   NEWTON --> VOC  (STARTVALUE: VOCG1 - BASED ON IM=0.0)
    1353            0 :                 VOCG1 = (std::log(IL / IO) + 1.0) * AA;
    1354            0 :                 NEWTON(state, VOC, FUN, FV, DataPrecisionGlobals::constant_zero, VOC, IO, IL, SeriesResistance, AA, VOCG1, EPS);
    1355              : 
    1356              :                 //  maximum power point tracking
    1357              : 
    1358              :                 //   SEARCH --> VM AT MAXIMUM POWER POINT
    1359            0 :                 VLEFT = 0.0;
    1360            0 :                 VRIGHT = VOC;
    1361            0 :                 SEARCH(state, VLEFT, VRIGHT, VM, K, IO, IL, SeriesResistance, AA, EPS, KMAX);
    1362              : 
    1363              :                 //   POWER --> IM & PM AT MAXIMUM POWER POINT
    1364            0 :                 POWER(state, IO, IL, SeriesResistance, AA, EPS, IM, VM, PM);
    1365              : 
    1366              :                 // calculate overall PV module efficiency
    1367            0 :                 ETA =
    1368            0 :                     PM / state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.Insolation / state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.Area;
    1369            0 :                 DummyErr = std::abs((ETA - EtaOld) / EtaOld);
    1370            0 :                 EtaOld = ETA;
    1371              : 
    1372              :             } // while
    1373              : 
    1374              :         } else {
    1375              :             // if there is no incident radiation or if the control switch is 'Off'
    1376            0 :             switch (state.dataPhotovoltaic->PVarray(PVnum).CellIntegrationMode) {
    1377            0 :             case CellIntegration::Decoupled: {
    1378            0 :                 CellTemp = Tambient;
    1379            0 :             } break;
    1380            0 :             case CellIntegration::DecoupledUllebergDynamic: {
    1381            0 :                 CellTemp = Tambient +
    1382            0 :                            (state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.LastCellTempK - Tambient) *
    1383            0 :                                std::exp(-state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.HeatLossCoef /
    1384            0 :                                         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVModule.HeatCapacity * state.dataPhotovoltaicState->PVTimeStep);
    1385            0 :             } break;
    1386            0 :             case CellIntegration::SurfaceOutsideFace: {
    1387            0 :                 CellTemp = state.dataHeatBalSurf->SurfTempOut(state.dataPhotovoltaic->PVarray(PVnum).SurfacePtr) + Constant::Kelvin;
    1388            0 :             } break;
    1389            0 :             case CellIntegration::TranspiredCollector: {
    1390            0 :                 GetUTSCTsColl(state, state.dataPhotovoltaic->PVarray(PVnum).UTSCPtr, CellTemp);
    1391            0 :                 CellTemp += Constant::Kelvin;
    1392            0 :             } break;
    1393            0 :             case CellIntegration::ExteriorVentedCavity: {
    1394            0 :                 GetExtVentedCavityTsColl(state, state.dataPhotovoltaic->PVarray(PVnum).ExtVentCavPtr, CellTemp);
    1395            0 :                 CellTemp += Constant::Kelvin;
    1396            0 :             } break;
    1397            0 :             case CellIntegration::PVTSolarCollector: {
    1398            0 :                 GetPVTTsColl(state, thisPVarray.PVTPtr, CellTemp);
    1399            0 :                 CellTemp += Constant::Kelvin;
    1400            0 :             } break;
    1401            0 :             default: {
    1402            0 :                 assert(false);
    1403              :             } break;
    1404              :             }
    1405              : 
    1406            0 :             state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.Insolation = 0.0;
    1407            0 :             IM = 0.0;  // module current
    1408            0 :             VM = 0.0;  // module voltage
    1409            0 :             PM = 0.0;  // module power
    1410            0 :             ETA = 0.0; // module efficiency
    1411            0 :             ISC = 0.0;
    1412            0 :             VOC = 0.0;
    1413              :         }
    1414              : 
    1415              :         // convert cell temperature back to C
    1416            0 :         CellTempC = CellTemp - Constant::Kelvin;
    1417              : 
    1418              :         // calculate array based outputs (so far, the outputs are module based
    1419            0 :         IA = state.dataPhotovoltaic->PVarray(PVnum).NumSeriesNParall * IM;
    1420            0 :         ISCA = state.dataPhotovoltaic->PVarray(PVnum).NumSeriesNParall * ISC;
    1421            0 :         VA = state.dataPhotovoltaic->PVarray(PVnum).NumModNSeries * VM;
    1422            0 :         VOCA = state.dataPhotovoltaic->PVarray(PVnum).NumModNSeries * VOC;
    1423            0 :         PA = IA * VA;
    1424              : 
    1425              :         // Place local variables into the reporting structure
    1426            0 :         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.ArrayCurrent = IA;
    1427            0 :         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.ArrayVoltage = VA;
    1428            0 :         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.ArrayPower = PA;
    1429            0 :         state.dataPhotovoltaic->PVarray(PVnum).Report.DCPower = PA;
    1430            0 :         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.ArrayEfficiency = ETA;
    1431            0 :         state.dataPhotovoltaic->PVarray(PVnum).Report.ArrayEfficiency = ETA;
    1432            0 :         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.CellTemp = CellTempC;
    1433            0 :         state.dataPhotovoltaic->PVarray(PVnum).Report.CellTemp = CellTempC;
    1434            0 :         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.CellTempK = CellTemp;
    1435            0 :         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.ArrayIsc = ISCA;
    1436            0 :         state.dataPhotovoltaic->PVarray(PVnum).Report.ArrayIsc = ISCA;
    1437            0 :         state.dataPhotovoltaic->PVarray(PVnum).TRNSYSPVcalc.ArrayVoc = VOCA;
    1438            0 :         state.dataPhotovoltaic->PVarray(PVnum).Report.ArrayVoc = VOCA;
    1439            0 :         state.dataPhotovoltaic->PVarray(PVnum).SurfaceSink = PA;
    1440            0 :     }
    1441              : 
    1442            0 :     void POWER(EnergyPlusData &state,
    1443              :                Real64 const IO,   // passed in from CalcPV
    1444              :                Real64 const IL,   // passed in from CalcPV
    1445              :                Real64 const RSER, // passed in from CalcPV
    1446              :                Real64 const AA,   // passed in from CalcPV
    1447              :                Real64 const EPS,  // passed in from CalcPV
    1448              :                Real64 &II,        // current [A]
    1449              :                Real64 const VV,   // voltage [V]
    1450              :                Real64 &PP         // power [W]
    1451              :     )
    1452              :     {
    1453              : 
    1454              :         // SUBROUTINE INFORMATION:
    1455              :         //       AUTHOR         O. Ulleberg, IFE Norway for Hydrogems
    1456              :         //       DATE WRITTEN   March 2001
    1457              :         //       MODIFIED       D. Bradley for use with EnergyPlus
    1458              :         //       RE-ENGINEERED  na
    1459              : 
    1460              :         // PURPOSE OF THIS SUBROUTINE:
    1461              :         // This subroutine calculates the power produced by the PV.
    1462              : 
    1463              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1464              :         Real64 IG1;
    1465              : 
    1466              :         // NEWTON --> II (STARTVALUE: IG1 BASED ON SIMPLIFIED I(I,V) EQUATION)
    1467            0 :         IG1 = IL - IO * std::exp(VV / AA - 1.0);
    1468            0 :         NEWTON(state, II, FUN, FI, II, VV, IO, IL, RSER, AA, IG1, EPS);
    1469            0 :         PP = II * VV;
    1470            0 :     }
    1471              : 
    1472            0 :     void NEWTON(EnergyPlusData &state,
    1473              :                 Real64 &XX,
    1474              :                 std::function<Real64(EnergyPlusData &state, Real64 const, Real64 const, Real64 const, Real64 const, Real64 const, Real64 const)> FXX,
    1475              :                 std::function<Real64(EnergyPlusData &state, Real64 const, Real64 const, Real64 const, Real64 const, Real64 const)> DER,
    1476              :                 Real64 const &II, // Autodesk Aliased to XX in some calls
    1477              :                 Real64 const &VV, // Autodesk Aliased to XX in some calls
    1478              :                 Real64 const IO,
    1479              :                 Real64 const IL,
    1480              :                 Real64 const RSER,
    1481              :                 Real64 const AA,
    1482              :                 Real64 const XS,
    1483              :                 Real64 const EPS)
    1484              :     {
    1485              : 
    1486              :         // SUBROUTINE INFORMATION:
    1487              :         //       AUTHOR         O. Ulleberg, IFE Norway for Hydrogems
    1488              :         //       DATE WRITTEN   March 2001
    1489              :         //       MODIFIED       D. Bradley for use with EnergyPlus
    1490              :         //       RE-ENGINEERED  na
    1491              : 
    1492              :         // PURPOSE OF THIS SUBROUTINE:
    1493              :         // This subroutine uses the Newton-Raphson method to solve a non linear equation with one variable.
    1494              : 
    1495              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1496              :         int COUNT;
    1497              :         Real64 ERR;
    1498              :         Real64 X0;
    1499              : 
    1500            0 :         COUNT = 0;
    1501            0 :         XX = XS;
    1502            0 :         ERR = 1.0;
    1503            0 :         while ((ERR > EPS) && (COUNT <= 10)) {
    1504            0 :             X0 = XX;
    1505            0 :             XX -= FXX(state, II, VV, IL, IO, RSER, AA) / DER(state, II, VV, IO, RSER, AA);
    1506            0 :             ++COUNT;
    1507            0 :             ERR = std::abs((XX - X0) / X0);
    1508              :         }
    1509            0 :     }
    1510              : 
    1511            0 :     void SEARCH(EnergyPlusData &state,
    1512              :                 Real64 &A,
    1513              :                 Real64 &B,
    1514              :                 Real64 &P,
    1515              :                 int &K,
    1516              :                 Real64 const IO,
    1517              :                 Real64 const IL,
    1518              :                 Real64 const RSER,
    1519              :                 Real64 const AA,
    1520              :                 Real64 const EPS,
    1521              :                 int const KMAX)
    1522              :     {
    1523              : 
    1524              :         // SUBROUTINE INFORMATION:
    1525              :         //       AUTHOR         O. Ulleberg, IFE Norway for Hydrogems
    1526              :         //       DATE WRITTEN   March 2001
    1527              :         //       MODIFIED       D. Bradley for use with EnergyPlus
    1528              :         //       RE-ENGINEERED  na
    1529              : 
    1530              :         // PURPOSE OF THIS SUBROUTINE:
    1531              :         // This subroutine minimum of an unimodal function with one variable. The algorithm was
    1532              :         // adapted to find the maximum power point of a PV module. The changes to the original
    1533              :         // algorithm are the following:
    1534              :         // 1. a subroutine "POWER" is called in order to calculate the power output of the PV module
    1535              :         // 2. the negative of the power of the PV module is taken so that the optimum can be found.
    1536              : 
    1537              :         // REFERENCES:
    1538              :         //   /1/ MATHEWS, JOHN H.  NUMERICAL METHODS:  FORTRAN PROGRAMS. 1992, PP 413.
    1539              :         //   /2/ NUMERICAL METHODS FOR MATHEMATICS, SCIENCE AND ENGINEERING, 2ND EDITION,
    1540              :         //       PRENTICE HALL, NEW JERSEY, 1992.
    1541              : 
    1542              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1543            0 :         Real64 constexpr DELTA(1.e-3);
    1544            0 :         Real64 constexpr EPSILON(1.e-3);
    1545              :         static Real64 const RONE((std::sqrt(5.0) - 1.0) / 2.0);
    1546              :         static Real64 const RTWO(RONE * RONE);
    1547              : 
    1548              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1549              :         Real64 C;
    1550              :         Real64 D;
    1551              :         Real64 H;
    1552              :         Real64 YP;
    1553              :         Real64 YA;
    1554              :         Real64 YB;
    1555              :         Real64 YC;
    1556              :         Real64 YD;
    1557              :         Real64 IM;
    1558              :         Real64 PM;
    1559              : 
    1560            0 :         H = B - A;
    1561            0 :         POWER(state, IO, IL, RSER, AA, EPS, IM, A, PM);
    1562            0 :         YA = -1.0 * PM;
    1563            0 :         POWER(state, IO, IL, RSER, AA, EPS, IM, B, PM);
    1564            0 :         YB = -1.0 * PM;
    1565            0 :         C = A + RTWO * H;
    1566            0 :         D = A + RONE * H;
    1567            0 :         POWER(state, IO, IL, RSER, AA, EPS, IM, C, PM);
    1568            0 :         YC = -1.0 * PM;
    1569            0 :         POWER(state, IO, IL, RSER, AA, EPS, IM, D, PM);
    1570            0 :         YD = -1.0 * PM;
    1571            0 :         K = 1;
    1572            0 :         while (std::abs(YB - YA) > EPSILON || H > DELTA) {
    1573            0 :             if (YC < YD) {
    1574            0 :                 B = D;
    1575            0 :                 YB = YD;
    1576            0 :                 D = C;
    1577            0 :                 YD = YC;
    1578            0 :                 H = B - A;
    1579            0 :                 C = A + RTWO * H;
    1580            0 :                 POWER(state, IO, IL, RSER, AA, EPS, IM, C, PM);
    1581            0 :                 YC = -1.0 * PM;
    1582              :             } else {
    1583            0 :                 A = C;
    1584            0 :                 YA = YC;
    1585            0 :                 C = D;
    1586            0 :                 YC = YD;
    1587            0 :                 H = B - A;
    1588            0 :                 D = A + RONE * H;
    1589            0 :                 POWER(state, IO, IL, RSER, AA, EPS, IM, D, PM);
    1590            0 :                 YD = -1.0 * PM;
    1591              :             }
    1592            0 :             ++K;
    1593              :         }
    1594            0 :         if (K < KMAX) {
    1595            0 :             P = A;
    1596            0 :             YP = YA;
    1597            0 :             if (YB < YA) {
    1598            0 :                 P = B;
    1599            0 :                 YP = YB;
    1600              :             }
    1601            0 :             return;
    1602              :         } else {
    1603            0 :             return;
    1604              :         }
    1605              :     }
    1606              : 
    1607            0 :     Real64 FUN(EnergyPlusData &state, Real64 const II, Real64 const VV, Real64 const IL, Real64 const IO, Real64 const RSER, Real64 const AA)
    1608              :     {
    1609              : 
    1610              :         // FUNCTION INFORMATION:
    1611              :         //       AUTHOR         O. Ulleberg, IFE Norway for Hydrogems
    1612              :         //       DATE WRITTEN   March 2001
    1613              :         //       MODIFIED       D. Bradley for EnergyPlus
    1614              :         //       RE-ENGINEERED
    1615              : 
    1616              :         // PURPOSE OF THIS FUNCTION:
    1617              :         // This function is based on the current-voltage characteristic of the PV module and is of the
    1618              :         // form f(I,V)=0
    1619              : 
    1620              :         // Return value
    1621            0 :         Real64 FUN(0.0);
    1622              : 
    1623            0 :         if (((VV + II * RSER) / AA) < 700.0) {
    1624            0 :             FUN = II - IL + IO * (std::exp((VV + II * RSER) / AA) - 1.0) - ((VV + II * RSER) / state.dataPhotovoltaic->ShuntResistance);
    1625              :         } else {
    1626            0 :             ShowSevereError(state, "EquivalentOneDiode Photovoltaic model failed to find maximum power point");
    1627            0 :             ShowContinueError(state, "Numerical solver failed trying to take exponential of too large a number");
    1628            0 :             ShowContinueError(state, format("Check input data in {}", pvModelNames[(int)PVModel::TRNSYS]));
    1629            0 :             ShowContinueError(state, format("VV (voltage) = {:.5R}", VV));
    1630            0 :             ShowContinueError(state, format("II (current) = {:.5R}", II));
    1631            0 :             ShowFatalError(state, "FUN: EnergyPlus terminates because of numerical problem in EquivalentOne-Diode PV model");
    1632              :         }
    1633              : 
    1634            0 :         return FUN;
    1635              :     }
    1636              : 
    1637            0 :     Real64 FI(EnergyPlusData &state, Real64 const II, Real64 const VV, Real64 const IO, Real64 const RSER, Real64 const AA)
    1638              :     {
    1639              : 
    1640              :         // FUNCTION INFORMATION:
    1641              :         //       AUTHOR         O. Ulleberg, IFE Norway for Hydrogems
    1642              :         //       DATE WRITTEN   March 2001
    1643              :         //       MODIFIED       D. Bradley for EnergyPlus
    1644              :         //       RE-ENGINEERED
    1645              : 
    1646              :         // PURPOSE OF THIS FUNCTION:
    1647              :         // partial differential of I=I(I,V)
    1648              : 
    1649              :         // METHODOLOGY EMPLOYED:
    1650              :         // the function is based on the current voltage characteristic of the PV module and is of
    1651              :         // the form dF(I,V)/dI=0
    1652              : 
    1653              :         // Return value
    1654            0 :         Real64 FI(0.0);
    1655              : 
    1656            0 :         if (((VV + II * RSER) / AA) < 700.0) {
    1657            0 :             FI = 1.0 + IO * std::exp((VV + II * RSER) / AA) * RSER / AA + (RSER / state.dataPhotovoltaic->ShuntResistance);
    1658              :         } else {
    1659            0 :             ShowSevereError(state, "EquivalentOneDiode Photovoltaic model failed to find maximum power point");
    1660            0 :             ShowContinueError(state, "Numerical solver failed trying to take exponential of too large a number");
    1661            0 :             ShowContinueError(state, format("Check input data in {}", pvModelNames[(int)PVModel::TRNSYS]));
    1662            0 :             ShowContinueError(state, format("VV (voltage) = {:.5R}", VV));
    1663            0 :             ShowContinueError(state, format("II (current) = {:.5R}", II));
    1664            0 :             ShowFatalError(state, "FI: EnergyPlus terminates because of numerical problem in EquivalentOne-Diode PV model");
    1665              :         }
    1666              : 
    1667            0 :         return FI;
    1668              :     }
    1669              : 
    1670            0 :     Real64 FV(EnergyPlusData &state, Real64 const II, Real64 const VV, Real64 const IO, Real64 const RSER, Real64 const AA)
    1671              :     {
    1672              : 
    1673              :         // FUNCTION INFORMATION:
    1674              :         //       AUTHOR         O. Ulleberg, IFE Norway for Hydrogems
    1675              :         //       DATE WRITTEN   March 2001
    1676              :         //       MODIFIED       D. Bradley for EnergyPlus
    1677              :         //       RE-ENGINEERED
    1678              : 
    1679              :         // PURPOSE OF THIS FUNCTION:
    1680              :         // partial differential of V=I(I,V)
    1681              : 
    1682              :         // METHODOLOGY EMPLOYED:
    1683              :         // the function is based on the current voltage characteristic of the PV module and is of
    1684              :         // the form dF(I,V)/dV=0
    1685              : 
    1686              :         // Return value
    1687            0 :         Real64 FV(0.0);
    1688              : 
    1689            0 :         if (((VV + II * RSER) / AA) < 700.0) {
    1690            0 :             FV = IO * std::exp((VV + II * RSER) / AA) / AA + (1.0 / state.dataPhotovoltaic->ShuntResistance);
    1691              :         } else {
    1692            0 :             ShowSevereError(state, "EquivalentOneDiode Photovoltaic model failed to find maximum power point");
    1693            0 :             ShowContinueError(state, "Numerical solver failed trying to take exponential of too large a number");
    1694            0 :             ShowContinueError(state, format("Check input data in {}", pvModelNames[(int)PVModel::TRNSYS]));
    1695            0 :             ShowContinueError(state, format("VV (voltage) = {:.5R}", VV));
    1696            0 :             ShowContinueError(state, format("II (current) = {:.5R}", II));
    1697            0 :             ShowFatalError(state, "FI: EnergyPlus terminates because of numerical problem in EquivalentOne-Diode PV model");
    1698              :         }
    1699              : 
    1700            0 :         return FV;
    1701              :     }
    1702              : 
    1703              :     // End routines for Equivalent One-Diode model as implemented by Bradley
    1704              :     //************************************************************************
    1705              : 
    1706              :     // Begin supporting routines for Sandia PV model
    1707              :     // -------------------------------------------------------------------------------
    1708              : 
    1709            0 :     Real64 SandiaModuleTemperature(Real64 const Ibc, // beam radiation on collector plane, W/m2
    1710              :                                    Real64 const Idc, // Diffuse radiation on collector plane, W/m2
    1711              :                                    Real64 const Ws,  // wind speed, m/s
    1712              :                                    Real64 const Ta,  // ambient temperature, degC
    1713              :                                    Real64 const fd,  // fraction of Idc used (empirical constant)
    1714              :                                    Real64 const a,   // empirical constant
    1715              :                                    Real64 const b    // empirical constant
    1716              :     )
    1717              :     {
    1718              :         // FUNCTION INFORMATION:
    1719              :         //       AUTHOR         G. Barker
    1720              :         //       DATE WRITTEN   unknown
    1721              :         //       MODIFIED       na
    1722              :         //       RE-ENGINEERED  B.Griffith December 2003
    1723              : 
    1724              :         // PURPOSE OF THIS FUNCTION:
    1725              :         // Returns back-of-module temperature, deg C
    1726              : 
    1727              :         // METHODOLOGY EMPLOYED:
    1728              :         // apply sandia temperature model, This is module temp or back of
    1729              :         // of the panel.  A separate correction handles delta T for actual cell
    1730              : 
    1731              :         // REFERENCES:
    1732              :         // from G. Barker's TRNSYS implementation
    1733              :         // Equations (10)  in Davis, M.W., A.H. Fanney, B.P. Dougherty. Measured versus
    1734              :         //   predicted performance of building integrated photovoltaics,
    1735              :         //   Solar 2002, Sunrise on the Reliable Energy Economy,
    1736              :         //   June 15-19, 2002, Reno, NV.
    1737              : 
    1738              :         // Return value
    1739              :         Real64 SandiaModuleTemperature;
    1740              : 
    1741              :         Real64 E; // total irradiance working variable
    1742              : 
    1743            0 :         E = Ibc + fd * Idc;
    1744              : 
    1745            0 :         SandiaModuleTemperature = E * std::exp(a + b * Ws) + Ta;
    1746              : 
    1747            0 :         return SandiaModuleTemperature;
    1748              :     }
    1749              : 
    1750              :     // -------------------------------------------------------------------------------
    1751              :     // -------------------------------------------------------------------------------
    1752              : 
    1753            0 :     Real64 SandiaTcellFromTmodule(Real64 const Tm,  // module temperature (deg C)
    1754              :                                   Real64 const Ibc, // beam radiation on collector plane, W/m2
    1755              :                                   Real64 const Idc, // Diffuse radiation on collector plane, W/m2
    1756              :                                   Real64 const fd,  // fraction of Idc used (empirical constant)
    1757              :                                   Real64 const DT0  // (Tc-Tm) at E=1000 W/m2 (empirical constant known as delta T), deg C
    1758              :     )
    1759              :     {
    1760              :         // FUNCTION INFORMATION:
    1761              :         //       AUTHOR         G. Barker
    1762              :         //       DATE WRITTEN   unknown
    1763              :         //       MODIFIED       na
    1764              :         //       RE-ENGINEERED  B. Griffith Jan 2004 F77 -> f90
    1765              : 
    1766              :         // PURPOSE OF THIS FUNCTION:
    1767              :         // Returns cell temperature, deg C
    1768              : 
    1769              :         // METHODOLOGY EMPLOYED:
    1770              :         // This is for the Sandia model method of determining cell temperatures
    1771              :         // module temperature differs from solar cell temperature
    1772              :         // because panel temperatures are not uniform
    1773              : 
    1774              :         // REFERENCES:
    1775              :         // Equations (11) in Davis, M.W., A.H. Fanney, B.P. Dougherty. Measured versus
    1776              :         //   predicted performance of building integrated photovoltaics,
    1777              :         //   Solar 2002, Sunrise on the Reliable Energy Economy,
    1778              :         //   June 15-19, 2002, Reno, NV.
    1779              : 
    1780              :         // Return value
    1781              :         Real64 SandiaTcellFromTmodule;
    1782              : 
    1783              :         Real64 E; // total irradiance working variable
    1784              : 
    1785            0 :         E = Ibc + fd * Idc;
    1786              : 
    1787            0 :         SandiaTcellFromTmodule = Tm + (E / 1000.0) * DT0;
    1788              : 
    1789            0 :         return SandiaTcellFromTmodule;
    1790              :     }
    1791              : 
    1792              :     // -------------------------------------------------------------------------------
    1793              : 
    1794            0 :     Real64 SandiaCellTemperature(Real64 const Ibc, // beam radiation on collector plane W/m2
    1795              :                                  Real64 const Idc, // Diffuse radiation on collector plane W/m2
    1796              :                                  Real64 const Ws,  // wind speed, m/s
    1797              :                                  Real64 const Ta,  // ambient temperature, degC
    1798              :                                  Real64 const fd,  // fraction of Idc used (empirical constant)
    1799              :                                  Real64 const a,   // empirical constant
    1800              :                                  Real64 const b,   // empirical constant
    1801              :                                  Real64 const DT0  // (Tc-Tm) at E=1000 W/m2 (empirical constant known as dTc), deg C
    1802              :     )
    1803              :     {
    1804              :         // FUNCTION INFORMATION:
    1805              :         //       AUTHOR         G. Barker
    1806              :         //       DATE WRITTEN   unknown
    1807              :         //       MODIFIED
    1808              :         //       RE-ENGINEERED  B. Griffith, Jan 2004 F77-> f90
    1809              : 
    1810              :         // PURPOSE OF THIS FUNCTION:
    1811              :         //  Returns cell temperature, deg C
    1812              :         // METHODOLOGY EMPLOYED:
    1813              :         // is this even used?  duplicates separate functions above.
    1814              :         // combines function SandiaTcellFromTmodule with
    1815              :         //  SandiaModuleTemperature
    1816              : 
    1817              :         // REFERENCES:
    1818              :         // Equations (10) and (11) in Davis, M.W., A.H. Fanney, B.P. Dougherty. Measured versus
    1819              :         //   predicted performance of building integrated photovoltaics,
    1820              :         //   Solar 2002, Sunrise on the Reliable Energy Economy,
    1821              :         //   June 15-19, 2002, Reno, NV.
    1822              : 
    1823              :         // Return value
    1824              :         Real64 SandiaCellTemperature;
    1825              : 
    1826              :         Real64 E; // irradiance working variable
    1827              :         Real64 Tm;
    1828              : 
    1829            0 :         E = Ibc + fd * Idc;
    1830              : 
    1831            0 :         Tm = E * std::exp(a + b * Ws) + Ta;
    1832              : 
    1833            0 :         SandiaCellTemperature = Tm + (E / 1000.0) * DT0; // E0=1000.0 W/m2
    1834              : 
    1835            0 :         return SandiaCellTemperature;
    1836              :     }
    1837              : 
    1838              :     // -------------------------------------------------------------------------------
    1839              : 
    1840            0 :     Real64 SandiaEffectiveIrradiance(Real64 const Tc,   // cell temperature (deg C)
    1841              :                                      Real64 const Isc,  // short-circuit current under operating conditions (A)
    1842              :                                      Real64 const Isc0, // reference Isc at Tc=25 C, Ic=1000 W/m2 (A)
    1843              :                                      Real64 const aIsc  // Isc temperature coefficient (degC^-1)
    1844              :     )
    1845              :     {
    1846              :         // FUNCTION INFORMATION:
    1847              :         //       AUTHOR         G. Barker
    1848              :         //       DATE WRITTEN   <unknown>
    1849              :         //       MODIFIED       na
    1850              :         //       RE-ENGINEERED  B. Griffith Jan 2004, F77 to f90
    1851              : 
    1852              :         // PURPOSE OF THIS FUNCTION:
    1853              :         // Returns "effective irradiance", used in calculation of Imp, Voc, Ix, Ixx
    1854              : 
    1855              :         // Return value
    1856              :         Real64 SandiaEffectiveIrradiance;
    1857              : 
    1858            0 :         SandiaEffectiveIrradiance = Isc / (1.0 + aIsc * (Tc - 25.0)) / Isc0;
    1859              : 
    1860            0 :         return SandiaEffectiveIrradiance;
    1861              :     }
    1862              : 
    1863              :     // -------------------------------------------------------------------------------
    1864              : 
    1865            2 :     Real64 AbsoluteAirMass(Real64 const SolZen,  // solar zenith angle (deg)
    1866              :                            Real64 const Altitude // site altitude (m)
    1867              :     )
    1868              :     {
    1869              :         // FUNCTION INFORMATION:
    1870              :         //       AUTHOR         G. Barker
    1871              :         //       DATE WRITTEN   <unknown>
    1872              :         //       MODIFIED       na
    1873              :         //       RE-ENGINEERED  B. Griffith Jan 2004 F77 -> f90
    1874              : 
    1875              :         // PURPOSE OF THIS FUNCTION:
    1876              :         // Returns absolute air mass
    1877              : 
    1878              :         // Return value
    1879              :         Real64 AbsoluteAirMass;
    1880              : 
    1881            2 :         if (SolZen < 89.9) {
    1882            1 :             Real64 const AM(1.0 / (std::cos(SolZen * Constant::DegToRad) + 0.5057 * std::pow(96.08 - SolZen, -1.634)));
    1883            1 :             AbsoluteAirMass = std::exp(-0.0001184 * Altitude) * AM;
    1884              :         } else {
    1885            1 :             Real64 constexpr AM(36.32); // evaluated above at SolZen = 89.9 issue #5528
    1886            1 :             AbsoluteAirMass = std::exp(-0.0001184 * Altitude) * AM;
    1887              :         }
    1888              : 
    1889            2 :         return AbsoluteAirMass;
    1890              :     }
    1891              : 
    1892              :     // -------------------------------------------------------------------------------
    1893              : 
    1894            0 :     Real64 SandiaF1(Real64 const AMa, // absolute air mass
    1895              :                     Real64 const a0,  // empirical constant, module-specific
    1896              :                     Real64 const a1,  // empirical constant, module-specific
    1897              :                     Real64 const a2,  // empirical constant, module-specific
    1898              :                     Real64 const a3,  // empirical constant, module-specific
    1899              :                     Real64 const a4   // empirical constant, module-specific
    1900              :     )
    1901              :     {
    1902              :         // FUNCTION INFORMATION:
    1903              :         //       AUTHOR         G. Barker
    1904              :         //       DATE WRITTEN   <unknown>
    1905              :         //       MODIFIED       na
    1906              :         //       RE-ENGINEERED  B. Griffith F77-> f90
    1907              : 
    1908              :         // PURPOSE OF THIS FUNCTION:
    1909              :         // Returns the result of Sandia Air Mass function
    1910              :         //  "AMa-Function" for solar spectral influence
    1911              : 
    1912              :         // METHODOLOGY EMPLOYED:
    1913              :         // <description>
    1914              : 
    1915              :         // REFERENCES:
    1916              :         // Equation (8) in Davis, M.W., A.H. Fanney, B.P. Dougherty. Measured versus
    1917              :         //   predicted performance of building integrated photovoltaics,
    1918              :         //   Solar 2002, Sunrise on the Reliable Energy Economy,
    1919              :         //   June 15-19, 2002, Reno, NV.
    1920              : 
    1921              :         // Return value
    1922              :         Real64 SandiaF1;
    1923              : 
    1924            0 :         Real64 const F1(a0 + a1 * AMa + a2 * pow_2(AMa) + a3 * pow_3(AMa) + a4 * pow_4(AMa));
    1925              : 
    1926            0 :         if (F1 > 0.0) {
    1927            0 :             SandiaF1 = F1;
    1928              :         } else {
    1929            0 :             SandiaF1 = 0.0;
    1930              :         }
    1931              : 
    1932            0 :         return SandiaF1;
    1933              :     }
    1934              : 
    1935              :     // -------------------------------------------------------------------------------
    1936              : 
    1937            0 :     Real64 SandiaF2(Real64 const IncAng, // incidence angle (deg)
    1938              :                     Real64 const b0,     // empirical module-specific constants
    1939              :                     Real64 const b1,     // empirical module-specific constants
    1940              :                     Real64 const b2,     // empirical module-specific constants
    1941              :                     Real64 const b3,     // empirical module-specific constants
    1942              :                     Real64 const b4,     // empirical module-specific constants
    1943              :                     Real64 const b5      // empirical module-specific constants
    1944              :     )
    1945              :     {
    1946              :         // FUNCTION INFORMATION:
    1947              :         //       AUTHOR         G. Barker
    1948              :         //       DATE WRITTEN   <unknown>
    1949              :         //       MODIFIED       na
    1950              :         //       RE-ENGINEERED  B. Griffith Jan 2004 F77-> f90
    1951              : 
    1952              :         // PURPOSE OF THIS FUNCTION:
    1953              :         // C Returns Sandia F2 function
    1954              : 
    1955              :         // REFERENCES:
    1956              :         // Equation (9) in Davis, M.W., A.H. Fanney, B.P. Dougherty. Measured versus
    1957              :         //   predicted performance of building integrated photovoltaics,
    1958              :         //   Solar 2002, Sunrise on the Reliable Energy Economy,
    1959              :         //   June 15-19, 2002, Reno, NV.
    1960              : 
    1961              :         // Return value
    1962              :         Real64 SandiaF2;
    1963              : 
    1964              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1965              :         Real64 F2; // working variable for function result
    1966              : 
    1967            0 :         F2 = b0 + b1 * IncAng + b2 * pow_2(IncAng) + b3 * pow_3(IncAng) + b4 * pow_4(IncAng) + b5 * pow_5(IncAng);
    1968              : 
    1969            0 :         if (F2 > 0.0) {
    1970            0 :             SandiaF2 = F2;
    1971              :         } else {
    1972            0 :             SandiaF2 = 0.0;
    1973              :         }
    1974              : 
    1975            0 :         return SandiaF2;
    1976              :     }
    1977              : 
    1978              :     // -------------------------------------------------------------------------------
    1979              : 
    1980            0 :     Real64 SandiaImp(Real64 const Tc,   // cell temperature (degC)
    1981              :                      Real64 const Ee,   // effective irradiance (W/m2)
    1982              :                      Real64 const Imp0, // current at MPP at SRC (1000 W/m2, 25 C) (A)
    1983              :                      Real64 const aImp, // Imp temperature coefficient (degC^-1)
    1984              :                      Real64 const C0,   // empirical module-specific constants
    1985              :                      Real64 const C1    // empirical module-specific constants
    1986              :     )
    1987              :     {
    1988              :         // FUNCTION INFORMATION:
    1989              :         //       AUTHOR         G. Barker
    1990              :         //       DATE WRITTEN   <unknown>
    1991              :         //       MODIFIED       na
    1992              :         //       RE-ENGINEERED  B. Griffith F77 -> f90
    1993              : 
    1994              :         // PURPOSE OF THIS FUNCTION:
    1995              :         // Returns current at maximum power point (A)
    1996              : 
    1997              :         // REFERENCES:
    1998              :         // Equation (3) in Davis, M.W., A.H. Fanney, B.P. Dougherty. Measured versus
    1999              :         //   predicted performance of building integrated photovoltaics,
    2000              :         //   Solar 2002, Sunrise on the Reliable Energy Economy,
    2001              :         //   June 15-19, 2002, Reno, NV.
    2002              : 
    2003              :         // Return value
    2004              :         Real64 SandiaImp;
    2005              : 
    2006            0 :         SandiaImp = Imp0 * (C0 * Ee + C1 * pow_2(Ee)) * (1.0 + aImp * (Tc - 25));
    2007              :         // why hardwire T0 at 25.0?  can this change? seems okay, fewer args
    2008            0 :         return SandiaImp;
    2009              :     }
    2010              : 
    2011              :     // -------------------------------------------------------------------------------
    2012              : 
    2013            0 :     Real64 SandiaIsc(Real64 const Tc,   // cell temperature (deg C)
    2014              :                      Real64 const Isc0, // Isc at Tc=25 C, Ic=1000 W/m2 (A)
    2015              :                      Real64 const Ibc,  // beam radiation on collector plane (W/m2)
    2016              :                      Real64 const Idc,  // Diffuse radiation on collector plane (W/m2)
    2017              :                      Real64 const F1,   // Sandia F1 function for air mass effects
    2018              :                      Real64 const F2,   // Sandia F2 function of incidence angle
    2019              :                      Real64 const fd,   // module-specific empirical constant
    2020              :                      Real64 const aIsc  // Isc temperature coefficient (degC^-1)
    2021              :     )
    2022              :     {
    2023              :         // FUNCTION INFORMATION:
    2024              :         //       AUTHOR         G. Barker
    2025              :         //       DATE WRITTEN   <date_written>
    2026              :         //       MODIFIED       na
    2027              :         //       RE-ENGINEERED  B. Griffith Jan 2004 F77 -> f90
    2028              : 
    2029              :         // PURPOSE OF THIS FUNCTION:
    2030              :         // Returns Short-Circuit Current
    2031              : 
    2032              :         // REFERENCES:
    2033              :         // Equation (1) in Davis, M.W., A.H. Fanney, B.P. Dougherty. Measured versus
    2034              :         //   predicted performance of building integrated photovoltaics,
    2035              :         //   Solar 2002, Sunrise on the Reliable Energy Economy,
    2036              :         //   June 15-19, 2002, Reno, NV.
    2037              : 
    2038              :         // Return value
    2039              :         Real64 SandiaIsc;
    2040              : 
    2041              :         // SandiaIsc=Isc0*((Ibc*F1*F2+fd*Idc)/1000.0)*(1.0+aIsc*(Tc-25.0))
    2042              :         // Barkers original (above) changed to match publish eq. (1) in reference
    2043            0 :         SandiaIsc = Isc0 * F1 * ((Ibc * F2 + fd * Idc) / 1000.0) * (1.0 + aIsc * (Tc - 25.0));
    2044              : 
    2045              :         // why hardwire E0 at 1000.0 ?, can this change? seems okay
    2046              : 
    2047            0 :         return SandiaIsc;
    2048              :     }
    2049              : 
    2050              :     // -------------------------------------------------------------------------------
    2051              : 
    2052            0 :     Real64 SandiaIx(Real64 const Tc,   // cell temperature (deg C)
    2053              :                     Real64 const Ee,   // effective irradiance
    2054              :                     Real64 const Ix0,  // Ix at SRC (1000 W/m2, 25 C) (A)
    2055              :                     Real64 const aIsc, // Isc temp coefficient (/C)
    2056              :                     Real64 const aImp, // Imp temp coefficient (/C)
    2057              :                     Real64 const C4,   // empirical module-specific constants
    2058              :                     Real64 const C5    // empirical module-specific constants
    2059              :     )
    2060              :     {
    2061              :         // FUNCTION INFORMATION:
    2062              :         //       AUTHOR         G. Barker
    2063              :         //       DATE WRITTEN   <unknown>
    2064              :         //       MODIFIED       na
    2065              :         //       RE-ENGINEERED  B. Griffith, Jan 2004 F77 -> f90
    2066              : 
    2067              :         // PURPOSE OF THIS FUNCTION:
    2068              :         // Returns current "Ix" at V=0.5*Voc (A)
    2069              : 
    2070              :         // REFERENCES:
    2071              :         // Equation 9 in King et al. nov 20003
    2072              : 
    2073              :         // Return value
    2074              :         Real64 SandiaIx;
    2075              : 
    2076            0 :         SandiaIx = Ix0 * (C4 * Ee + C5 * pow_2(Ee)) * (1.0 + ((aIsc + aImp) / 2.0 * (Tc - 25.0)));
    2077              : 
    2078            0 :         return SandiaIx;
    2079              :     }
    2080              : 
    2081              :     // -------------------------------------------------------------------------------
    2082              : 
    2083            0 :     Real64 SandiaIxx(Real64 const Tc,   // cell temperature (deg C)
    2084              :                      Real64 const Ee,   // effective irradiance (W/m2 ?)
    2085              :                      Real64 const Ixx0, // Ixx at SRC (1000 W/m2, 25 C) (A)
    2086              :                      Real64 const aImp, // Imp temp coefficient (/C)
    2087              :                      Real64 const C6,   // empirical module-specific constants
    2088              :                      Real64 const C7    // empirical module-specific constants
    2089              :     )
    2090              :     {
    2091              :         // FUNCTION INFORMATION:
    2092              :         //       AUTHOR         G. Barker
    2093              :         //       DATE WRITTEN   <unknown>
    2094              :         //       MODIFIED       na
    2095              :         //       RE-ENGINEERED  B. Griffith Jan2004 F77 to f90
    2096              : 
    2097              :         // PURPOSE OF THIS FUNCTION:
    2098              :         // Returns current "Ix" at V=0.5*(Voc+Vmp) (A)
    2099              : 
    2100              :         // REFERENCES:
    2101              :         // Equation 10 in King et al nov. 2003
    2102              : 
    2103              :         // Return value
    2104              :         Real64 SandiaIxx;
    2105              : 
    2106            0 :         SandiaIxx = Ixx0 * (C6 * Ee + C7 * pow_2(Ee)) * (1.0 + aImp * (Tc - 25.0));
    2107              : 
    2108            0 :         return SandiaIxx;
    2109              :     }
    2110              : 
    2111              :     // -------------------------------------------------------------------------------
    2112              : 
    2113            0 :     Real64 SandiaVmp(Real64 const Tc,          // cell temperature (deg C)
    2114              :                      Real64 const Ee,          // effective irradiance
    2115              :                      Real64 const Vmp0,        // Vmp at SRC (1000 W/m2, 25 C) (V)
    2116              :                      Real64 const NcellSer,    // # cells in series
    2117              :                      Real64 const DiodeFactor, // module-specIFic empirical constant
    2118              :                      Real64 const BVmp0,       // Vmp temperature coefficient (V/C)
    2119              :                      Real64 const mBVmp,       // change in BVmp with irradiance
    2120              :                      Real64 const C2,          // empirical module-specific constants
    2121              :                      Real64 const C3           // empirical module-specific constants
    2122              :     )
    2123              :     {
    2124              :         // FUNCTION INFORMATION:
    2125              :         //       AUTHOR         G. Barker
    2126              :         //       DATE WRITTEN   <unknown>
    2127              :         //       MODIFIED       na
    2128              :         //       RE-ENGINEERED  B. Griffith, Jan 2004, F77 -> f90
    2129              : 
    2130              :         // PURPOSE OF THIS FUNCTION:
    2131              :         // Returns Voltage at Max. Power Point (V)
    2132              : 
    2133              :         // METHODOLOGY EMPLOYED:
    2134              :         // <description>
    2135              : 
    2136              :         // REFERENCES:
    2137              :         // Equation 4 in King et al Nov. 2003
    2138              : 
    2139              :         // Return value
    2140              :         Real64 SandiaVmp;
    2141              : 
    2142              :         Real64 dTc;
    2143              :         Real64 BVmpEe;
    2144              : 
    2145            0 :         if (Ee > 0.0) {
    2146              :             // following is equation 8 in King et al. nov. 2003
    2147            0 :             dTc = DiodeFactor * ((1.38066e-23 * (Tc + Constant::Kelvin)) / 1.60218e-19);
    2148              : 
    2149            0 :             BVmpEe = BVmp0 + mBVmp * (1.0 - Ee);
    2150              : 
    2151            0 :             SandiaVmp = Vmp0 + C2 * NcellSer * dTc * std::log(Ee) + C3 * NcellSer * pow_2(dTc * std::log(Ee)) + BVmpEe * (Tc - 25.0);
    2152              :         } else {
    2153            0 :             SandiaVmp = 0.0;
    2154              :         }
    2155              : 
    2156            0 :         return SandiaVmp;
    2157              :     }
    2158              : 
    2159              :     // -------------------------------------------------------------------------------
    2160              : 
    2161            0 :     Real64 SandiaVoc(Real64 const Tc,          // cell temperature (deg C)
    2162              :                      Real64 const Ee,          // effective irradiance
    2163              :                      Real64 const Voc0,        // Voc at SRC (1000 W/m2, 25 C) (V)
    2164              :                      Real64 const NcellSer,    // # cells in series
    2165              :                      Real64 const DiodeFactor, // module-specIFic empirical constant
    2166              :                      Real64 const BVoc0,       // Voc temperature coefficient (V/C)
    2167              :                      Real64 const mBVoc        // change in BVoc with irradiance
    2168              :     )
    2169              :     {
    2170              :         // FUNCTION INFORMATION:
    2171              :         //       AUTHOR         G Barker
    2172              :         //       DATE WRITTEN   <unknown>
    2173              :         //       MODIFIED       na
    2174              :         //       RE-ENGINEERED  B Griffith Jan 2004 F77 -> f90
    2175              : 
    2176              :         // PURPOSE OF THIS FUNCTION:
    2177              :         // Returns Open-Circuit Voltage (V)
    2178              : 
    2179              :         // Return value
    2180              :         Real64 SandiaVoc;
    2181              : 
    2182              :         Real64 dTc;    // working variable
    2183              :         Real64 BVocEe; // working variable
    2184              : 
    2185            0 :         if (Ee > 0.0) {
    2186            0 :             dTc = DiodeFactor * ((1.38066e-23 * (Tc + Constant::Kelvin)) / 1.60218e-19);
    2187            0 :             BVocEe = BVoc0 + mBVoc * (1.0 - Ee);
    2188              : 
    2189            0 :             SandiaVoc = Voc0 + NcellSer * dTc * std::log(Ee) + BVocEe * (Tc - 25.0);
    2190              :         } else {
    2191            0 :             SandiaVoc = 0.0;
    2192              :         }
    2193              : 
    2194            0 :         return SandiaVoc;
    2195              :     }
    2196              : 
    2197            0 :     void SetVentedModuleQdotSource(EnergyPlusData &state,
    2198              :                                    int const VentModNum,
    2199              :                                    Real64 const QSource // source term in Watts
    2200              :     )
    2201              :     {
    2202              : 
    2203              :         // SUBROUTINE INFORMATION:
    2204              :         //       AUTHOR         B. Griffith
    2205              :         //       DATE WRITTEN   January 2004
    2206              :         //       MODIFIED       na
    2207              :         //       RE-ENGINEERED  na
    2208              : 
    2209              :         // PURPOSE OF THIS SUBROUTINE:
    2210              :         // object oriented "Set" routine for updating sink term without exposing variables
    2211              : 
    2212              :         // METHODOLOGY EMPLOYED:
    2213              :         // update derived type with new data , turn power into W/m2
    2214              : 
    2215              :         // Using/Aliasing
    2216              :         using namespace DataSurfaces;
    2217              : 
    2218            0 :         state.dataHeatBal->ExtVentedCavity(VentModNum).QdotSource = QSource / state.dataHeatBal->ExtVentedCavity(VentModNum).ProjArea;
    2219            0 :     }
    2220              : 
    2221            0 :     void GetExtVentedCavityIndex(EnergyPlusData &state, int const SurfacePtr, int &VentCavIndex)
    2222              :     {
    2223              : 
    2224              :         // SUBROUTINE INFORMATION:
    2225              :         //       AUTHOR         B. Griffith
    2226              :         //       DATE WRITTEN   January 2004
    2227              :         //       MODIFIED       na
    2228              :         //       RE-ENGINEERED  na
    2229              : 
    2230              :         // PURPOSE OF THIS SUBROUTINE:
    2231              :         // object oriented "Get" routine for establishing correct integer index from outside this module
    2232              : 
    2233              :         // METHODOLOGY EMPLOYED:
    2234              :         // mine Surface derived type for correct index/number of surface
    2235              :         // mine  ExtVentedCavity derived type that has the surface.
    2236              : 
    2237              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2238              :         int CavNum;   // temporary
    2239              :         int ThisSurf; // temporary
    2240              :         int thisCav;
    2241              :         bool Found;
    2242              : 
    2243            0 :         if (SurfacePtr == 0) {
    2244              :             // should be trapped already
    2245            0 :             ShowFatalError(state, "Invalid surface passed to GetExtVentedCavityIndex");
    2246              :         }
    2247              : 
    2248            0 :         CavNum = 0;
    2249            0 :         Found = false;
    2250            0 :         for (thisCav = 1; thisCav <= state.dataSurface->TotExtVentCav; ++thisCav) {
    2251            0 :             for (ThisSurf = 1; ThisSurf <= state.dataHeatBal->ExtVentedCavity(thisCav).NumSurfs; ++ThisSurf) {
    2252            0 :                 if (SurfacePtr == state.dataHeatBal->ExtVentedCavity(thisCav).SurfPtrs(ThisSurf)) {
    2253            0 :                     Found = true;
    2254            0 :                     CavNum = thisCav;
    2255              :                 }
    2256              :             }
    2257              :         }
    2258              : 
    2259            0 :         if (!Found) {
    2260            0 :             ShowFatalError(state,
    2261            0 :                            format("Did not find surface in Exterior Vented Cavity description in GetExtVentedCavityIndex, Surface name = {}",
    2262            0 :                                   state.dataSurface->Surface(SurfacePtr).Name));
    2263              :         } else {
    2264              : 
    2265            0 :             VentCavIndex = CavNum;
    2266              :         }
    2267            0 :     }
    2268              : 
    2269            0 :     void GetExtVentedCavityTsColl(EnergyPlusData &state, int const VentModNum, Real64 &TsColl)
    2270              :     {
    2271              : 
    2272              :         // SUBROUTINE INFORMATION:
    2273              :         //       AUTHOR         <author>
    2274              :         //       DATE WRITTEN   <date_written>
    2275              :         //       MODIFIED       na
    2276              :         //       RE-ENGINEERED  na
    2277              : 
    2278              :         // PURPOSE OF THIS SUBROUTINE:
    2279              :         // object oriented "Get" routine for collector surface temperature
    2280              : 
    2281              :         // METHODOLOGY EMPLOYED:
    2282              :         // access derived type
    2283              : 
    2284              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2285            0 :         TsColl = state.dataHeatBal->ExtVentedCavity(VentModNum).Tbaffle;
    2286            0 :     }
    2287              : 
    2288              :     // -------------------------------------------------------------------------------
    2289              : 
    2290              :     //     EnergyPlus V1.2 and beyond include models for photovoltaic calculations called
    2291              :     //     Generator:Photovoltaic:Simple and Generator:PV:Sandia implemented by the Center for
    2292              :     //     Buildings and Thermal Systems, National Renewable Energy Laboratory, 1617 Cole Blvd
    2293              :     //     MS 2722, Golden, CO, 80401
    2294              : 
    2295              :     //     EnergyPlus v1.1.1 and beyond includes model for Photovoltaic calculations, now
    2296              :     //     referred to as the Generator:PV:Equivalent One-Diode model developed by Thermal Energy
    2297              :     //     System Specialists, 2916 Marketplace Drive, Suite 104, Madison, WI 53719;
    2298              :     //     Tel: (608) 274-2577
    2299              : 
    2300              : } // namespace Photovoltaics
    2301              : 
    2302              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1