LCOV - code coverage report
Current view: top level - EnergyPlus - Photovoltaics.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 79.2 % 854 676
Test Date: 2025-06-02 07:23:51 Functions: 96.8 % 31 30

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

Generated by: LCOV version 2.0-1