LCOV - code coverage report
Current view: top level - EnergyPlus - Photovoltaics.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 757 957 79.1 %
Date: 2023-01-17 19:17:23 Functions: 32 33 97.0 %

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

Generated by: LCOV version 1.13