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.
Files changed (63) hide show
  1. bifacial_radiance/HPCScripts/BasicSimulations/addNewModule.py +15 -0
  2. bifacial_radiance/HPCScripts/BasicSimulations/dask_on_node.sh +11 -0
  3. bifacial_radiance/HPCScripts/BasicSimulations/run_sbatch.sbatch +51 -0
  4. bifacial_radiance/HPCScripts/BasicSimulations/simulate_fixedtilt_gencumsky.py +110 -0
  5. bifacial_radiance/HPCScripts/BasicSimulations/simulate_fixedtilt_gendaylit.py +102 -0
  6. bifacial_radiance/HPCScripts/BasicSimulations/simulate_tracking_gendaylit.py +126 -0
  7. bifacial_radiance/HPCScripts/Other Examples (unorganized)/PuertoRico.py +168 -0
  8. bifacial_radiance/HPCScripts/Other Examples (unorganized)/PuertoRico_2.py +166 -0
  9. bifacial_radiance/HPCScripts/Other Examples (unorganized)/PuertoRico_Original.py +195 -0
  10. bifacial_radiance/HPCScripts/Other Examples (unorganized)/basic_module_sampling.py +154 -0
  11. bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_B.py +162 -0
  12. bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_Cases.py +122 -0
  13. bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_CasesMonth.py +142 -0
  14. bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_PRNew.py +91 -0
  15. bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_PRNewP2.py +95 -0
  16. bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_TreeResults.py +108 -0
  17. bifacial_radiance/HPCScripts/Other Examples (unorganized)/compile_basic_module_sampling.py +103 -0
  18. bifacial_radiance/HPCScripts/Other Examples (unorganized)/simulate_JackHourly.py +160 -0
  19. bifacial_radiance/HPCScripts/Other Examples (unorganized)/simulate_improvedArray_Oct2127.py +623 -0
  20. bifacial_radiance/TEMP/.gitignore +4 -0
  21. bifacial_radiance/__init__.py +24 -0
  22. bifacial_radiance/data/CEC Modules.csv +16860 -0
  23. bifacial_radiance/data/default.ini +65 -0
  24. bifacial_radiance/data/falsecolor.exe +0 -0
  25. bifacial_radiance/data/gencumsky/License.txt +54 -0
  26. bifacial_radiance/data/gencumsky/Makefile +17 -0
  27. bifacial_radiance/data/gencumsky/README.txt +9 -0
  28. bifacial_radiance/data/gencumsky/Solar Irradiation Modelling.doc +0 -0
  29. bifacial_radiance/data/gencumsky/Sun.cpp +118 -0
  30. bifacial_radiance/data/gencumsky/Sun.h +45 -0
  31. bifacial_radiance/data/gencumsky/average_val.awk +3 -0
  32. bifacial_radiance/data/gencumsky/cPerezSkyModel.cpp +238 -0
  33. bifacial_radiance/data/gencumsky/cPerezSkyModel.h +57 -0
  34. bifacial_radiance/data/gencumsky/cSkyVault.cpp +536 -0
  35. bifacial_radiance/data/gencumsky/cSkyVault.h +86 -0
  36. bifacial_radiance/data/gencumsky/climateFile.cpp +312 -0
  37. bifacial_radiance/data/gencumsky/climateFile.h +37 -0
  38. bifacial_radiance/data/gencumsky/cumulative.cal +177 -0
  39. bifacial_radiance/data/gencumsky/cumulative.rad +14 -0
  40. bifacial_radiance/data/gencumsky/cumulativesky_rotated.rad +2 -0
  41. bifacial_radiance/data/gencumsky/gencumulativesky +0 -0
  42. bifacial_radiance/data/gencumsky/gencumulativesky.cpp +269 -0
  43. bifacial_radiance/data/gencumsky/make_gencumskyexe.py +107 -0
  44. bifacial_radiance/data/gencumsky/paths.h +62 -0
  45. bifacial_radiance/data/gencumulativesky +0 -0
  46. bifacial_radiance/data/gencumulativesky.exe +0 -0
  47. bifacial_radiance/data/ground.rad +83 -0
  48. bifacial_radiance/data/module.json +103 -0
  49. bifacial_radiance/gui.py +1696 -0
  50. bifacial_radiance/images/fig1_fixed_small.gif +0 -0
  51. bifacial_radiance/images/fig2_tracked_small.gif +0 -0
  52. bifacial_radiance/load.py +1156 -0
  53. bifacial_radiance/main.py +5673 -0
  54. bifacial_radiance/mismatch.py +461 -0
  55. bifacial_radiance/modelchain.py +299 -0
  56. bifacial_radiance/module.py +1427 -0
  57. bifacial_radiance/performance.py +466 -0
  58. bifacial_radiance/spectral_utils.py +555 -0
  59. bifacial_radiance-0.5.1.dist-info/METADATA +129 -0
  60. bifacial_radiance-0.5.1.dist-info/RECORD +63 -0
  61. bifacial_radiance-0.5.1.dist-info/WHEEL +6 -0
  62. bifacial_radiance-0.5.1.dist-info/licenses/LICENSE +30 -0
  63. 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
+ '''