bifacial-radiance 0.5.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bifacial_radiance/HPCScripts/BasicSimulations/addNewModule.py +15 -0
- bifacial_radiance/HPCScripts/BasicSimulations/dask_on_node.sh +11 -0
- bifacial_radiance/HPCScripts/BasicSimulations/run_sbatch.sbatch +51 -0
- bifacial_radiance/HPCScripts/BasicSimulations/simulate_fixedtilt_gencumsky.py +110 -0
- bifacial_radiance/HPCScripts/BasicSimulations/simulate_fixedtilt_gendaylit.py +102 -0
- bifacial_radiance/HPCScripts/BasicSimulations/simulate_tracking_gendaylit.py +126 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/PuertoRico.py +168 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/PuertoRico_2.py +166 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/PuertoRico_Original.py +195 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/basic_module_sampling.py +154 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_B.py +162 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_Cases.py +122 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_CasesMonth.py +142 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_PRNew.py +91 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_PRNewP2.py +95 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_TreeResults.py +108 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_basic_module_sampling.py +103 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/simulate_JackHourly.py +160 -0
- bifacial_radiance/HPCScripts/Other Examples (unorganized)/simulate_improvedArray_Oct2127.py +623 -0
- bifacial_radiance/TEMP/.gitignore +4 -0
- bifacial_radiance/__init__.py +24 -0
- bifacial_radiance/data/CEC Modules.csv +16860 -0
- bifacial_radiance/data/default.ini +65 -0
- bifacial_radiance/data/falsecolor.exe +0 -0
- bifacial_radiance/data/gencumsky/License.txt +54 -0
- bifacial_radiance/data/gencumsky/Makefile +17 -0
- bifacial_radiance/data/gencumsky/README.txt +9 -0
- bifacial_radiance/data/gencumsky/Solar Irradiation Modelling.doc +0 -0
- bifacial_radiance/data/gencumsky/Sun.cpp +118 -0
- bifacial_radiance/data/gencumsky/Sun.h +45 -0
- bifacial_radiance/data/gencumsky/average_val.awk +3 -0
- bifacial_radiance/data/gencumsky/cPerezSkyModel.cpp +238 -0
- bifacial_radiance/data/gencumsky/cPerezSkyModel.h +57 -0
- bifacial_radiance/data/gencumsky/cSkyVault.cpp +536 -0
- bifacial_radiance/data/gencumsky/cSkyVault.h +86 -0
- bifacial_radiance/data/gencumsky/climateFile.cpp +312 -0
- bifacial_radiance/data/gencumsky/climateFile.h +37 -0
- bifacial_radiance/data/gencumsky/cumulative.cal +177 -0
- bifacial_radiance/data/gencumsky/cumulative.rad +14 -0
- bifacial_radiance/data/gencumsky/cumulativesky_rotated.rad +2 -0
- bifacial_radiance/data/gencumsky/gencumulativesky +0 -0
- bifacial_radiance/data/gencumsky/gencumulativesky.cpp +269 -0
- bifacial_radiance/data/gencumsky/make_gencumskyexe.py +107 -0
- bifacial_radiance/data/gencumsky/paths.h +62 -0
- bifacial_radiance/data/gencumulativesky +0 -0
- bifacial_radiance/data/gencumulativesky.exe +0 -0
- bifacial_radiance/data/ground.rad +83 -0
- bifacial_radiance/data/module.json +103 -0
- bifacial_radiance/gui.py +1696 -0
- bifacial_radiance/images/fig1_fixed_small.gif +0 -0
- bifacial_radiance/images/fig2_tracked_small.gif +0 -0
- bifacial_radiance/load.py +1156 -0
- bifacial_radiance/main.py +5673 -0
- bifacial_radiance/mismatch.py +461 -0
- bifacial_radiance/modelchain.py +299 -0
- bifacial_radiance/module.py +1427 -0
- bifacial_radiance/performance.py +466 -0
- bifacial_radiance/spectral_utils.py +555 -0
- bifacial_radiance-0.5.1.dist-info/METADATA +129 -0
- bifacial_radiance-0.5.1.dist-info/RECORD +63 -0
- bifacial_radiance-0.5.1.dist-info/WHEEL +6 -0
- bifacial_radiance-0.5.1.dist-info/licenses/LICENSE +30 -0
- bifacial_radiance-0.5.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1156 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Module providing routines for loading and cleaning results from bifacial_radiance.
|
|
4
|
+
Bifacial_radiance results are .csv format files stored in a results folder
|
|
5
|
+
autogenerated in the location where the RadianceObj was set to build its scene.
|
|
6
|
+
If no path was provided for the RadianceObj to build its scene, it defaults to
|
|
7
|
+
TEMP folder in bifacial_radiance \\ bifacial_radiance
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
from deprecated import deprecated
|
|
11
|
+
|
|
12
|
+
''' DEPRECATED - doesn't work with python3
|
|
13
|
+
def load_inputvariablesfile(inputfile):
|
|
14
|
+
"""
|
|
15
|
+
Loads inputfile which must be in the bifacial_radiance directory,
|
|
16
|
+
and must be a ``.py`` file with all the variables, and organizes the variables
|
|
17
|
+
into dictionaries that it returns
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
inputfile : str
|
|
22
|
+
String of a ``.py`` file in the bifacial_radiance directory.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
simulationParamsDict : Dictionary
|
|
27
|
+
Dictionary containing the parameters for performing the simulation,
|
|
28
|
+
including simulation names, and types of sky, fixed or tracked systems:
|
|
29
|
+
======================== ======= =============================
|
|
30
|
+
variable type Description
|
|
31
|
+
======================== ======= =============================
|
|
32
|
+
testfolder str Path to testfolder
|
|
33
|
+
weatherfile str File (with path) to weatherfile
|
|
34
|
+
getEPW bool
|
|
35
|
+
simulationname str Name for simulation
|
|
36
|
+
moduletype str Module name as is / or will be defined in JSON
|
|
37
|
+
rewritemodule bool If moduletype exists in JSON, True will rewrite with new parameters
|
|
38
|
+
cellLevelmodule bool
|
|
39
|
+
axisofrotationtorquetube bool
|
|
40
|
+
torqueTube bool
|
|
41
|
+
hpc bool
|
|
42
|
+
tracking bool
|
|
43
|
+
cumulativesky bool
|
|
44
|
+
daydateSimulation bool
|
|
45
|
+
selectTimes bool
|
|
46
|
+
saveImage bool Activates saving of module and scene .HDR images, default True
|
|
47
|
+
======================== ======= =============================
|
|
48
|
+
sceneParamsDict : Dictionary
|
|
49
|
+
gcrorpitch, gcr, pitch, albedo, nMods, nRows,
|
|
50
|
+
hub_height, clearance_height, azimuth, hub_height, axis_Azimuth
|
|
51
|
+
timeControlParamsDict : Dictionary
|
|
52
|
+
hourstart, hourend, daystart, dayend, monthstart, monthend,
|
|
53
|
+
timestampstart, timestampend,
|
|
54
|
+
moduleParamsDict : Dictionary
|
|
55
|
+
numpanels, x, y, bifi, xgap, ygap, zgap
|
|
56
|
+
cellLevelModuleParamsDict : Dictionary
|
|
57
|
+
numcellsx, numcellsy, xcell, ycell, xcellgap, ycellgap
|
|
58
|
+
trackingParamsDict : Dictionary
|
|
59
|
+
backtrack, limit_angle,angle_delta
|
|
60
|
+
torquetubeParamsDict : Dictionary
|
|
61
|
+
diameter, tubetype, torqueTubeMaterial
|
|
62
|
+
analysisParamsDict : Dictionary
|
|
63
|
+
sensorsy, modWanted, rowWanted
|
|
64
|
+
CECModParamsDict : Dictionary
|
|
65
|
+
lpha_sc, a_ref, I_L_ref, I_o_ref, R_sh_ref, R_s, Adjust
|
|
66
|
+
"""
|
|
67
|
+
import inputfile as ibf
|
|
68
|
+
|
|
69
|
+
simulationParamsDict = {'testfolder':ibf.testfolder,
|
|
70
|
+
'epwfile':ibf.epwfile,
|
|
71
|
+
'simulationname':ibf.simulationname,
|
|
72
|
+
'moduletype':ibf.moduletype,
|
|
73
|
+
'rewriteModule':ibf.rewriteModule,
|
|
74
|
+
'cellLevelModule':ibf.cellLevelModule,
|
|
75
|
+
'axisofrotationTorqueTube':ibf.axisofrotationTorqueTube,
|
|
76
|
+
'torqueTube':ibf.torqueTube}
|
|
77
|
+
|
|
78
|
+
simulationControlDict = {'fixedortracked':ibf.fixedortracked,
|
|
79
|
+
'cumulativeSky': ibf.cumulativeSky,
|
|
80
|
+
'selectTimes':ibf.selectTimes
|
|
81
|
+
'hpc': ibf.hpc,
|
|
82
|
+
'daydateSimulation': ibf.dayDateSimulation}
|
|
83
|
+
#'singleKeySimulation': ibf.singleKeySimulation,
|
|
84
|
+
#'singleKeyRangeSimulation': ibf.singleKeyRangeSimulation}
|
|
85
|
+
|
|
86
|
+
timeControlParamsDict = {'timestampstart': ibf.timestampstart,
|
|
87
|
+
'timestampend': ibf.timestampend,
|
|
88
|
+
'startdate': ibf.startdate,
|
|
89
|
+
'enddate': ibf.enddate,
|
|
90
|
+
'singlekeystart': ibf.singlekeystart,
|
|
91
|
+
'singlekeyend': ibf.singlekeyend,
|
|
92
|
+
'day_date':ibf.daydate}
|
|
93
|
+
|
|
94
|
+
moduleParamsDict = {'numpanels': ibf.numpanels, 'x': ibf.x, 'y': ibf.y,
|
|
95
|
+
'bifi': ibf.bifi, 'xgap': ibf.xgap,
|
|
96
|
+
'ygap': ibf.ygap, 'zgap': ibf.zgap}
|
|
97
|
+
|
|
98
|
+
sceneParamsDict = {'gcr': ibf.gcr, 'pitch': ibf.pitch, 'albedo': ibf.albedo,
|
|
99
|
+
'nMods':ibf.nMods, 'nRows': ibf.nRows,
|
|
100
|
+
'azimuth': ibf.azimuth_ang, 'tilt': ibf.tilt,
|
|
101
|
+
'clearance_height': ibf.clearance_height, 'hub_height': ibf.hub_height,
|
|
102
|
+
'axis_azimuth': ibf.axis_azimuth}
|
|
103
|
+
|
|
104
|
+
trackingParamsDict = {'backtrack': ibf.backtrack, 'limit_angle': ibf.limit_angle,
|
|
105
|
+
'angle_delta': ibf.angle_delta}
|
|
106
|
+
|
|
107
|
+
# #TODO: Figure out how to return this optional return items.
|
|
108
|
+
#cdeline: this isn't returned by the function ??
|
|
109
|
+
torquetubeParamsDict = {'diameter': ibf.diameter, 'tubetype': ibf.tubetype,
|
|
110
|
+
'torqueTubeMaterial': ibf.torqueTubeMaterial}
|
|
111
|
+
|
|
112
|
+
analysisParamsDict = {'sensorsy': ibf.sensorsy, 'modWanted': ibf.modWanted,
|
|
113
|
+
'rowWanted': ibf.rowWanted}
|
|
114
|
+
|
|
115
|
+
cellLevelModuleParamsDict = {'numcellsx': ibf.numcellsx,
|
|
116
|
+
'numcellsy': ibf.numcellsy,
|
|
117
|
+
'xcell': ibf.xcell, 'ycell': ibf.ycell,
|
|
118
|
+
'xcellgap': ibf.xcellgap, 'ycellgap': ibf.ycellgap}
|
|
119
|
+
CECModParamsDict = {'alpha_sc': ibf.alpha_sc,
|
|
120
|
+
'a_ref': ibf.a_ref,
|
|
121
|
+
'I_L_ref': ibf.I_L_ref,
|
|
122
|
+
'I_o_ref': ibf.I_o_ref,
|
|
123
|
+
'R_sh_ref': ibf.R_sh_ref,
|
|
124
|
+
'R_s': ibf.R_s,
|
|
125
|
+
'Adjust': ibf.Adjust}
|
|
126
|
+
|
|
127
|
+
return(simulationParamsDict, simulationControlDict, timeControlParamsDict,
|
|
128
|
+
moduleParamsDict, cellLevelModuleParamsDict, sceneParamsDict,
|
|
129
|
+
trackingParamsDict, analysisParamsDict, CECModParamsDict)
|
|
130
|
+
|
|
131
|
+
'''
|
|
132
|
+
|
|
133
|
+
def loadRadianceObj(savefile=None):
|
|
134
|
+
"""
|
|
135
|
+
Load the pickled radiance object for further use
|
|
136
|
+
Usage (once you're in the correct local directory)::
|
|
137
|
+
|
|
138
|
+
demo = bifacial_radiance.loadRadianceObj(savefile)
|
|
139
|
+
|
|
140
|
+
Parameters
|
|
141
|
+
----------
|
|
142
|
+
savefile : str
|
|
143
|
+
Optional savefile name. Otherwise default to `save.pickle`
|
|
144
|
+
|
|
145
|
+
"""
|
|
146
|
+
import pickle
|
|
147
|
+
|
|
148
|
+
if savefile is None:
|
|
149
|
+
savefile = 'save.pickle'
|
|
150
|
+
with open(savefile,'rb') as f:
|
|
151
|
+
loadObj= pickle.load(f)
|
|
152
|
+
|
|
153
|
+
print('Loaded file {}'.format(savefile))
|
|
154
|
+
return loadObj
|
|
155
|
+
|
|
156
|
+
def read1Result(selectfile):
|
|
157
|
+
"""
|
|
158
|
+
Loads in a bifacial_radiance results file ``.csv`` format,
|
|
159
|
+
and return a :py:class:`~pandas.DataFrame`
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
selectfile : str
|
|
164
|
+
File name (with path if not in working folder) that has been produced by
|
|
165
|
+
bifacial_radiance.
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
resultsDF : :py:class:`~pandas.DataFrame`
|
|
170
|
+
Dataframe with the bifacial_radiance .csv values read.
|
|
171
|
+
|
|
172
|
+
"""
|
|
173
|
+
import pandas as pd
|
|
174
|
+
|
|
175
|
+
#resultsDict = pd.read_csv(os.path.join('results',selectfile))
|
|
176
|
+
resultsDF = pd.read_csv(selectfile)
|
|
177
|
+
|
|
178
|
+
if 'Unnamed: 0' in resultsDF.columns:
|
|
179
|
+
resultsDF.index = resultsDF['Unnamed: 0'].values
|
|
180
|
+
resultsDF.drop(columns='Unnamed: 0', inplace=True)
|
|
181
|
+
|
|
182
|
+
#return(np.array(temp['Wm2Front']), np.array(temp['Wm2Back']))
|
|
183
|
+
return resultsDF
|
|
184
|
+
# End read1Result subroutine
|
|
185
|
+
|
|
186
|
+
def cleanResult(resultsDF, matchers=None):
|
|
187
|
+
"""
|
|
188
|
+
Replace irradiance values with NaN's when the scan intersects ground,
|
|
189
|
+
sky, or anything in `matchers`.
|
|
190
|
+
|
|
191
|
+
Matchers are words in the dataframe like 'sky' or 'tube'
|
|
192
|
+
in the front or back material description column that
|
|
193
|
+
get substituted by NaN in Wm2Front and Wm2Back
|
|
194
|
+
There are default matchers established in this routine but other matchers
|
|
195
|
+
can be passed.
|
|
196
|
+
Default matchers: 'sky', 'tube', 'pole', 'ground', '3267', '1540'.
|
|
197
|
+
Matchers 3267 and 1540 is to get rid of inner-sides of the module.
|
|
198
|
+
|
|
199
|
+
Parameters
|
|
200
|
+
----------
|
|
201
|
+
resultsDF : :py:class:`~pandas.DataFrame`
|
|
202
|
+
DataFrame of results from bifacial_radiance, for example read
|
|
203
|
+
from :py:class:`~bifacial_radiance.load.read1Result`
|
|
204
|
+
|
|
205
|
+
Returns
|
|
206
|
+
--------
|
|
207
|
+
resultsDF : :py:class:`~pandas.DataFrame`
|
|
208
|
+
Updated resultsDF
|
|
209
|
+
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
import numpy as np
|
|
213
|
+
|
|
214
|
+
if matchers is None:
|
|
215
|
+
matchers = ['sky','pole','tube','bar','ground', '3267', '1540']
|
|
216
|
+
if ('mattype' in resultsDF) & ('Wm2Front' in resultsDF) :
|
|
217
|
+
resultsDF.loc[resultsDF.mattype.str.contains('|'.join(matchers)),'Wm2Front'] = np.nan
|
|
218
|
+
if ('rearMat' in resultsDF) & ('Wm2Back' in resultsDF) :
|
|
219
|
+
resultsDF.loc[resultsDF.rearMat.str.contains('|'.join(matchers)),'Wm2Back'] = np.nan
|
|
220
|
+
|
|
221
|
+
return resultsDF
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def loadTrackerDict(trackerdict, fileprefix=None):
|
|
225
|
+
"""
|
|
226
|
+
Load a trackerdict by reading all files in the `\\results` directory.
|
|
227
|
+
fileprefix is used to select only certain matching files in `\\results`
|
|
228
|
+
|
|
229
|
+
It will then save the `Wm2Back`, `Wm2Front` and `backRatio` by reading in all valid files in the
|
|
230
|
+
`\\results` directory. Note: it will match any file ending in `_key.csv`
|
|
231
|
+
|
|
232
|
+
Parameters
|
|
233
|
+
----------
|
|
234
|
+
trackerdict :
|
|
235
|
+
You need to pass in a valid trackerdict with correct keys from
|
|
236
|
+
:py:class:`~bifacial_radiance.RadianceObj.set1axis`
|
|
237
|
+
fileprefix : str
|
|
238
|
+
Optional parameter to specify the initial part of the savefile prior
|
|
239
|
+
to '_key.csv'
|
|
240
|
+
|
|
241
|
+
Returns
|
|
242
|
+
-------
|
|
243
|
+
trackerdict : Dictionary
|
|
244
|
+
Dictionary with additional keys ``Wm2Back``, ``Wm2Front``, ``backRatio``
|
|
245
|
+
totaldict : Dictionary
|
|
246
|
+
totalized dictionary with ``Wm2Back``, ``Wm2Front``.
|
|
247
|
+
Also ``numfiles`` (number of csv files loaded) and
|
|
248
|
+
``finalkey`` (last index file in directory)
|
|
249
|
+
|
|
250
|
+
"""
|
|
251
|
+
# TODO: get this module working
|
|
252
|
+
import re, os
|
|
253
|
+
import numpy as np
|
|
254
|
+
|
|
255
|
+
print('Warning: loadTrackerDict has not been updated to the new v0.5.0' +\
|
|
256
|
+
' dictionary structure and is currently incomplete. Please' +\
|
|
257
|
+
' reach out at github.com/NREL/bifacial_radiance/issues if' +\
|
|
258
|
+
' this is functionality you need.\n')
|
|
259
|
+
|
|
260
|
+
# get list of filenames in \results\
|
|
261
|
+
filelist = sorted(os.listdir('results'))
|
|
262
|
+
|
|
263
|
+
print('{} files in the directory'.format(filelist.__len__()))
|
|
264
|
+
i = 0 # counter to track # files loaded.
|
|
265
|
+
|
|
266
|
+
for key in sorted(trackerdict):
|
|
267
|
+
if fileprefix is None:
|
|
268
|
+
r = re.compile(".*_" + re.escape(key) + ".csv")
|
|
269
|
+
else:
|
|
270
|
+
r = re.compile(fileprefix + re.escape(key) + ".csv")
|
|
271
|
+
try:
|
|
272
|
+
selectfile = list(filter(r.match,filelist))[0]
|
|
273
|
+
i += 1
|
|
274
|
+
except IndexError:
|
|
275
|
+
continue
|
|
276
|
+
resultsDF = read1Result(os.path.join('results',selectfile)) #return dataframe
|
|
277
|
+
resultsDF = cleanResult(resultsDF) # remove invalid materials
|
|
278
|
+
|
|
279
|
+
Wm2Front = np.array(resultsDF['Wm2Front'])
|
|
280
|
+
Wm2Back = np.array(resultsDF['Wm2Back'])
|
|
281
|
+
|
|
282
|
+
try:
|
|
283
|
+
Wm2FrontTotal += Wm2Front
|
|
284
|
+
Wm2BackTotal += Wm2Back
|
|
285
|
+
except NameError:
|
|
286
|
+
Wm2FrontTotal = Wm2Front
|
|
287
|
+
Wm2BackTotal = Wm2Back
|
|
288
|
+
trackerdict[key]['Wm2Front'] = list(Wm2Front)
|
|
289
|
+
trackerdict[key]['Wm2Back'] = list(Wm2Back)
|
|
290
|
+
trackerdict[key]['backRatio'] = list(Wm2Back / Wm2Front)
|
|
291
|
+
finalkey = key
|
|
292
|
+
# == TS: LoadTrackerDict failure 'Wm2FrontTotal' ==
|
|
293
|
+
totaldict = {'Wm2Front':Wm2FrontTotal, 'Wm2Back':Wm2BackTotal, 'numfiles':i, 'finalkey':finalkey}
|
|
294
|
+
|
|
295
|
+
print('Files loaded: {}; Wm2Front_avg: {:0.1f}; Wm2Rear_avg: {:0.1f}'.format(i, np.nanmean(Wm2FrontTotal), np.nanmean(Wm2BackTotal) ))
|
|
296
|
+
print('final key loaded: {}'.format(finalkey))
|
|
297
|
+
return(trackerdict, totaldict)
|
|
298
|
+
#end loadTrackerDict subroutine. set demo.Wm2Front = totaldict.Wm2Front. demo.Wm2Back = totaldict.Wm2Back
|
|
299
|
+
|
|
300
|
+
def getResults(trackerdict, cumulativesky=False):
|
|
301
|
+
"""
|
|
302
|
+
Iterate over trackerdict and return irradiance results
|
|
303
|
+
following analysis1axis runs
|
|
304
|
+
|
|
305
|
+
Parameters
|
|
306
|
+
----------
|
|
307
|
+
trackerdict : dict
|
|
308
|
+
trackerdict, after analysis1axis has been run
|
|
309
|
+
|
|
310
|
+
cumulativesky : Bool
|
|
311
|
+
determines whether trackerdict index is labeled 'timestamp' or 'angle'
|
|
312
|
+
|
|
313
|
+
Returns
|
|
314
|
+
-------
|
|
315
|
+
results : Pandas.DataFrame
|
|
316
|
+
dataframe containing irradiance scan results.
|
|
317
|
+
|
|
318
|
+
"""
|
|
319
|
+
import pandas as pd
|
|
320
|
+
from pandas import DataFrame as df
|
|
321
|
+
|
|
322
|
+
results = pd.DataFrame(None)
|
|
323
|
+
|
|
324
|
+
def _printRow(analysisobj, key):
|
|
325
|
+
if cumulativesky:
|
|
326
|
+
keyname = 'theta'
|
|
327
|
+
else:
|
|
328
|
+
keyname = 'timestamp'
|
|
329
|
+
return pd.concat([pd.DataFrame({keyname:key},index=[0]),
|
|
330
|
+
analysisobj.results], axis=1)
|
|
331
|
+
|
|
332
|
+
for key in trackerdict:
|
|
333
|
+
try:
|
|
334
|
+
extra_columns = ['surf_azm','surf_tilt','theta']
|
|
335
|
+
data_extra = df(dict([(col,trackerdict[key][col]) \
|
|
336
|
+
for col in extra_columns if col in trackerdict[key]]),
|
|
337
|
+
index=[0])
|
|
338
|
+
|
|
339
|
+
for analysis in trackerdict[key]['AnalysisObj']:
|
|
340
|
+
results = pd.concat([results,
|
|
341
|
+
pd.concat([_printRow(analysis, key),data_extra], axis=1)
|
|
342
|
+
], ignore_index=True)
|
|
343
|
+
except KeyError:
|
|
344
|
+
pass
|
|
345
|
+
|
|
346
|
+
return results.loc[:,~results.columns.duplicated()]
|
|
347
|
+
|
|
348
|
+
def _exportTrackerDict(trackerdict, savefile, cumulativesky=False, reindex=False, monthlyyearly=False):
|
|
349
|
+
"""
|
|
350
|
+
Save a TrackerDict output as a ``.csv`` file.
|
|
351
|
+
|
|
352
|
+
Parameters
|
|
353
|
+
----------
|
|
354
|
+
trackerdict : Dictionary
|
|
355
|
+
The tracker dictionary to save
|
|
356
|
+
savefile : str
|
|
357
|
+
Path to .csv save file location
|
|
358
|
+
reindex : bool
|
|
359
|
+
Boolean indicating if trackerdict should be resampled to include
|
|
360
|
+
all 8760 hours in the year (even those when the sun is not up and
|
|
361
|
+
irradiance results is empty). NOTE: this is incompatible with multiple
|
|
362
|
+
row / modules per trackerdict entry.
|
|
363
|
+
|
|
364
|
+
"""
|
|
365
|
+
from pandas import DataFrame as df
|
|
366
|
+
import pandas as pd
|
|
367
|
+
|
|
368
|
+
print("Exporting TrackerDict")
|
|
369
|
+
|
|
370
|
+
d0 = getResults(trackerdict, cumulativesky)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
d0.rename(columns={'Wind Speed':'wind_speed'}, inplace=True)
|
|
374
|
+
|
|
375
|
+
columnlist = ['timestamp', 'rowNum', 'modNum', 'sceneNum', 'name', 'Wm2Front', 'Wm2Back','DNI','DHI','GHI',
|
|
376
|
+
'temp_air', 'wind_speed','theta','surf_tilt','surf_azm', 'POA_eff','Gfront_mean',
|
|
377
|
+
'Grear_mean', 'Pout_raw', 'Mismatch', 'Pout', 'Pout_Gfront']
|
|
378
|
+
d = df.from_dict(d0).loc[:, d0.columns.isin(columnlist)]
|
|
379
|
+
d = d.reindex(columns=[k for k in columnlist])
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
# TODO: Continue work from here...
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
if reindex is True: # change to proper timestamp and interpolate to get 8760 output
|
|
387
|
+
|
|
388
|
+
d=d.set_index(pd.to_datetime(d['timestamp'], format='%Y-%m-%d_%H%M'))
|
|
389
|
+
try:
|
|
390
|
+
d=d.resample('H').asfreq()
|
|
391
|
+
except ValueError:
|
|
392
|
+
temp = d.groupby(d.index).mean(numeric_only=True)
|
|
393
|
+
d=temp.resample('H').asfreq()
|
|
394
|
+
#print('Warning: Unable to reindex - possibly duplicate entries in trackerdict')
|
|
395
|
+
|
|
396
|
+
# Add tabs:
|
|
397
|
+
d.to_csv(savefile)
|
|
398
|
+
|
|
399
|
+
if monthlyyearly:
|
|
400
|
+
|
|
401
|
+
D2join = pd.DataFrame()
|
|
402
|
+
D3join = pd.DataFrame()
|
|
403
|
+
D4join = pd.DataFrame()
|
|
404
|
+
for rownum in d['rowNum'].unique():
|
|
405
|
+
for modnum in d['modNum'].unique():
|
|
406
|
+
for sceneNum in d['sceneNum'].unique():#TODO: is sceneNum iteration required here?
|
|
407
|
+
mask = (d['rowNum']==rownum) & (d['modNum']==modnum) & (d['sceneNum']==sceneNum)
|
|
408
|
+
print(modnum)
|
|
409
|
+
# Gfront_mean.append(filledFront[mask].sum(axis=0).mean())
|
|
410
|
+
D2 = d[mask].copy()
|
|
411
|
+
D2['timestamp'] = pd.to_datetime(D2['timestamp'], format="%Y-%m-%d_%H%M")
|
|
412
|
+
D2 = D2.set_index('timestamp')
|
|
413
|
+
# D2 = D2.set_index(D2['timestamp'])
|
|
414
|
+
|
|
415
|
+
# Determine if data is sub-hourly
|
|
416
|
+
if len(D2) > 1:
|
|
417
|
+
if (D2.index[1]-D2.index[0]).total_seconds() / 60 < 60.0:
|
|
418
|
+
# Subhourly to hourly data averages, doesn't sum
|
|
419
|
+
# So we get average hourly irradiance as well as Wh on
|
|
420
|
+
# results of power.
|
|
421
|
+
D2b = D2.copy()
|
|
422
|
+
D2b = D2b.groupby(pd.PeriodIndex(D2b.index, freq="h")).mean(numeric_only=True).reset_index()
|
|
423
|
+
D2b['BGG'] = D2b['Grear_mean']*100/D2b['Gfront_mean']
|
|
424
|
+
D2b['BGE'] = (D2b['Pout']-D2b['Pout_Gfront'])*100/D2b['Pout']
|
|
425
|
+
D2b['Mismatch'] = (D2b['Pout_raw']-D2b['Pout'])*100/D2b['Pout_raw']
|
|
426
|
+
D2b['rowNum'] = rownum
|
|
427
|
+
D2b['modNum'] = modnum
|
|
428
|
+
D2b.drop(columns=['theta', 'surf_tilt', 'surf_azm'], inplace=True)
|
|
429
|
+
D2b=D2b.reset_index()
|
|
430
|
+
D2join = pd.concat([D2join, D2b], ignore_index=True, sort=False)
|
|
431
|
+
|
|
432
|
+
D3 = D2.groupby(pd.PeriodIndex(D2.index, freq="M")).sum(numeric_only=True).reset_index()
|
|
433
|
+
D3['BGG'] = D3['Grear_mean']*100/D3['Gfront_mean']
|
|
434
|
+
D3['BGE'] = (D3['Pout']-D3['Pout_Gfront'])*100/D3['Pout']
|
|
435
|
+
D3['Mismatch'] = (D3['Pout_raw']-D3['Pout'])*100/D3['Pout_raw']
|
|
436
|
+
D3['rowNum'] = rownum
|
|
437
|
+
D3['modNum'] = modnum
|
|
438
|
+
D3m = D2.groupby(pd.PeriodIndex(D2.index, freq="M")).mean(numeric_only=True).reset_index()
|
|
439
|
+
D3['temp_air'] = D3m['temp_air']
|
|
440
|
+
D3['wind_speed'] = D3m['wind_speed']
|
|
441
|
+
D3.drop(columns=['theta', 'surf_tilt', 'surf_azm'], inplace=True)
|
|
442
|
+
|
|
443
|
+
D4 = D2.groupby(pd.PeriodIndex(D2.index, freq="Y")).sum(numeric_only=True).reset_index()
|
|
444
|
+
D4['BGG'] = D4['Grear_mean']*100/D4['Gfront_mean']
|
|
445
|
+
D4['BGE'] = (D4['Pout']-D4['Pout_Gfront'])*100/D4['Pout']
|
|
446
|
+
D4['Mismatch'] = (D4['Pout_raw']-D4['Pout'])*100/D4['Pout_raw']
|
|
447
|
+
D4['rowNum'] = rownum
|
|
448
|
+
D4['modNum'] = modnum
|
|
449
|
+
D4m = D2.groupby(pd.PeriodIndex(D2.index, freq="Y")).mean(numeric_only=True).reset_index()
|
|
450
|
+
D4['temp_air'] = D4m['temp_air']
|
|
451
|
+
D4['wind_speed'] = D4m['wind_speed']
|
|
452
|
+
D4.drop(columns=['theta', 'surf_tilt', 'surf_azm'], inplace=True)
|
|
453
|
+
|
|
454
|
+
D3=D3.reset_index()
|
|
455
|
+
D4=D4.reset_index()
|
|
456
|
+
D3join = pd.concat([D3join, D3], ignore_index=True, sort=False)
|
|
457
|
+
D4join = pd.concat([D4join, D4], ignore_index=True, sort=False)
|
|
458
|
+
|
|
459
|
+
savefile2 = savefile[:-4]+'_Hourly.csv'
|
|
460
|
+
savefile3 = savefile[:-4]+'_Monthly.csv'
|
|
461
|
+
savefile4 = savefile[:-4]+'_Yearly.csv'
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
if D2join.empty is False:
|
|
465
|
+
D2join.to_csv(savefile2)
|
|
466
|
+
D3join.to_csv(savefile3)
|
|
467
|
+
D4join.to_csv(savefile4)
|
|
468
|
+
|
|
469
|
+
return
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
@deprecated(reason='load.deepcleanResult has been abandoned'+\
|
|
473
|
+
' Please use load.cleanResult instead',
|
|
474
|
+
version='0.5.0')
|
|
475
|
+
def deepcleanResult(resultsDict, sensorsy, numpanels, automatic=True):
|
|
476
|
+
"""
|
|
477
|
+
Cleans results file read by read1Result. If automatic = False, user is
|
|
478
|
+
asked to select material of the module (usually the one with the most results)
|
|
479
|
+
and removes sky, ground, and other materials (side of module, for example).
|
|
480
|
+
If you pass in results from a file with only _Front or _Back parameters,
|
|
481
|
+
only the corresponding Frontresults or Backresults will be returned.
|
|
482
|
+
|
|
483
|
+
.. deprecated:: 0.5.0
|
|
484
|
+
This cleaning routine is deprecated in favor of :func:`cleanResult` which
|
|
485
|
+
is more stable
|
|
486
|
+
|
|
487
|
+
Parameters
|
|
488
|
+
-----------
|
|
489
|
+
sensorsy : int
|
|
490
|
+
For the interpolation routine. Can be more than original sensorsy or same value.
|
|
491
|
+
numpanels : int
|
|
492
|
+
Options are 1 or 2 panels for this function.
|
|
493
|
+
automatic : bool
|
|
494
|
+
Default True. Automaticatlly detects module and ignores Ground, torque tube and
|
|
495
|
+
sky values. If set to off, user gets queried about the right surfaces.
|
|
496
|
+
|
|
497
|
+
Returns
|
|
498
|
+
-------
|
|
499
|
+
Frontresults : :py:class:`~pandas.DataFrame`
|
|
500
|
+
Dataframe with only front-irradiance values for the module material selected,
|
|
501
|
+
length is the number of sensors desired.
|
|
502
|
+
Backresults : :py:class:`~pandas.DataFrame`
|
|
503
|
+
Dataframe with only rear-irradiance values for the module material selected,
|
|
504
|
+
length is the number of sensors desired.
|
|
505
|
+
"""
|
|
506
|
+
|
|
507
|
+
# #TODO: add automatization of panel select.
|
|
508
|
+
|
|
509
|
+
import numpy as np
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def interp_sub(panelDict, sensorsy, frontbackkey):
|
|
513
|
+
"""
|
|
514
|
+
Parameters
|
|
515
|
+
-----------
|
|
516
|
+
panelDict : Dictionary
|
|
517
|
+
resultsDict filtered for either panelA or panelB from above.
|
|
518
|
+
sensorsy : int
|
|
519
|
+
Number of y sensors to interpolate to
|
|
520
|
+
frontbackkey : str
|
|
521
|
+
Either 'Wm2Front' or 'Wm2Back'
|
|
522
|
+
|
|
523
|
+
"""
|
|
524
|
+
x_0 = np.linspace(0, len(panelDict)-1, len(panelDict))
|
|
525
|
+
x_i = np.linspace(0, len(panelDict)-1, int(sensorsy))
|
|
526
|
+
interp_out = np.interp(x_i, x_0, panelDict[frontbackkey])
|
|
527
|
+
|
|
528
|
+
return interp_out
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
def filter_sub(resultsDict, sensorsy, frontmask, backmask=None):
|
|
532
|
+
"""
|
|
533
|
+
filter_sub: filter resultsDict to accept points where front and rear
|
|
534
|
+
materials match the list of strings in frontmask and backmask.
|
|
535
|
+
|
|
536
|
+
Parameters
|
|
537
|
+
----------
|
|
538
|
+
panelDict : Dictionary
|
|
539
|
+
resultsDict to filter
|
|
540
|
+
frontmask / backmask: List
|
|
541
|
+
list of material string values to filter for, one entry per panel.
|
|
542
|
+
"""
|
|
543
|
+
mask = np.zeros(len(resultsDict))
|
|
544
|
+
for i in range(len(frontmask)):
|
|
545
|
+
try:
|
|
546
|
+
temp_mask = (resultsDict['mattype'].str.contains(frontmask[i]) )
|
|
547
|
+
except KeyError:
|
|
548
|
+
temp_mask = np.ones(len(resultsDict))
|
|
549
|
+
if backmask:
|
|
550
|
+
temp_mask = temp_mask & (resultsDict['rearMat'].str.contains(backmask[i]))
|
|
551
|
+
mask = mask | temp_mask
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
if backmask:
|
|
555
|
+
try:
|
|
556
|
+
Frontresults = interp_sub(resultsDict[mask], sensorsy, 'Wm2Front')
|
|
557
|
+
except KeyError: # no Wm2Front data passed - rear data only.
|
|
558
|
+
Frontresults = None
|
|
559
|
+
Backresults = interp_sub(resultsDict[mask], sensorsy, 'Wm2Back')
|
|
560
|
+
else:
|
|
561
|
+
Frontresults = interp_sub(resultsDict[mask], sensorsy, resultsDict.columns[-1])
|
|
562
|
+
Backresults = None
|
|
563
|
+
|
|
564
|
+
return Frontresults, Backresults
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
if automatic == True:
|
|
568
|
+
# by default, these are the material values attached to bifacial_radiance
|
|
569
|
+
# modules
|
|
570
|
+
if 'mattype' in resultsDict:
|
|
571
|
+
frontmask = ['PVmodule.6457']
|
|
572
|
+
else: frontmask = ['PVmodule.2310'] # result only has _Back file passed
|
|
573
|
+
|
|
574
|
+
if 'rearMat' in resultsDict:
|
|
575
|
+
backmask = ['PVmodule.2310']
|
|
576
|
+
else: backmask = None
|
|
577
|
+
|
|
578
|
+
else:
|
|
579
|
+
# user-defined front and back material pairs to select. one per numpanel
|
|
580
|
+
frontmask = []
|
|
581
|
+
backmask = []
|
|
582
|
+
try: # User-entered front materials to select for
|
|
583
|
+
fronttypes = resultsDict.groupby('mattype').count()
|
|
584
|
+
print("Front type materials index and occurrences: ")
|
|
585
|
+
for i in range (len(fronttypes)):
|
|
586
|
+
print(i, " --> ", fronttypes['x'][i] , " :: ", fronttypes.index[i])
|
|
587
|
+
for i in range(numpanels):
|
|
588
|
+
val = int(input(f"Panel a{i} Front material "))
|
|
589
|
+
frontmask.append(fronttypes.index[val])
|
|
590
|
+
except KeyError: # no front mattype options to be selected
|
|
591
|
+
pass
|
|
592
|
+
|
|
593
|
+
try: # User-eneterd rear materials to select for
|
|
594
|
+
backtypes = resultsDict.groupby('rearMat').count()
|
|
595
|
+
if 'rearMat' in resultsDict:
|
|
596
|
+
print("Rear type materials index and occurrences: ")
|
|
597
|
+
for i in range (len(backtypes)):
|
|
598
|
+
print(i, " --> ", backtypes['x'][i] , " :: ", backtypes.index[i])
|
|
599
|
+
for i in range(numpanels):
|
|
600
|
+
val = int(input(f"Panel a{i} Rear material "))
|
|
601
|
+
backmask.append(backtypes.index[val])
|
|
602
|
+
except KeyError: # no rear materials to be selected
|
|
603
|
+
pass
|
|
604
|
+
|
|
605
|
+
# now that we know what material names to look for, filter resultsDict for
|
|
606
|
+
# them, removing frames, sky, torque tube, etc.
|
|
607
|
+
Frontresults, Backresults = filter_sub(resultsDict, sensorsy, frontmask, backmask)
|
|
608
|
+
|
|
609
|
+
return Frontresults, Backresults; # End Deep clean Result subroutine.
|
|
610
|
+
|
|
611
|
+
def readconfigurationinputfile(inifile=None):
|
|
612
|
+
"""
|
|
613
|
+
Function to read configurationinput file for a bifacial_radiance simulation.
|
|
614
|
+
|
|
615
|
+
Parameters
|
|
616
|
+
----------
|
|
617
|
+
input : str
|
|
618
|
+
Filename with extension .ini to read in
|
|
619
|
+
|
|
620
|
+
Returns
|
|
621
|
+
-------
|
|
622
|
+
simulationParamsDict : Dictionary
|
|
623
|
+
sceneParamsDict : Dictionary
|
|
624
|
+
timeControlParamsDict : Dictionary
|
|
625
|
+
moduleParamsDict : Dictionary
|
|
626
|
+
trackingParamsDict : Dictionary
|
|
627
|
+
torquetubeParamsDict : Dictionary
|
|
628
|
+
analysisParamsDict : Dictionary
|
|
629
|
+
cellModuleDict : Dictionary
|
|
630
|
+
CECMod : Dictionary
|
|
631
|
+
frameParamsDict : Dictionary
|
|
632
|
+
omegaParamsDict : Dictionary
|
|
633
|
+
|
|
634
|
+
"""
|
|
635
|
+
|
|
636
|
+
## #TODO: check if modulename exists on jason and rewrite is set to false, then
|
|
637
|
+
#don't save moduleParamsDict? Discuss.
|
|
638
|
+
|
|
639
|
+
import configparser
|
|
640
|
+
import os
|
|
641
|
+
import ast
|
|
642
|
+
|
|
643
|
+
def boolConvert(d):
|
|
644
|
+
""" convert strings 'True' and 'False' to boolean and convert numbers to float
|
|
645
|
+
"""
|
|
646
|
+
for key,value in d.items():
|
|
647
|
+
if value.lower() == 'true':
|
|
648
|
+
d[key] = True
|
|
649
|
+
elif value.lower() == 'false':
|
|
650
|
+
d[key] = False
|
|
651
|
+
try:
|
|
652
|
+
d[key] = float(value)
|
|
653
|
+
except ValueError:
|
|
654
|
+
pass
|
|
655
|
+
return d
|
|
656
|
+
|
|
657
|
+
if inifile is None:
|
|
658
|
+
inifile = os.path.join("data","default.ini")
|
|
659
|
+
|
|
660
|
+
config = configparser.ConfigParser(allow_no_value=True)
|
|
661
|
+
config.optionxform = str
|
|
662
|
+
config.read_file(open(inifile, 'r'))
|
|
663
|
+
|
|
664
|
+
confdict = {section: dict(config.items(section)) for section in config.sections()}
|
|
665
|
+
|
|
666
|
+
if config.has_section("simulationParamsDict"):
|
|
667
|
+
simulationParamsDict = boolConvert(confdict['simulationParamsDict'])
|
|
668
|
+
else:
|
|
669
|
+
raise Exception("Missing simulationParamsDict! Breaking")
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
if config.has_section("sceneParamsDict"):
|
|
673
|
+
sceneParamsDict2 = boolConvert(confdict['sceneParamsDict'])
|
|
674
|
+
else:
|
|
675
|
+
raise Exception("Missing sceneParams Dictionary! Breaking")
|
|
676
|
+
|
|
677
|
+
if simulationParamsDict['selectTimes']:
|
|
678
|
+
if config.has_section("timeControlParamsDict"):
|
|
679
|
+
timeControlParamsDict = confdict['timeControlParamsDict']
|
|
680
|
+
|
|
681
|
+
if simulationParamsDict['getEPW']:
|
|
682
|
+
try:
|
|
683
|
+
simulationParamsDict['latitude'] = float(simulationParamsDict['latitude'])
|
|
684
|
+
simulationParamsDict['longitude'] = float(simulationParamsDict['longitude'])
|
|
685
|
+
except:
|
|
686
|
+
if 'weatherFile' in simulationParamsDict:
|
|
687
|
+
try:
|
|
688
|
+
os.path.exists(simulationParamsDict['weatherFile'])
|
|
689
|
+
simulationParamsDict['getEPW'] = False
|
|
690
|
+
print("Load Warning: latitude or longitude missing/nan in input file.",\
|
|
691
|
+
"Since a valid weatherfile was found in the input file,",\
|
|
692
|
+
"simulationParamsDict['getepw'] has been set to false and weather file",\
|
|
693
|
+
" will be read instead.")
|
|
694
|
+
except:
|
|
695
|
+
simulationParamsDict['latitude'] = 33.0
|
|
696
|
+
simulationParamsDict['longitude'] = -110.0
|
|
697
|
+
print("Load Warning: latitude or longitude missing/nan in input file.",\
|
|
698
|
+
"Weather file was attempted to read but was invalid address/notfound,",\
|
|
699
|
+
"so default values will be used,",\
|
|
700
|
+
"latitud: %s, longitude: %s" % (simulationParamsDict['latitude'], simulationParamsDict['longitude']))
|
|
701
|
+
else:
|
|
702
|
+
simulationParamsDict['latitude'] = 33.0
|
|
703
|
+
simulationParamsDict['longitude'] = -110.0
|
|
704
|
+
print("Load Warning: latitude or longitude missing/nan in input file.",\
|
|
705
|
+
"No Weather file was passed, so default values will be used,",\
|
|
706
|
+
"latitud: %s, longitude: %s" % (simulationParamsDict['latitude'], simulationParamsDict['longitude']))
|
|
707
|
+
|
|
708
|
+
if config.has_section("moduleParamsDict"):
|
|
709
|
+
moduleParamsDict2 = boolConvert(confdict['moduleParamsDict'])
|
|
710
|
+
moduleParamsDict={} # Defining a new one to only save relevant values from passed.
|
|
711
|
+
try:
|
|
712
|
+
moduleParamsDict['bifi'] = round(float(moduleParamsDict2['bifi']),2)
|
|
713
|
+
except:
|
|
714
|
+
moduleParamsDict['bifi'] = 0.9 #Default
|
|
715
|
+
print("Load Warning: moduleParamsDict['bifi'] not specified, setting to default value: %s" % moduleParamsDict['bifi'] )
|
|
716
|
+
try:
|
|
717
|
+
moduleParamsDict['numpanels'] = int(moduleParamsDict2['numpanels'])
|
|
718
|
+
except:
|
|
719
|
+
moduleParamsDict['numpanels'] = 1 #Default
|
|
720
|
+
print("Load Warning: moduleParamsDict['numpanels'] not specified, setting to default value: %s" % moduleParamsDict['numpanels'] )
|
|
721
|
+
try:
|
|
722
|
+
moduleParamsDict['xgap'] = round(float(moduleParamsDict2['xgap']),3)
|
|
723
|
+
except:
|
|
724
|
+
moduleParamsDict['xgap'] = 0.01 #Default
|
|
725
|
+
print("Load Warning: moduleParamsDict['xgap'] not specified, setting to default value: %s" % moduleParamsDict['xgap'] )
|
|
726
|
+
try:
|
|
727
|
+
moduleParamsDict['ygap'] = round(float(moduleParamsDict2['ygap']),3)
|
|
728
|
+
except:
|
|
729
|
+
moduleParamsDict['ygap'] = 0.150 #Default
|
|
730
|
+
print("Load Warning: moduleParamsDict['ygap'] not specified, setting to default value: %s" % moduleParamsDict['ygap'] )
|
|
731
|
+
|
|
732
|
+
try:
|
|
733
|
+
moduleParamsDict['zgap'] = round(float(moduleParamsDict2['zgap']),3)
|
|
734
|
+
except:
|
|
735
|
+
moduleParamsDict['zgap'] = 0.1 #Default
|
|
736
|
+
print("Load Warning: moduleParamsDict['zgap'] not specified, setting to default value: %s" % moduleParamsDict['zgap'] )
|
|
737
|
+
if 'glass' in moduleParamsDict2:
|
|
738
|
+
moduleParamsDict['glass'] = moduleParamsDict2['glass']
|
|
739
|
+
if moduleParamsDict2.get('glassEdge'):
|
|
740
|
+
moduleParamsDict['glassEdge'] = moduleParamsDict2['glassEdge']
|
|
741
|
+
|
|
742
|
+
try:
|
|
743
|
+
moduleParamsDict['customtext'] = moduleParamsDict2['customtext']
|
|
744
|
+
except:
|
|
745
|
+
moduleParamsDict['customtext'] = ''
|
|
746
|
+
|
|
747
|
+
try:
|
|
748
|
+
moduleParamsDict['customObject'] = moduleParamsDict2['customObject']
|
|
749
|
+
except:
|
|
750
|
+
moduleParamsDict['customObject'] = ''
|
|
751
|
+
|
|
752
|
+
if simulationParamsDict['cellLevelModule']:
|
|
753
|
+
if config.has_section("cellLevelModuleParamsDict"):
|
|
754
|
+
cellModuleDict = confdict['cellLevelModuleParamsDict']
|
|
755
|
+
try: # being lazy so just validating the whole dictionary as a whole. #TODO: validate individually maybe.
|
|
756
|
+
cellModuleDict['numcellsx'] = int(cellModuleDict['numcellsx'])
|
|
757
|
+
cellModuleDict['numcellsy'] = int(cellModuleDict['numcellsy'])
|
|
758
|
+
cellModuleDict['xcell'] = round(float(cellModuleDict['xcell']),3)
|
|
759
|
+
cellModuleDict['xcellgap'] = round(float(cellModuleDict['xcellgap']),3)
|
|
760
|
+
cellModuleDict['ycell'] = round(float(cellModuleDict['ycell']),3)
|
|
761
|
+
cellModuleDict['ycellgap'] = round(float(cellModuleDict['ycellgap']),3)
|
|
762
|
+
if 'centerJB' in cellModuleDict:
|
|
763
|
+
cellModuleDict['centerJB'] = round(float(cellModuleDict['centerJB']),3)
|
|
764
|
+
except:
|
|
765
|
+
print("Load Warning: celllevelModule set to True,",\
|
|
766
|
+
"but celllevelModule parameters are missing/not numbers.")
|
|
767
|
+
try:
|
|
768
|
+
moduleParamsDict['x'] = round(float(moduleParamsDict2['x']),3)
|
|
769
|
+
moduleParamsDict['y'] = round(float(moduleParamsDict2['y']),3)
|
|
770
|
+
simulationParamsDict['celllevelmodule'] = False
|
|
771
|
+
print("Due to error on celllevelModule info, ",\
|
|
772
|
+
"celllevelModule has ben set to False and the", \
|
|
773
|
+
"passed values of x and y on moduleParamsDict will",\
|
|
774
|
+
"be used to generate the custom module")
|
|
775
|
+
except:
|
|
776
|
+
print("Attempted to load x and y instead of celllevelModule parameters,",\
|
|
777
|
+
"Failed, so default values for cellLevelModule will be passed")
|
|
778
|
+
cellModuleDict['numcellsx'] = 12
|
|
779
|
+
cellModuleDict['numcellsy'] = 6
|
|
780
|
+
cellModuleDict['xcell'] = 0.15
|
|
781
|
+
cellModuleDict['xcellgap'] = 0.1
|
|
782
|
+
cellModuleDict['ycell'] = 0.15
|
|
783
|
+
cellModuleDict['ycellgap'] = 0.1
|
|
784
|
+
else: # no cellleveldictionary passed
|
|
785
|
+
print("Load Warning: celllevelmodule selected, but no dictionary was passed in input file.",\
|
|
786
|
+
"attempting to proceed with regular custom module and setting celllevelmodule to false")
|
|
787
|
+
simulationParamsDict['celllevelmodule'] = False
|
|
788
|
+
|
|
789
|
+
try:
|
|
790
|
+
moduleParamsDict['x'] = round(float(moduleParamsDict2['x']),3)
|
|
791
|
+
except:
|
|
792
|
+
moduleParamsDict['x'] = 0.98
|
|
793
|
+
print("Load Warning: moduleParamsDict['x'] not specified, setting to default value: %s" % moduleParamsDict['x'] )
|
|
794
|
+
try:
|
|
795
|
+
moduleParamsDict['y'] = round(float(moduleParamsDict2['y']),3)
|
|
796
|
+
except:
|
|
797
|
+
moduleParamsDict['y'] = 1.95
|
|
798
|
+
print("Load Warning: moduleParamsDict['y'] not specified, setting to default value: %s" % moduleParamsDict['y'] )
|
|
799
|
+
|
|
800
|
+
else: # no cell level module requested:
|
|
801
|
+
try:
|
|
802
|
+
moduleParamsDict['x'] = round(float(moduleParamsDict2['x']),3)
|
|
803
|
+
except:
|
|
804
|
+
moduleParamsDict['x'] = 0.98
|
|
805
|
+
print("Load Warning: moduleParamsDict['x'] not specified, setting to default value: %s" % moduleParamsDict['x'] )
|
|
806
|
+
try:
|
|
807
|
+
moduleParamsDict['y'] = round(float(moduleParamsDict2['y']),3)
|
|
808
|
+
except:
|
|
809
|
+
moduleParamsDict['y'] = 1.95
|
|
810
|
+
print("Load Warning: moduleParamsDict['y'] not specified, setting to default value: %s" % moduleParamsDict['y'] )
|
|
811
|
+
|
|
812
|
+
if simulationParamsDict['selectTimes']:
|
|
813
|
+
if ('starttime' in timeControlParamsDict) or ('endtime' in timeControlParamsDict):
|
|
814
|
+
print("Loading times to restrict weather data to")
|
|
815
|
+
else:
|
|
816
|
+
print("Load Warning: no valid time to restrict weather data passed"
|
|
817
|
+
"Simulating default day 06/21 at noon")
|
|
818
|
+
timeControlParamsDict['starttime']='06_21_12'
|
|
819
|
+
timeControlParamsDict['endtime']='06_21_12'
|
|
820
|
+
|
|
821
|
+
#NEEDED sceneParamsDict parameters
|
|
822
|
+
sceneParamsDict={}
|
|
823
|
+
try:
|
|
824
|
+
sceneParamsDict['albedo']=round(float(sceneParamsDict2['albedo']),2)
|
|
825
|
+
except:
|
|
826
|
+
sceneParamsDict['albedo']=sceneParamsDict2['albedo']
|
|
827
|
+
#print("Load Warning: sceneParamsDict['albedo'] not specified, setting to default value: %s" % sceneParamsDict['albedo'] )
|
|
828
|
+
try:
|
|
829
|
+
sceneParamsDict['nMods']=int(sceneParamsDict2['nMods'])
|
|
830
|
+
except:
|
|
831
|
+
sceneParamsDict['nMods']=20
|
|
832
|
+
print("Load Warning: sceneParamsDict['nMods'] not specified, setting to default value: %s" % sceneParamsDict['nMods'] )
|
|
833
|
+
try:
|
|
834
|
+
sceneParamsDict['nRows']=int(sceneParamsDict2['nRows'])
|
|
835
|
+
except:
|
|
836
|
+
sceneParamsDict['nRows']=7
|
|
837
|
+
print("Load Warning: sceneParamsDict['nRows'] not specified, setting to default value: %s" % sceneParamsDict['nRows'] )
|
|
838
|
+
|
|
839
|
+
#Optional sceneParamsDict parameters
|
|
840
|
+
sceneParamsDict['gcrorpitch'] = sceneParamsDict2['gcrorpitch']
|
|
841
|
+
if sceneParamsDict['gcrorpitch'] == 'gcr':
|
|
842
|
+
sceneParamsDict['gcr']=round(float(sceneParamsDict2['gcr']),3)
|
|
843
|
+
else:
|
|
844
|
+
sceneParamsDict['pitch']=round(float(sceneParamsDict2['pitch']),2)
|
|
845
|
+
|
|
846
|
+
if "customObject" in sceneParamsDict2:
|
|
847
|
+
sceneParamsDict['customObject'] = sceneParamsDict2['customObject']
|
|
848
|
+
|
|
849
|
+
if simulationParamsDict['tracking']:
|
|
850
|
+
if 'axis_aziumth' in sceneParamsDict2:
|
|
851
|
+
azimuth = round(float(sceneParamsDict2['axis_azimuth']),2)
|
|
852
|
+
elif sceneParamsDict2.get('azimuth'):
|
|
853
|
+
azimuth = sceneParamsDict2.get('azimuth')
|
|
854
|
+
else:
|
|
855
|
+
raise Exception(f'Neither "axis_azimuth" or "azimuth" in .inifile {inifile}' )
|
|
856
|
+
|
|
857
|
+
sceneParamsDict['azimuth']=round(float(azimuth),2)
|
|
858
|
+
sceneParamsDict['hub_height']=round(float(sceneParamsDict2['hub_height']),2)
|
|
859
|
+
|
|
860
|
+
if config.has_section("trackingParamsDict"):
|
|
861
|
+
trackingParamsDict = boolConvert(confdict['trackingParamsDict'])
|
|
862
|
+
printTrackerWarning = False
|
|
863
|
+
else:
|
|
864
|
+
trackingParamsDict={}
|
|
865
|
+
printTrackerWarning = True
|
|
866
|
+
if 'limit_angle' in trackingParamsDict:
|
|
867
|
+
trackingParamsDict['limit_angle']=round(float(trackingParamsDict['limit_angle']), 0)
|
|
868
|
+
else:
|
|
869
|
+
trackingParamsDict['limit_angle']=60
|
|
870
|
+
if 'angle_delta' in trackingParamsDict:
|
|
871
|
+
try:
|
|
872
|
+
trackingParamsDict['angle_delta']=round(float(trackingParamsDict['angle_delta']), 2)
|
|
873
|
+
except:
|
|
874
|
+
trackingParamsDict['angle_delta']=1
|
|
875
|
+
else:
|
|
876
|
+
trackingParamsDict['angle_delta'] = (5 if simulationParamsDict['cumulativeSky'] else 0.01)
|
|
877
|
+
if 'backtrack' not in trackingParamsDict:
|
|
878
|
+
trackingParamsDict['backtrack']=5
|
|
879
|
+
|
|
880
|
+
if printTrackerWarning:
|
|
881
|
+
print("Load warning: tracking selected, but no tracking parameters specified.",\
|
|
882
|
+
"Using defaults for limit angle: 60; angle delta: %s, backtracking: True" % trackingParamsDict['angle_delta'])
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
else: # fixed
|
|
886
|
+
sceneParamsDict['azimuth']=round(float(sceneParamsDict2['azimuth']),2)
|
|
887
|
+
sceneParamsDict['clearance_height']=round(float(sceneParamsDict2['clearance_height']),2)
|
|
888
|
+
sceneParamsDict['tilt']=round(float(sceneParamsDict2['tilt']),2)
|
|
889
|
+
|
|
890
|
+
#
|
|
891
|
+
if simulationParamsDict['torqueTube']:
|
|
892
|
+
if config.has_section("torquetubeParamsDict"):
|
|
893
|
+
torquetubeParamsDict = boolConvert(confdict['torquetubeParamsDict'])
|
|
894
|
+
try:
|
|
895
|
+
torquetubeParamsDict['diameter'] = round(float(torquetubeParamsDict['diameter']),3)
|
|
896
|
+
except:
|
|
897
|
+
torquetubeParamsDict['diameter'] = 0.150
|
|
898
|
+
print("Load Warning: torquetubeParamsDict['diameter'] not "
|
|
899
|
+
"specified, setting to default value: %s" % torquetubeParamsDict['diameter'] )
|
|
900
|
+
#TODO: Validate for torquetube material and torquetube shape.
|
|
901
|
+
else:
|
|
902
|
+
print("Load warning: torquetubeParams dictionary not passed, but torquetube set to true.",\
|
|
903
|
+
"settung torquetube to false")
|
|
904
|
+
simulationParamsDict['torquetube'] = False
|
|
905
|
+
#TODO: decide if default values passed if this is set to true ?
|
|
906
|
+
|
|
907
|
+
#Optional analysisParamsDict
|
|
908
|
+
if config.has_section("analysisParamsDict"):
|
|
909
|
+
analysisParamsDict = boolConvert(confdict['analysisParamsDict'])
|
|
910
|
+
try:
|
|
911
|
+
analysisParamsDict['sensorsy']=ast.literal_eval(str(analysisParamsDict['sensorsy']))
|
|
912
|
+
except ValueError:
|
|
913
|
+
print("Load Warning: improper analysisParamsDict['sensorsy']"
|
|
914
|
+
" passed: %s, setting to default value: 9" % analysisParamsDict['sensorsy'] )
|
|
915
|
+
analysisParamsDict['sensorsy'] = 9 #Default
|
|
916
|
+
try:
|
|
917
|
+
analysisParamsDict['modWanted']=ast.literal_eval(str(analysisParamsDict['modWanted']))
|
|
918
|
+
except:
|
|
919
|
+
analysisParamsDict['modWanted'] = None #Default
|
|
920
|
+
print("analysisParamsDict['modWanted'] set to middle module by default" )
|
|
921
|
+
try:
|
|
922
|
+
analysisParamsDict['rowWanted']=ast.literal_eval(str(analysisParamsDict['rowWanted']))
|
|
923
|
+
except:
|
|
924
|
+
analysisParamsDict['rowWanted'] = None #Default
|
|
925
|
+
print("analysisParamsDict['rowWanted'] set to middle row by default" )
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
if config.has_section("CECModParamsDict"):
|
|
929
|
+
CECModParamsDict = confdict['CECModParamsDict']
|
|
930
|
+
try:
|
|
931
|
+
CECModParamsDict['alpha_sc']=float(CECModParamsDict['alpha_sc'])
|
|
932
|
+
CECModParamsDict['a_ref']=float(CECModParamsDict['a_ref'])
|
|
933
|
+
CECModParamsDict['I_L_ref']=float(CECModParamsDict['I_L_ref'])
|
|
934
|
+
CECModParamsDict['I_o_ref']=float(CECModParamsDict['I_o_ref'])
|
|
935
|
+
CECModParamsDict['R_sh_ref']=float(CECModParamsDict['R_sh_ref'])
|
|
936
|
+
CECModParamsDict['R_s']=float(CECModParamsDict['R_s'])
|
|
937
|
+
CECModParamsDict['Adjust']=float(CECModParamsDict['Adjust'])
|
|
938
|
+
except:
|
|
939
|
+
print("Error: Mising/wrong parameters for CECModParamsDict, setting dictionary to None.",
|
|
940
|
+
"MAke sure to include alpha_sc, a_ref, I_L_ref, I_o_ref, ",
|
|
941
|
+
"R_sh_ref, R_s, and Adjust."
|
|
942
|
+
"Performance calculations, if performed, will use default module")
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
# Add omegas, frames, piles here
|
|
946
|
+
if config.has_section("omegaParamsDict"):
|
|
947
|
+
omegaParamsDict = confdict['omegaParamsDict']
|
|
948
|
+
try: # validating the whole dictionary as a whole. #TODO: validate individually maybe.
|
|
949
|
+
omegaParamsDict['x_omega1'] = round(float(omegaParamsDict['x_omega1']),3)
|
|
950
|
+
omegaParamsDict['mod_overlap'] = round(float(omegaParamsDict['mod_overlap']),3)
|
|
951
|
+
omegaParamsDict['y_omega'] = round(float(omegaParamsDict['y_omega']),3)
|
|
952
|
+
omegaParamsDict['omega_thickness'] = round(float(omegaParamsDict['omega_thickness']),3)
|
|
953
|
+
omegaParamsDict['x_omega3'] = round(float(omegaParamsDict['x_omega3']),3)
|
|
954
|
+
omegaParamsDict['inverted'] = ast.literal_eval(str(omegaParamsDict['inverted']))
|
|
955
|
+
except:
|
|
956
|
+
print("Load Warning: Omega Parameters passed, ",\
|
|
957
|
+
"but some parameters are missing/not numbers.")
|
|
958
|
+
|
|
959
|
+
# Add Frames, frames, piles here
|
|
960
|
+
if config.has_section("frameParamsDict"):
|
|
961
|
+
frameParamsDict = confdict['frameParamsDict']
|
|
962
|
+
try: # validating the whole dictionary as a whole. #TODO: validate individually maybe.
|
|
963
|
+
frameParamsDict['frame_width'] = round(float(frameParamsDict['frame_width']),3)
|
|
964
|
+
frameParamsDict['frame_thickness'] = round(float(frameParamsDict['frame_thickness']),3)
|
|
965
|
+
frameParamsDict['frame_z'] = round(float(frameParamsDict['frame_z']),3)
|
|
966
|
+
frameParamsDict['frame_width'] = round(float(frameParamsDict['frame_width']),3)
|
|
967
|
+
frameParamsDict['nSides_frame'] = int(frameParamsDict['nSides_frame'])
|
|
968
|
+
except:
|
|
969
|
+
print("Load Warning: Fame Parameters passed, ",\
|
|
970
|
+
"but some parameters are missing/not numbers.")
|
|
971
|
+
|
|
972
|
+
# Piles here
|
|
973
|
+
if config.has_section("pilesParamsDict"):
|
|
974
|
+
pilesParamsDict = confdict['pilesParamsDict']
|
|
975
|
+
try: # validating the whole dictionary as a whole. #TODO: validate individually maybe.
|
|
976
|
+
pilesParamsDict['spacingPiles'] = round(float(pilesParamsDict['spacingPiles']),3)
|
|
977
|
+
pilesParamsDict['pile_lenx'] = round(float(pilesParamsDict['pile_lenx']),3)
|
|
978
|
+
pilesParamsDict['pile_leny'] = round(float(pilesParamsDict['pile_leny']),3)
|
|
979
|
+
pilesParamsDict['pile_height'] = round(float(pilesParamsDict['pile_height']),3)
|
|
980
|
+
except:
|
|
981
|
+
print("Load Warning: Pile Parameters passed, ",\
|
|
982
|
+
"but some parameters are missing/not numbers.")
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
# Creating None dictionaries for those empty ones
|
|
986
|
+
try: timeControlParamsDict
|
|
987
|
+
except: timeControlParamsDict = None
|
|
988
|
+
|
|
989
|
+
try: moduleParamsDict
|
|
990
|
+
except: moduleParamsDict = None
|
|
991
|
+
|
|
992
|
+
try: trackingParamsDict
|
|
993
|
+
except: trackingParamsDict = None
|
|
994
|
+
|
|
995
|
+
try: torquetubeParamsDict
|
|
996
|
+
except: torquetubeParamsDict = None
|
|
997
|
+
|
|
998
|
+
try: analysisParamsDict
|
|
999
|
+
except: analysisParamsDict = None
|
|
1000
|
+
|
|
1001
|
+
try: cellModuleDict
|
|
1002
|
+
except: cellModuleDict = None
|
|
1003
|
+
|
|
1004
|
+
try: CECModParamsDict
|
|
1005
|
+
except: CECModParamsDict = None
|
|
1006
|
+
|
|
1007
|
+
try: frameParamsDict
|
|
1008
|
+
except: frameParamsDict = None
|
|
1009
|
+
|
|
1010
|
+
try: pilesParamsDict
|
|
1011
|
+
except: pilesParamsDict = None
|
|
1012
|
+
|
|
1013
|
+
try: omegaParamsDict
|
|
1014
|
+
except: omegaParamsDict = None
|
|
1015
|
+
|
|
1016
|
+
# end readconfigurationinputfile
|
|
1017
|
+
return (simulationParamsDict, sceneParamsDict, timeControlParamsDict,
|
|
1018
|
+
moduleParamsDict, trackingParamsDict, torquetubeParamsDict,
|
|
1019
|
+
analysisParamsDict, cellModuleDict, CECModParamsDict,
|
|
1020
|
+
frameParamsDict, omegaParamsDict, pilesParamsDict)
|
|
1021
|
+
|
|
1022
|
+
|
|
1023
|
+
|
|
1024
|
+
def savedictionariestoConfigurationIniFile(simulationParamsDict, sceneParamsDict,
|
|
1025
|
+
timeControlParamsDict=None, moduleParamsDict=None,
|
|
1026
|
+
trackingParamsDict=None, torquetubeParamsDict=None,
|
|
1027
|
+
analysisParamsDict=None, cellModuleDict=None,
|
|
1028
|
+
CECModParamsDict=None, frameParamsDict=None,
|
|
1029
|
+
omegaParamsDict=None, pilesParamsDict=None,
|
|
1030
|
+
inifilename=None):
|
|
1031
|
+
"""
|
|
1032
|
+
Saves dictionaries from working memory into a Configuration File
|
|
1033
|
+
with extension format .ini.
|
|
1034
|
+
|
|
1035
|
+
Parameters
|
|
1036
|
+
----------
|
|
1037
|
+
simulationParamsDict
|
|
1038
|
+
sceneParamsDict
|
|
1039
|
+
timeControlParamsDict
|
|
1040
|
+
Default None
|
|
1041
|
+
moduleParamsDict
|
|
1042
|
+
Default None
|
|
1043
|
+
trackingParamsDict
|
|
1044
|
+
Default None
|
|
1045
|
+
torquetubeParamsDict
|
|
1046
|
+
Default None
|
|
1047
|
+
analysisParamsDict
|
|
1048
|
+
Default None,
|
|
1049
|
+
cellModuleDict
|
|
1050
|
+
Default None
|
|
1051
|
+
|
|
1052
|
+
Returns
|
|
1053
|
+
-------
|
|
1054
|
+
Writes output into inifilename passed (default if inifilename=None is
|
|
1055
|
+
'example.ini')
|
|
1056
|
+
"""
|
|
1057
|
+
|
|
1058
|
+
import configparser
|
|
1059
|
+
|
|
1060
|
+
config = configparser.ConfigParser(allow_no_value=True)
|
|
1061
|
+
config.optionxform = str
|
|
1062
|
+
config['simulationParamsDict'] = simulationParamsDict
|
|
1063
|
+
config['sceneParamsDict'] = sceneParamsDict
|
|
1064
|
+
|
|
1065
|
+
try: config['timeControlParamsDict'] = timeControlParamsDict
|
|
1066
|
+
except: pass
|
|
1067
|
+
|
|
1068
|
+
try: config['moduleParamsDict'] = moduleParamsDict
|
|
1069
|
+
except: pass
|
|
1070
|
+
|
|
1071
|
+
try: config['trackingParamsDict'] = trackingParamsDict
|
|
1072
|
+
except: pass
|
|
1073
|
+
|
|
1074
|
+
try: config['torquetubeParamsDict'] = torquetubeParamsDict
|
|
1075
|
+
except: pass
|
|
1076
|
+
|
|
1077
|
+
try: config['analysisParamsDict'] = analysisParamsDict
|
|
1078
|
+
except: pass
|
|
1079
|
+
|
|
1080
|
+
try: config['cellLevelModuleParamsDict'] = cellModuleDict
|
|
1081
|
+
except: pass
|
|
1082
|
+
|
|
1083
|
+
try: config['CECModParamsDict'] = CECModParamsDict
|
|
1084
|
+
except: pass
|
|
1085
|
+
|
|
1086
|
+
if frameParamsDict:
|
|
1087
|
+
try: config['frameParamsDict'] = frameParamsDict
|
|
1088
|
+
except: pass
|
|
1089
|
+
|
|
1090
|
+
if omegaParamsDict:
|
|
1091
|
+
try: config['omegaParamsDict'] = omegaParamsDict
|
|
1092
|
+
except: pass
|
|
1093
|
+
|
|
1094
|
+
if pilesParamsDict:
|
|
1095
|
+
try: config['pilesParamsDict'] = pilesParamsDict
|
|
1096
|
+
except: pass
|
|
1097
|
+
|
|
1098
|
+
if inifilename is None:
|
|
1099
|
+
inifilename = 'example.ini'
|
|
1100
|
+
|
|
1101
|
+
with open(inifilename, 'w') as configfile:
|
|
1102
|
+
config.write(configfile)
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
'''
|
|
1106
|
+
## abandoned project to refactor this module...
|
|
1107
|
+
class Params():
|
|
1108
|
+
"""
|
|
1109
|
+
Model configuration parameters. Including the following:
|
|
1110
|
+
|
|
1111
|
+
Parameters
|
|
1112
|
+
----------
|
|
1113
|
+
simulationParams testfolder, weatherfile, getEPW, simulationname,
|
|
1114
|
+
moduletype, rewritemodule,
|
|
1115
|
+
rcellLevelmodule, axisofrotationtorquetube,
|
|
1116
|
+
torqueTube, hpc, tracking, cumulativesky,
|
|
1117
|
+
selectTimes
|
|
1118
|
+
sceneParams: gcrorpitch, gcr, pitch, albedo, nMods, nRows,
|
|
1119
|
+
hub_height, clearance_height, azimuth, hub_height, axis_Azimuth
|
|
1120
|
+
timeControlParams: hourstart, hourend, daystart, dayend, monthstart, monthend,
|
|
1121
|
+
timestampstart, timestampend,
|
|
1122
|
+
moduleParams: numpanels, x, y, bifi, xgap, ygap, zgap
|
|
1123
|
+
cellLevelModuleParams: numcellsx, numcellsy, xcell, ycell, xcellgap, ycellgap
|
|
1124
|
+
trackingParams: backtrack, limit_angle,angle_delta
|
|
1125
|
+
torquetubeParams: diameter, tubetype, torqueTubeMaterial
|
|
1126
|
+
analysisParams: sensorsy, modWanted, rowWanted
|
|
1127
|
+
|
|
1128
|
+
"""
|
|
1129
|
+
# #DocumentationCheck : add to updates
|
|
1130
|
+
# cdeline 5/9/19: new class to try to make some sense of these model parameters?
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
def __init__(self, simulationParams=None, sceneParams=None,
|
|
1134
|
+
timeControlParams=None, moduleParams=None,
|
|
1135
|
+
cellLevelModuleParams=None, trackingParams=None,
|
|
1136
|
+
torquetubeParams=None, analysisParams=None):
|
|
1137
|
+
|
|
1138
|
+
self.simulationParams = simulationParams
|
|
1139
|
+
self.sceneParams = sceneParams
|
|
1140
|
+
self.timeControlParams = timeControlParams
|
|
1141
|
+
self.moduleParams = moduleParams
|
|
1142
|
+
self.cellLevelModuleParams = cellLevelModuleParams
|
|
1143
|
+
self.trackingParams = trackingParams
|
|
1144
|
+
self.torquetubeParams = torquetubeParams
|
|
1145
|
+
self.analysisParams = analysisParams
|
|
1146
|
+
|
|
1147
|
+
def unpack(self):
|
|
1148
|
+
return self.simulationParams, \
|
|
1149
|
+
self.sceneParams, \
|
|
1150
|
+
self.timeControlParams, \
|
|
1151
|
+
self.moduleParams, \
|
|
1152
|
+
self.trackingParams, \
|
|
1153
|
+
self.torquetubeParams, \
|
|
1154
|
+
self.analysisParams, \
|
|
1155
|
+
self.cellLevelModuleParams
|
|
1156
|
+
'''
|