https://github.com/chill90/BoloCalc
Tip revision: 81e6e0c72bd4795af883db7fec9c42317c616e53 authored by Charlie Hill on 10 December 2018, 23:36:12 UTC
Fixed bug with edges of band when custom band file is passed and updated the user manual
Fixed bug with edges of band when custom band file is passed and updated the user manual
Tip revision: 81e6e0c
display.py
import numpy as np
import collections as cl
import os
import src.physics as ph
import src.units as un
class Display:
def __init__(self, log, calcs):
#Store passed parameters
self.log = log
self.__calcs = calcs
#Create physics class for calculations
self.__ph = ph.Physics()
#Get experiment info
self.exp = self.__calcs[0].exp
snsmeans = [calc.snsmeans for calc in calcs]
snsstds = [calc.snsstds for calc in calcs]
optmeans = [calc.optmeans for calc in calcs]
optstds = [calc.optstds for calc in calcs]
self.snsmeans = [[[(np.mean([snsmeans[m][i][j][k] for m in range(len(snsmeans))], axis=0) ).tolist() for k in range(len(snsmeans[0][i][j]))] for j in range(len(snsmeans[0][i]))] for i in range(len(snsmeans[0]))]
self.snsstds = [[[(np.mean([snsstds[m][i][j][k] for m in range(len(snsstds))], axis=0) + np.std([snsmeans[m][i][j][k] for m in range(len(snsmeans))], axis=0)).tolist() for k in range(len(snsstds[0][i][j]))] for j in range(len(snsstds[0][i]))] for i in range(len(snsstds[0] ))]
self.optmeans = [[[(np.mean([optmeans[m][i][j][k] for m in range(len(optmeans))], axis=0) ).tolist() for k in range(len(optmeans[0][i][j]))] for j in range(len(optmeans[0][i]))] for i in range(len(optmeans[0]))]
self.optstds = [[[(np.mean([optstds[m][i][j][k] for m in range(len(optstds))], axis=0) + np.std([optmeans[m][i][j][k] for m in range(len(optmeans))], axis=0)).tolist() for k in range(len(optstds[0][i][j]))] for j in range(len(optstds[0][i]))] for i in range(len(optstds[0] ))]
#Dictionaries to hold values for look-up
self.dict = cl.OrderedDict({})
self.name = []
self.freq = []; self.freqStd = []
self.fbw = []; self.fbwStd = []
self.numDet = []
self.netArr = []; self.netArrStd = []
self.sens = []; self.sensStd = []
self.ms = []; self.msStd = []
#Table column titles for camera files
self.titleStrC = str("%-5s | %-15s | %-15s | %-7s | %-15s | %-15s | %-15s | %-15s | %-15s | %-15s | %-17s | %-15s | %-21s | %-15s\n"
% ("Chan", "Frequency", "Frac Bandwidth", "Num Det", "Stop Efficiency", "Optical Power", "Photon NEP", "Bolometer NEP", "Readout NEP", "Detector NEP", "Detector NET", "Array NET", "Mapping Speed", "Map Depth"))
self.unitStrC = str("%-5s | %-15s | %-15s | %-7s | %-15s | %-15s | %-15s | %-15s | %-15s | %-15s | %-17s | %-15s | %-21s | %-15s\n"
% ("", "[GHz]", "", "", "[%]", "[pW]", "[aW/rtHz]", "[aW/rtHz]", "[aW/rtHz]", "[aW/rtHz]", "[uK-rtSec]", "[uK-rtSec]", "[(uK^2 s)^-1]", "[uK-arcmin]"))
self.breakStrC = "-"*240+"\n"
#Table column titles for telescope and experiment files
self.titleStrTE = str("%-5s | %-15s | %-15s | %-7s | %-15s | %-21s | %-15s\n"
% ("Chan", "Frequency", "Frac Bandwidth", "Num Det", "Array NET", "Mapping Speed", "Map Depth"))
self.unitStrTE = str("%-5s | %-15s | %-15s | %-7s | %-15s | %-21s | %-15s\n"
% ("", "[GHz]", "", "", "[uK-rtSec]", "[(uK^2 s)^-1]", "[uK-arcmin]"))
self.breakStrTE = "-"*110+"\n"
#Generate sensitivities
def sensitivity(self, genTables=True):
#Full experiment
experiment = self.exp
if genTables:
fE = open(os.path.join(experiment.dir, 'sensitivity.txt'), 'w')
fE.write(self.titleStrTE)
fE.write(self.breakStrTE)
fE.write(self.unitStrTE)
fE.write(self.breakStrTE)
#Loop over telescopes
for i in range(len(experiment.telescopes)):
#Telescope dictionary
dictT = cl.OrderedDict({})
nameT = []
freqT = []; freqStdT = []
fbwT = []; fbwStdT = []
numDetT = []
netArrT = []; netArrStdT = []
sensT = []; sensStdT = []
msT = []; msStdT = []
telescope = list(experiment.telescopes.values())[i]
if genTables:
fT = open(os.path.join(telescope.dir, 'sensitivity.txt'), "w")
fT.write(self.titleStrTE)
fT.write(self.breakStrTE)
fT.write(self.unitStrTE)
fT.write(self.breakStrTE)
#Loop over cameras
for j in range(len(telescope.cameras)):
#Camera dictionary
dictC = cl.OrderedDict({})
nameC = []
freqC = []; freqStdC = []
fbwC = []; fbwStdC = []
numDetC = []
netArrC = []; netArrStdC = []
sensC = []; sensStdC = []
msC = []; msStdC = []
camera = list(telescope.cameras.values())[j]
if genTables:
fC = open(os.path.join(camera.dir, 'sensitivity.txt'), 'w')
fC.write(self.titleStrC)
fC.write(self.breakStrC)
fC.write(self.unitStrC)
fC.write(self.breakStrC)
#Loop over channels
for k in range(len(camera.channels)):
#Channel dictionary
dictCh = cl.OrderedDict({})
ch = list(camera.channels.values())[k]
#Write channel values to camera file
if genTables:
printStr = str("%-5s | %-5.1f +/- %-5.1f | %-5.3f +/- %-5.3f | %-7d | %-5.2f +/- %-5.2f | %-5.2f +/- %-5.2f | %-5.2f +/- %-5.2f | %-5.2f +/- %-5.2f | %-5.2f +/- %-5.2f | %-5.2f +/- %-5.2f | %-6.1f +/- %-6.1f | %-5.2f +/- %-5.2f | %-8.2e +/- %-8.2e | %-5.1f +/- %-5.1f\n"
% (ch.name,
ch.detectorDict['Band Center'].getAvg()*un.HzToGHz, ch.detectorDict['Band Center'].getStd()*un.HzToGHz,
ch.detectorDict['Fractional BW'].getAvg(), ch.detectorDict['Fractional BW'].getStd(),
ch.numDet,
self.snsmeans[i][j][k][0]*un.decToPct, self.snsstds[i][j][k][0]*un.decToPct,
self.snsmeans[i][j][k][1]*un.WtoPw, self.snsstds[i][j][k][1]*un.WtoPw,
self.snsmeans[i][j][k][2]*un.WrtHzToaWrtHz, self.snsstds[i][j][k][2]*un.WrtHzToaWrtHz,
self.snsmeans[i][j][k][3]*un.WrtHzToaWrtHz, self.snsstds[i][j][k][3]*un.WrtHzToaWrtHz,
self.snsmeans[i][j][k][4]*un.WrtHzToaWrtHz, self.snsstds[i][j][k][4]*un.WrtHzToaWrtHz,
self.snsmeans[i][j][k][5]*un.WrtHzToaWrtHz, self.snsstds[i][j][k][5]*un.WrtHzToaWrtHz,
self.snsmeans[i][j][k][6]*un.KTouK, self.snsstds[i][j][k][6]*un.KTouK,
self.snsmeans[i][j][k][7]*un.KTouK, self.snsstds[i][j][k][7]*un.KTouK,
self.snsmeans[i][j][k][8]*un.uK2ToK2, self.__ifZero(self.snsmeans[i][j][k][8], self.snsstds[i][j][k][8])*un.uK2ToK2,
self.snsmeans[i][j][k][9]*un.KTouK, self.snsstds[i][j][k][9]*un.KTouK))
fC.write(printStr)
fC.write(self.breakStrC)
#Store the channel values for dictionary lookup
dictCh = cl.OrderedDict({'Frequency': [ch.detectorDict['Band Center'].getAvg()*un.HzToGHz, ch.detectorDict['Band Center'].getStd()*un.HzToGHz],
'Frac Bandwidth': [ch.detectorDict['Fractional BW'].getAvg(), ch.detectorDict['Fractional BW'].getStd()],
'Num Det': [ch.numDet, 0.],
'Stop Efficiency': [self.snsmeans[i][j][k][0]*un.decToPct, self.snsstds[i][j][k][0]*un.decToPct],
'Optical Power': [self.snsmeans[i][j][k][1]*un.WtoPw, self.snsstds[i][j][k][1]*un.WtoPw],
'Photon NEP': [self.snsmeans[i][j][k][2]*un.WrtHzToaWrtHz, self.snsstds[i][j][k][2]*un.WrtHzToaWrtHz],
'Bolometer NEP': [self.snsmeans[i][j][k][3]*un.WrtHzToaWrtHz, self.snsstds[i][j][k][3]*un.WrtHzToaWrtHz],
'Readout NEP': [self.snsmeans[i][j][k][4]*un.WrtHzToaWrtHz, self.snsstds[i][j][k][4]*un.WrtHzToaWrtHz],
'Detector NEP': [self.snsmeans[i][j][k][5]*un.WrtHzToaWrtHz, self.snsstds[i][j][k][5]*un.WrtHzToaWrtHz],
'Detector NET': [self.snsmeans[i][j][k][6]*un.KTouK, self.snsstds[i][j][k][6]*un.KTouK],
'Array NET': [self.snsmeans[i][j][k][7]*un.KTouK, self.snsstds[i][j][k][7]*un.KTouK],
'Mapping Speed': [self.snsmeans[i][j][k][8]*un.uK2ToK2, self.__ifZero(self.snsmeans[i][j][k][8], self.snsstds[i][j][k][8])*un.uK2ToK2],
'Map Depth': [self.snsmeans[i][j][k][9]*un.KTouK, self.snsstds[i][j][k][9]*un.KTouK]})
#Store channel values in camera arrays for averaging later
nameC.append(ch.name)
freqC.append(ch.detectorDict['Band Center'].getAvg()); freqStdC.append(ch.detectorDict['Band Center'].getStd())
fbwC.append( ch.detectorDict['Fractional BW'].getAvg()); fbwStdC.append( ch.detectorDict['Fractional BW'].getStd())
numDetC.append(ch.numDet)
netArrC.append( self.snsmeans[i][j][k][7]); netArrStdC.append(self.snsstds[i][j][k][7])
msC.append( self.snsmeans[i][j][k][8]); msStdC.append( self.__ifZero(self.snsmeans[i][j][k][8], self.snsstds[i][j][k][8]))
sensC.append( self.snsmeans[i][j][k][9]); sensStdC.append( self.snsstds[i][j][k][9])
#Store channel dictionary in camera dictionary
dictC[ch.name] = dictCh
#Write cumulative sensitivity for camera
if genTables:
printStr = str("%-5s | %-33s | %-7d | %-125s | %-5.2f +/- %-5.2f | %-8.2e +/- %-8.2e | %-5.1f +/- %-5.1f\n"
% ('Total', '', sum(numDetC), '',
self.__ph.invVar(netArrC)*un.KTouK, self.__ph.invVar(netArrStdC)*un.KTouK,
sum(msC)*un.uK2ToK2, self.__ifZero(sum(msC), sum(msStdC))*un.uK2ToK2,
self.__ph.invVar(sensC)*un.KTouK, self.__ph.invVar(sensStdC)*un.KTouK))
fC.write(printStr)
fC.close()
#Store camera sensitivities for lookup
dictT[camera.name] = dictC
#Store camera parameters in telescope arrays
nameT.append( nameC)
freqT.append( freqC); freqStdT.append( freqStdC)
fbwT.append( fbwC); fbwStdT.append( fbwStdC)
numDetT.append(numDetC)
netArrT.append(netArrC); netArrStdT.append(netArrStdC)
msT.append( msC); msStdT.append( msStdC )
sensT.append( sensC); sensStdT.append( sensStdC )
#Store camera dictionary in telescope dictionary
dictT[camera.name] = dictC
#Combine all cameras in telescope
inds = np.argsort(np.array(self.__flatten(freqT)))
nameT = np.array(self.__flatten(nameT))[inds]
freqT = np.array(self.__flatten(freqT))[inds]; freqStdT = np.array(self.__flatten(freqStdT))[inds]
fbwT = np.array(self.__flatten(fbwT))[inds]; fbwStdT = np.array(self.__flatten(fbwStdT))[inds]
numDetT = np.array(self.__flatten(numDetT))[inds]
netArrT = np.array(self.__flatten(netArrT))[inds]; netArrStdT = np.array(self.__flatten(netArrStdT))[inds]
msT = np.array(self.__flatten(msT))[inds]; msStdT = np.array(self.__flatten(msStdT))[inds]
sensT = np.array(self.__flatten(sensT))[inds]; sensStdT = np.array(self.__flatten(sensStdT))[inds]
#Combine repeat channels in this telescope
for m in range(len(nameT)):
if m >= len(nameT): continue
for n in range(m, len(nameT)):
if m == n or n >= len(nameT):
continue
if nameT[m] == nameT[n]:
freqT[m] = np.mean([freqT[m], freqT[n]])
freqStdT[m] = np.std([freqT[m], freqT[n]]) + np.mean([freqStdT[m], freqStdT[n]])
fbwT[m] = np.mean([fbwT[m], fbwT[n]])
fbwStdT[m] = np.std([fbwT[m], fbwT[n]]) + np.mean([fbwStdT[m], fbwStdT[n]])
numDetT[m] += numDetT[n]
netArrTv = self.__ph.invVar([netArrT[m], netArrT[n]])
netArrStdTv = np.mean([netArrStdT[m], netArrStdT[n]])
sensTv = self.__ph.invVar([sensT[m], sensT[n]])
sensStdTv = np.mean([sensStdT[m], sensStdT[n]])
msTv = 1./(np.power(netArrTv, 2.))
msStdTv = np.mean([msStdT[m]*(msT/float(msT[m])) + msStdT[n]*(msT/float(msT[n]))])
if msStdTv < (1.e-3)*msTv: msStdTv = 0
netArrT[m] = netArrTv
netArrStdT[m] = netArrStdTv
sensT[m] = sensTv
sensStdT[m] = sensStdTv
msT[m] = msTv
msStdT[m] = msStdTv
nameT = np.delete(nameT, n)
freqT = np.delete(freqT, n)
freqStdT = np.delete(freqStdT, n)
fbwT = np.delete(fbwT, n)
fbwStdT = np.delete(fbwStdT, n)
numDetT = np.delete(numDetT, n)
netArrT = np.delete(netArrT, n)
netArrStdT = np.delete(netArrStdT, n)
sensT = np.delete(sensT, n)
sensStdT = np.delete(sensStdT, n)
msT = np.delete(msT, n)
msStdT = np.delete(msStdT, n)
#Write combined telescope sensitivities for each channel
if genTables:
printStr = ("%-5s | %-5.1f +/- %-5.1f | %-5.3f +/- %-5.3f | %-7d | %-5.2f +/- %-5.2f | %-8.2e +/- %-8.2e | %-5.1f +/- %-5.1f\n"
% (nameT[m],
freqT[m]*un.HzToGHz, freqStdT[m]*un.HzToGHz,
fbwT[m], fbwStdT[m],
numDetT[m],
netArrT[m]*un.KTouK, netArrStdT[m]*un.KTouK,
msT[m]*un.uK2ToK2, self.__ifZero(msT[m], msStdT[m])*un.uK2ToK2,
sensT[m]*un.KTouK, sensStdT[m]*un.KTouK))
fT.write(printStr)
fT.write(self.breakStrTE)
#Store telescope dictionary in experiment dictionary
self.dict[telescope.name] = dictT
#Store telescope sensitivities in experiment arrays
self.name.append(nameT)
self.freq.append(freqT); self.freqStd.append(freqStdT)
self.fbw.append(fbwT); self.fbwStd.append(fbwStdT)
self.numDet.append(numDetT)
self.netArr.append(netArrT); self.netArrStd.append(netArrStdT)
self.ms.append(msT); self.msStd.append(msStdT)
self.sens.append(sensT); self.sensStd.append(sensStdT)
#Print the total sensitivity for the telescopes
if genTables:
printStr = ("%-5s | %-33s | %-7d | %-5.2f +/- %-5.2f | %-8.2e +/- %-8.2e | %-5.1f +/- %-5.1f\n"
% ('Total', '', sum(numDetT),
self.__ph.invVar(netArrT)*un.KTouK, self.__ph.invVar(netArrStdT)*un.KTouK,
sum(msT)*un.uK2ToK2, self.__ifZero(sum(msT), sum(msStdT))*un.uK2ToK2,
self.__ph.invVar(sensT)*un.KTouK, self.__ph.invVar(sensStdT)*un.KTouK))
fT.write(printStr)
fT.close()
#Combine all telescopes in experiment
inds = np.argsort(np.array(self.__flatten(self.freq)))
self.name = np.array(self.__flatten(self.name))[inds]
self.freq = np.array(self.__flatten(self.freq))[inds]; self.freqStd = np.array(self.__flatten(self.freqStd))[inds]
self.fbw = np.array(self.__flatten(self.fbw))[inds]; self.fbwStd = np.array(self.__flatten(self.fbwStd))[inds]
self.numDet = np.array(self.__flatten(self.numDet))[inds]
self.netArr = np.array(self.__flatten(self.netArr))[inds]; self.netArrStd = np.array(self.__flatten(self.netArrStd))[inds]
self.ms = np.array(self.__flatten(self.ms))[inds]; self.msStd = np.array(self.__flatten(self.msStd))[inds]
self.sens = np.array(self.__flatten(self.sens))[inds]; self.sensStd = np.array(self.__flatten(self.sensStd))[inds]
#Combine repeat frequencies in this experiment
for m in range(len(self.name)):
if m >= len(self.name): continue
for n in range(m, len(self.name)):
if m == n or n >= len(self.name):
continue
if self.name[m] == self.name[n]:
self.freq[m] = np.mean([self.freq[m], self.freq[n]])
self.freqStd[m] = np.std([self.freq[m], self.freq[n]]) + np.mean([self.freqStd[m], self.freqStd[n]])
self.fbw[m] = np.mean([self.fbw[m], self.fbw[n]])
self.fbwStd[m] = np.std([self.fbw[m], self.fbw[n]]) + np.mean([self.fbwStd[m], self.fbwStd[n]])
self.numDet[m] += self.numDet[n]
netArr = self.__ph.invVar([self.netArr[m], self.netArr[n]])
netArrStd = np.mean([self.netArrStd[m], self.netArrStd[n]])
sens = self.__ph.invVar([self.sens[m], self.sens[n]])
sensStd = np.mean([self.sensStd[m], self.sensStd[n]])
ms = 1./float(np.power(netArr, 2.))
msStd = np.mean([self.msStd[m]*(ms/float(self.ms[m])) + self.msStd[n]*(ms/float(self.ms[n]))])
if msStd < (1.e-3)*ms: msStd = 0
self.netArr[m] = netArr
self.netArrStd[m] = netArrStd
self.sens[m] = sens
self.sensStd[m] = sensStd
self.ms[m] = ms
self.msStd[m] = msStd
self.name = np.delete(self.name, n)
self.freq = np.delete(self.freq, n)
self.freqStd = np.delete(self.freqStd, n)
self.fbw = np.delete(self.fbw, n)
self.fbwStd = np.delete(self.fbwStd, n)
self.numDet = np.delete(self.numDet, n)
self.netArr = np.delete(self.netArr, n)
self.netArrStd = np.delete(self.netArrStd, n)
self.sens = np.delete(self.sens, n)
self.sensStd = np.delete(self.sensStd, n)
self.ms = np.delete(self.ms, n)
self.msStd = np.delete(self.msStd, n)
#Write combined experiment sensitivities for each channel
if genTables:
printStr = ("%-5s | %-5.1f +/- %-5.1f | %-5.3f +/- %-5.3f | %-7d | %-5.2f +/- %-5.2f | %-8.2e +/- %-8.2e | %-5.1f +/- %-5.1f\n"
% (self.name[m],
self.freq[m]*un.HzToGHz, self.freqStd[m]*un.HzToGHz,
self.fbw[m], self.fbwStd[m],
self.numDet[m],
self.netArr[m]*un.KTouK, self.netArrStd[m]*un.KTouK,
self.ms[m]*un.uK2ToK2, self.__ifZero(self.ms[m], self.msStd[m])*un.uK2ToK2,
self.sens[m]*un.KTouK, self.sensStd[m]*un.KTouK))
fE.write(printStr)
fE.write(self.breakStrTE)
#Print the total sensitivity for the telescopes
if genTables:
printStr = ("%-5s | %-33s | %-7d | %-5.2f +/- %-5.2f | %-8.2e +/- %-8.2e | %-5.1f +/- %-5.1f\n"
% ('Total', '', sum(self.numDet),
self.__ph.invVar(self.netArr)*un.KTouK, self.__ph.invVar(self.netArrStd)*un.KTouK,
sum(self.ms)*un.uK2ToK2, self.__ifZero(sum(self.ms), sum(self.msStd))*un.uK2ToK2,
self.__ph.invVar(self.sens)*un.KTouK, self.__ph.invVar(self.sensStd)*un.KTouK))
fE.write(printStr)
fE.close()
return
#Generate opticalPower.txt files
def opticalPowerTables(self):
title = "| %-15s | %-15s | %-15s | %-15s |\n" % ("Element", "Power from Sky", "Power to Detect", "Cumulative Eff")
units = "| %-15s | %-15s | %-15s | %-15s |\n" % ("", "[pW]", "[pW]", "" )
row = ("-"*73)+"\n"
for i in range(len(self.exp.telescopes)):
telescope = list(self.exp.telescopes.values())[i]
for j in range(len(telescope.cameras)):
camera = list(telescope.cameras.values())[j]
fi = open(os.path.join(camera.dir, 'opticalPower.txt'), 'w')
for k in range(len(camera.channels)):
ch = list(camera.channels.values())[k]
bandName = ch.bandID
bandTitle = ("*"*24)+(" %11s %-12s " % (camera.name, bandName))+("*"*23)+"\n"
fi.write(bandTitle)
fi.write(row)
fi.write(title)
fi.write(row)
fi.write(units)
fi.write(row)
for m in range(len(ch.elem[0][0])):
elemName = ch.elem[0][0][m]
values = ("| %-15s | %-5.3f +/- %-5.3f | %-5.3f +/- %-5.3f | %-5.3f +/- %-5.3f |\n"
% (elemName,
self.optmeans[i][j][k][0][m]*un.WtoPw, self.optstds[i][j][k][0][m]*un.WtoPw,
self.optmeans[i][j][k][1][m]*un.WtoPw, self.optstds[i][j][k][1][m]*un.WtoPw,
self.optmeans[i][j][k][2][m], self.optstds[i][j][k][2][m]))
fi.write(values)
fi.write(row)
fi.write("\n\n")
fi.close()
#Function to flatten nested lists
def __flatten(self, arr):
return [i for sarr in arr for i in sarr]
#Function to force a zero for small values written in scientific notation
def __ifZero(self, avg, std):
if std < avg*1.e-3: return 0
else: return std