LCOV - code coverage report
Current view: top level - EnergyPlus - Photovoltaics.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 685 894 76.6 %
Date: 2024-08-24 18:31:18 Functions: 30 31 96.8 %

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

Generated by: LCOV version 1.14