# -*- coding: utf-8 -*-
"""
Created on Tue Mar 26 20:16:47 2019
@author: sayala
"""
#from load import *
def _sensorupsampletocellsbyInterpolation(df, cellsy):
'''
Function for when sensorsy in the results are less than cellsy desired.
Interpolates the dataframe.
#2DO: improve interpolation with pandas. right onw it's row by row.
_sensorupsampletocellsbyInterpolation(df, cellsy)
'''
import pandas as pd
import numpy as np
sensorsy = len(df)
#2DO: Update this section to match bifacialvf
cellCenterPVM=[]
for i in range (0, cellsy):
cellCenterPVM.append((i*sensorsy/cellsy+(i+1)*sensorsy/cellsy)/2)
df2 = pd.DataFrame()
for j in range (0, len(df.keys())):
A = list(df[df.keys()[j]])
B= np.interp(cellCenterPVM, list(range(0,sensorsy)), A)
df2[df.keys()[j]]=B
return df2
def _sensorsdownsampletocellsbyAverage(df, cellsy):
'''
df = dataframe with rows indexed by number (i.e. 0 to sensorsy) where sensorsy > cellsy
cellsy = int. usually 8 or 12.
example:
F_centeraverages = _sensorsdownsampletocellsbyAverage(F, cellsy)
'''
import numpy as np
import pandas as pd
edges=len(df)-np.floor(len(df)/(cellsy))*(cellsy)
edge1=int(np.floor(edges/2))
edge2=int(edges-edge1)
A = list(range(df.index[0]+edge1, df.index[-1]-edge2+2, int(np.floor(len(df)/(cellsy)))))
B = range(0,len(A)-1,1)
C = [df.iloc[A[x]:A[x+1]].mean(axis=0) for x in B]
df_centeraverages=pd.DataFrame(C)
return df_centeraverages
def _sensorsdownsampletocellbyCenter(df, cellsy):
'''
df = dataframe with rows indexed by number (i.e. 0 to sensorsy) where sensorsy > cellsy
cellsy = int. usually 8 or 12.
example:
F_centervalues = _sensorsdownsampletocellbyCenter(F, cellsy)
'''
import numpy as np
edges=len(df)-np.floor(len(df)/(cellsy))*(cellsy)
edge1=int(np.floor(edges/2))
edge2=int(edges-edge1)
A = list(range(df.index[0]+edge1, df.index[-1]-edge2+2, int(np.floor(len(df)/(cellsy)))))
A = [int(x+(A[1]-A[0])*0.5) for x in A]
A = A[:-1]
df_centervalues=df.loc[A]
df_centervalues=df_centervalues.reset_index(drop=True)
return df_centervalues
def _setupforPVMismatch(portraitorlandscape, sensorsy, numcells=72):
r''' Sets values for calling PVMismatch, for ladscape or portrait modes and
Example:
stdpl, cellsx, cellsy = _setupforPVMismatch(portraitorlandscape='portrait', sensorsy=100):
'''
import numpy as np
# cell placement for 'portrait'.
if numcells == 72:
stdpl=np.array([[0, 23, 24, 47, 48, 71],
[1, 22, 25, 46, 49, 70],
[2, 21, 26, 45, 50, 69],
[3, 20, 27, 44, 51, 68],
[4, 19, 28, 43, 52, 67],
[5, 18, 29, 42, 53, 66],
[6, 17, 30, 41, 54, 65],
[7, 16, 31, 40, 55, 64],
[8, 15, 32, 39, 56, 63],
[9, 14, 33, 38, 57, 62],
[10, 13, 34, 37, 58, 61],
[11, 12, 35, 36, 59, 60]])
elif numcells == 96:
stdpl=np.array([[0, 23, 24, 47, 48, 71, 72, 95],
[1, 22, 25, 46, 49, 70, 73, 94],
[2, 21, 26, 45, 50, 69, 74, 93],
[3, 20, 27, 44, 51, 68, 75, 92],
[4, 19, 28, 43, 52, 67, 76, 91],
[5, 18, 29, 42, 53, 66, 77, 90],
[6, 17, 30, 41, 54, 65, 78, 89],
[7, 16, 31, 40, 55, 64, 79, 88],
[8, 15, 32, 39, 56, 63, 80, 87],
[9, 14, 33, 38, 57, 62, 81, 86],
[10, 13, 34, 37, 58, 61, 82, 85],
[11, 12, 35, 36, 59, 60, 83, 84]])
else:
print("Error. Only 72 and 96 cells modules supported at the moment. Change numcells to either of this options!")
return
if portraitorlandscape == 'landscape':
stdpl = stdpl.transpose()
elif portraitorlandscape != 'portrait':
print("Error. portraitorlandscape variable must either be 'landscape' or 'portrait'")
return
cellsx = len(stdpl[1]); cellsy = len(stdpl)
return stdpl, cellsx, cellsy
def calculatePVMismatch(pvsys, stdpl, cellsx, cellsy, Gpoat):
r''' calls PVMismatch with all the pre-generated values on bifacial_radiance
Example:
PowerAveraged, PowerDetailed = def calculatePVMismatch(pvsys, stdpl, cellsx, cellsy, Gpoat)
'''
import numpy as np
if np.mean(Gpoat) < 0.001:
PowerAveraged = 0
PowerDetailed = 0
else:
# makes the system # 1 module, in portrait mode.
G=np.array([Gpoat]).transpose()
H = np.ones([1,cellsx])
array_det = np.dot(G,H)
array_avg = np.ones([cellsy,cellsx])*np.mean(Gpoat)
# ACtually do calculations
pvsys.setSuns({0: {0: [array_avg, stdpl]}})
PowerAveraged=pvsys.Pmp
pvsys.setSuns({0: {0: [array_det, stdpl]}})
PowerDetailed=pvsys.Pmp
return PowerAveraged, PowerDetailed
def mad_fn(data):
'''
Mean average deviation calculation for mismatch purposes.
Parameters
----------
data : np.ndarray
Gtotal irradiance measurements.
Returns
-------
scalar : return MAD / Average for a 1D array
Equation: 1/(n^2*Gavg)*Sum Sum (abs(G_i - G_j))
## Note: starting with Pandas 1.0.0 this function will not work on Series objects.
'''
import numpy as np
import pandas as pd
# Pandas returns a notimplemented error if this is a series.
if type(data) == pd.Series:
data = data.to_numpy()
return (np.abs(np.subtract.outer(data,data)).sum()/float(data.__len__())**2 / np.mean(data))*100
[docs]def analysisIrradianceandPowerMismatch(testfolder, writefiletitle, portraitorlandscape, bififactor, numcells=72, downsamplingmethod='byCenter'):
r'''
Use this when sensorsy calculated with bifacial_radiance > cellsy
Reads and calculates power output and mismatch for each file in the
testfolder where all the bifacial_radiance irradiance results .csv are saved.
First load each file, cleans it and resamples it to the numsensors set in this function,
and then calculates irradiance mismatch and PVMismatch power output for averaged, minimum,
or detailed irradiances on each cell for the cases of A) only 12 or 8 downsmaples values are
considered (at the center of each cell), and B) 12 or 8 values are obtained from averaging
all the irradiances falling in the area of the cell (No edges or inter-cell spacing are considered
at this moment). Then it saves all the A and B irradiances, as well as the cleaned/resampled
front and rear irradiances.
Ideally sensorsy in the read data is >> 12 to give results for the irradiance mismatch in the cell.
Also ideally n
Parameters
----------
testfolder: folder containing output .csv files for bifacial_radiance
writefiletitle: .csv title where the output results will be saved.
portraitorlandscape: 'portrait' or 'landscape', for PVMismatch input
which defines the electrical interconnects inside the module.
bififactor: bifaciality factor of the module. Max 1.0. ALL Rear irradiance values saved include the bifi-factor.
downsampling method: 1 - 'byCenter' - 2 - 'byAverage'
Example:
# User information.
import bifacial_radiance
testfolder=r'C:\Users\sayala\Documents\HPC_Scratch\EUPVSEC\HPC Tracking Results\RICHMOND\Bifacial_Radiance Results\PVPMC_0\results'
writefiletitle= r'C:\Users\sayala\Documents\HPC_Scratch\EUPVSEC\HPC Tracking Results\RICHMOND\Bifacial_Radiance Results\PVPMC_0\test_df.csv'
sensorsy=100
portraitorlandscape = 'portrait'
analysis.analysisIrradianceandPowerMismatch(testfolder, writefiletitle, portraitorlandscape, bififactor=1.0, numcells=72)
'''
from bifacial_radiance import load
import os, glob
import pandas as pd
# Default variables
numpanels=1 # 1 at the moment, necessary for the cleaning routine.
automatic=True
#loadandclean
# testfolder = r'C:\Users\sayala\Documents\HPC_Scratch\EUPVSEC\PinPV_Bifacial_Radiance_Runs\HPCResults\df4_FixedTilt\FixedTilt_Cairo_C_0.15\results'
filelist = sorted(os.listdir(testfolder))
#filelist = sorted(glob.glob(os.path.join('testfolder','*.csv')))
print('{} files in the directory'.format(filelist.__len__()))
# Check number of sensors on data.
temp = load.read1Result(os.path.join(testfolder,filelist[0]))
sensorsy = len(temp)
# Setup PVMismatch parameters
stdpl, cellsx, cellsy = _setupforPVMismatch(portraitorlandscape=portraitorlandscape, sensorsy=sensorsy, numcells=numcells)
F=pd.DataFrame()
B=pd.DataFrame()
for z in range(0, filelist.__len__()):
data=load.read1Result(os.path.join(testfolder,filelist[z]))
[frontres, backres] = load.deepcleanResult(data, sensorsy=sensorsy, numpanels=numpanels, automatic=automatic)
F[filelist[z]]=frontres
B[filelist[z]]=backres
B = B*bififactor
# Downsample routines:
if sensorsy > cellsy:
if downsamplingmethod == 'byCenter':
print("Sensors y > cellsy; Downsampling data by finding CellCenter method")
F = _sensorsdownsampletocellbyCenter(F, cellsy)
B = _sensorsdownsampletocellbyCenter(B, cellsy)
elif downsamplingmethod == 'byAverage':
print("Sensors y > cellsy; Downsampling data by Averaging data into Cells method")
F = _sensorsdownsampletocellsbyAverage(F, cellsy)
B = _sensorsdownsampletocellsbyAverage(B, cellsy)
else:
print ("Sensors y > cellsy for your module. Select a proper downsampling method ('byCenter', or 'byAverage')")
return
elif sensorsy < cellsy:
print("Sensors y < cellsy; Upsampling data by Interpolation")
F = _sensorupsampletocellsbyInterpolation(F, cellsy)
B = _sensorupsampletocellsbyInterpolation(B, cellsy)
elif sensorsy == cellsy:
print ("Same number of sensorsy and cellsy for your module.")
F = F
B = B
# Calculate POATs
Poat = F+B
# Define arrays to fill in:
Pavg_all=[]; Pdet_all=[]
Pavg_front_all=[]; Pdet_front_all=[]
colkeys = F.keys()
import pvmismatch
if cellsx*cellsy == 72:
cell_pos = pvmismatch.pvmismatch_lib.pvmodule.STD72
elif cellsx*cellsy == 96:
cell_pos = pvmismatch.pvmismatch_lib.pvmodule.STD96
else:
print("Error. Only 72 and 96 cells modules supported at the moment. Change numcells to either of this options!")
return
pvmod=pvmismatch.pvmismatch_lib.pvmodule.PVmodule(cell_pos=cell_pos)
pvsys = pvmismatch.pvsystem.PVsystem(numberStrs=1, numberMods=1, pvmods=pvmod)
# Calculate powers for each hour:
for i in range(0,len(colkeys)):
Pavg, Pdet = calculatePVMismatch(pvsys = pvsys, stdpl=stdpl, cellsx=cellsx, cellsy=cellsy, Gpoat=list(Poat[colkeys[i]]/1000))
Pavg_front, Pdet_front = calculatePVMismatch(pvsys = pvsys, stdpl = stdpl, cellsx = cellsx, cellsy = cellsy, Gpoat= list(F[colkeys[i]]/1000))
Pavg_all.append(Pavg)
Pdet_all.append(Pdet)
Pavg_front_all.append(Pavg_front)
Pdet_front_all.append(Pdet_front)
## Rename Rows and save dataframe and outputs.
F.index='FrontIrradiance_cell_'+F.index.astype(str)
B.index='BackIrradiance_cell_'+B.index.astype(str)
Poat.index='POAT_Irradiance_cell_'+Poat.index.astype(str)
## Transpose
F = F.T
B = B.T
Poat = Poat.T
# Statistics Calculatoins
dfst=pd.DataFrame()
dfst['MAD/G_Total'] = mad_fn(Poat.T)
dfst['Front_MAD/G_Total'] = mad_fn(F.T)
dfst['MAD/G_Total**2'] = dfst['MAD/G_Total']**2
dfst['Front_MAD/G_Total**2'] = dfst['Front_MAD/G_Total']**2
dfst['poat'] = Poat.mean(axis=1)
dfst['gfront'] = F.mean(axis=1)
dfst['grear'] = B.mean(axis=1)
dfst['bifi_ratio'] = dfst['grear']/dfst['gfront']
dfst['stdev'] = Poat.std(axis=1)/ dfst['poat']
dfst.index=Poat.index.astype(str)
# Power Calculations/Saving
Pout=pd.DataFrame()
Pout['Pavg']=Pavg_all
Pout['Pdet']=Pdet_all
Pout['Front_Pavg']=Pavg_front_all
Pout['Front_Pdet']=Pdet_front_all
Pout['Mismatch_rel'] = 100-(Pout['Pdet']*100/Pout['Pavg'])
Pout['Front_Mismatch_rel'] = 100-(Pout['Front_Pdet']*100/Pout['Front_Pavg'])
Pout.index=Poat.index.astype(str)
## Save CSV
df_all = pd.concat([Pout,dfst,Poat,F,B],axis=1)
df_all.to_csv(writefiletitle)
print("Saved Results to ", writefiletitle)