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