539 lines
28 KiB
Python
539 lines
28 KiB
Python
|
|
import os
|
|
import numpy as np
|
|
from ROOT import TH1D, TH2D, TCanvas, TF1, TFile
|
|
from multiprocessing import Pool
|
|
from array import array
|
|
import h5py
|
|
import aare
|
|
|
|
_cfg = {} ### global config
|
|
_aduToKev3DMap = None ### global caliFile
|
|
_pedestalAduFrame = None ### global pedestalAduFrame
|
|
_noiseEneFrame = None ### global noiseEneFrame
|
|
nChunks = 16
|
|
clusterSize3Photon = 9
|
|
clusterSize2Photon = 7
|
|
clusterSize1Photon = 3
|
|
|
|
def init(cfg):
|
|
global _cfg
|
|
global _aduToKev3DMap
|
|
_cfg = cfg
|
|
NX, NY = cfg['NX'], cfg['NY']
|
|
St_x, St_y = cfg.get('StCorner', [0, 0]) ### with default corner at (0, 0)
|
|
_aduToKev3DMap = np.load(cfg['caliFileName'])[:, St_y:St_y+NY, St_x:St_x+NX]
|
|
Roi = cfg['Roi']
|
|
global nChunks
|
|
nChunks = _cfg.get('NChunks', 16)
|
|
|
|
def convertAduFrameToEnergyFrame(aduFrame):
|
|
if _aduToKev3DMap is None:
|
|
return aduFrame
|
|
NX, NY = _cfg['NX'], _cfg['NY']
|
|
if _aduToKev3DMap.shape[0] == 1640:
|
|
idxFrame = (np.abs(aduFrame//10)).astype(np.int32)
|
|
idxFrame[idxFrame > _aduToKev3DMap.shape[0]-2] = _aduToKev3DMap.shape[0]-2
|
|
NY, NX = _aduToKev3DMap.shape[1:3]
|
|
_energyFrame0 = _aduToKev3DMap[idxFrame, np.arange(NY).reshape(-1, 1), np.arange(NX)]
|
|
_energyFrame1 = _aduToKev3DMap[idxFrame+1, np.arange(NY).reshape(-1, 1), np.arange(NX)]
|
|
energyFrame = _energyFrame0 + (_energyFrame1 - _energyFrame0)/10 * (np.abs(aduFrame) - idxFrame*10)
|
|
energyFrame *= np.sign(aduFrame)
|
|
|
|
else:
|
|
aduPerBin = 10
|
|
nExtraBins = 1000 // aduPerBin
|
|
idxFrame = (aduFrame//aduPerBin).astype(np.int32) + nExtraBins
|
|
idxFrame[idxFrame > _aduToKev3DMap.shape[0]-2] = _aduToKev3DMap.shape[0]-2
|
|
NY, NX = _aduToKev3DMap.shape[1:3]
|
|
_energyFrame0 = _aduToKev3DMap[idxFrame, np.arange(NY).reshape(-1, 1), np.arange(NX)]
|
|
_energyFrame1 = _aduToKev3DMap[idxFrame+1, np.arange(NY).reshape(-1, 1), np.arange(NX)]
|
|
energyFrame = _energyFrame0 + (_energyFrame1 - _energyFrame0)/aduPerBin * (aduFrame - (idxFrame-nExtraBins)*aduPerBin)
|
|
if 'energyScalingFactor' in _cfg:
|
|
energyFrame *= _cfg['energyScalingFactor']
|
|
return energyFrame
|
|
|
|
def bookHistograms(energy, suffix='', energyBinWidth=0.1, isMC=False):
|
|
histMaxEnergy = energy * 5.5
|
|
nEnergyBins = int(histMaxEnergy // energyBinWidth)
|
|
roi_x0, roi_x1, roi_y0, roi_y1 = _cfg['Roi'][0], _cfg['Roi'][1], _cfg['Roi'][2], _cfg['Roi'][3]
|
|
roi_width = roi_x1 - roi_x0
|
|
roi_height = roi_y1 - roi_y0
|
|
interpolationBins = 10
|
|
|
|
histograms = {}
|
|
histograms['h1_ClusterEnergy'] = TH1D(
|
|
f'h1_ClusterEnergy{suffix}', f'h1_ClusterEnergy{suffix}', nEnergyBins, -1, histMaxEnergy
|
|
)
|
|
histograms['h1_ClusterEnergy'].SetTitle('Cluster Energy;Energy [keV];Counts')
|
|
|
|
histograms['h1_PixelEnergy'] = TH1D(
|
|
f'h1_PixelEnergy{suffix}', f'h1_PixelEnergy{suffix}', nEnergyBins, -1, histMaxEnergy
|
|
)
|
|
histograms['h1_PixelEnergy'].SetTitle('Pixel Energy;Energy [keV];Counts')
|
|
|
|
histograms['h1_1PhotonClusterSize'] = TH1D(
|
|
f'h1_1PhotonClusterSize{suffix}', f'h1_1PhotonClusterSize{suffix}', 30, 0, 30
|
|
)
|
|
histograms['h1_1PhotonClusterSize'].SetTitle('1-Photon Cluster Size;Cluster Size [pixel];Counts')
|
|
|
|
histograms['h1_1PhotonClusterDiameterX'] = TH1D(
|
|
f'h1_1PhotonClusterDiameterX{suffix}', f'h1_1PhotonClusterDiameterX{suffix}', 10, 0, 10
|
|
)
|
|
histograms['h1_1PhotonClusterDiameterX'].SetTitle('1-Photon Cluster Diameter X;Cluster Diameter X [pixel];Counts')
|
|
|
|
histograms['h1_1PhotonClusterDiameterY'] = TH1D(
|
|
f'h1_1PhotonClusterDiameterY{suffix}', f'h1_1PhotonClusterDiameterY{suffix}', 10, 0, 10
|
|
)
|
|
histograms['h1_1PhotonClusterDiameterY'].SetTitle('1-Photon Cluster Diameter Y;Cluster Diameter Y [pixel];Counts')
|
|
|
|
histograms['h1_1PhotonClusterPixelEnergy'] = TH1D(
|
|
f'h1_1PhotonClusterPixelEnergy{suffix}', f'h1_1PhotonClusterPixelEnergy{suffix}', nEnergyBins, -1, energy*1.5
|
|
)
|
|
histograms['h1_1PhotonClusterPixelEnergy'].SetTitle('1-Photon Cluster Pixel Energy;Energy [keV];Counts')
|
|
|
|
histograms['h1_1PhotonClusterEnergy'] = TH1D(
|
|
f'h1_1PhotonClusterEnergy{suffix}', f'h1_1PhotonClusterEnergy{suffix}', nEnergyBins, -1, energy*1.5
|
|
)
|
|
histograms['h1_1PhotonClusterEnergy'].SetTitle('1-Photon Cluster Energy;Energy [keV];Counts')
|
|
|
|
histograms['h1_1PhotonEta_X'] = TH1D(
|
|
f'h1_1PhotonEta_X{suffix}', f'h1_1PhotonEta_X{suffix}', 100, -0.5, 0.5
|
|
)
|
|
histograms['h1_1PhotonEta_X'].SetTitle('1-Photon Eta X;Eta X;Counts')
|
|
|
|
histograms['h1_1PhotonEta_Y'] = TH1D(
|
|
f'h1_1PhotonEta_Y{suffix}', f'h1_1PhotonEta_Y{suffix}', 100, -0.5, 0.5
|
|
)
|
|
histograms['h1_1PhotonEta_Y'].SetTitle('1-Photon Eta Y;Eta Y;Counts')
|
|
|
|
histograms['h1_2PhotonClusterEnergy'] = TH1D(
|
|
f'h1_2PhotonClusterEnergy{suffix}', f'h1_2PhotonClusterEnergy{suffix}', nEnergyBins, -1, energy*4
|
|
)
|
|
histograms['h1_2PhotonClusterEnergy'].SetTitle('2-Photon Cluster Energy;Energy [keV];Counts')
|
|
|
|
histograms['h1_3PhotonClusterEnergy'] = TH1D(
|
|
f'h1_3PhotonClusterEnergy{suffix}', f'h1_3PhotonClusterEnergy{suffix}', nEnergyBins, -1, energy*6
|
|
)
|
|
histograms['h1_3PhotonClusterEnergy'].SetTitle('3-Photon Cluster Energy;Energy [keV];Counts')
|
|
|
|
histograms['h1_2PhotonClusterSize'] = TH1D(
|
|
f'h1_2PhotonClusterSize{suffix}', f'h1_2PhotonClusterSize{suffix}', 30, 0, 30
|
|
)
|
|
histograms['h1_2PhotonClusterSize'].SetTitle('2-Photon Cluster Size;Cluster Size [pixel];Counts')
|
|
|
|
histograms['h1_3PhotonClusterSize'] = TH1D(
|
|
f'h1_3PhotonClusterSize{suffix}', f'h1_3PhotonClusterSize{suffix}', 30, 0, 30
|
|
)
|
|
histograms['h1_3PhotonClusterSize'].SetTitle('3-Photon Cluster Size;Cluster Size [pixel];Counts')
|
|
|
|
histograms['h1_2PhotonClusterDiameterX'] = TH1D(
|
|
f'h1_2PhotonClusterDiameterX{suffix}', f'h1_2PhotonClusterDiameterX{suffix}', 10, 0, 10
|
|
)
|
|
histograms['h1_2PhotonClusterDiameterX'].SetTitle('2-Photon Cluster Diameter X;Cluster Diameter X [pixel];Counts')
|
|
|
|
histograms['h1_3PhotonClusterDiameterX'] = TH1D(
|
|
f'h1_3PhotonClusterDiameterX{suffix}', f'h1_3PhotonClusterDiameterX{suffix}', 15, 0, 15
|
|
)
|
|
histograms['h1_3PhotonClusterDiameterX'].SetTitle('3-Photon Cluster Diameter X;Cluster Diameter X [pixel];Counts')
|
|
|
|
histograms['h1_2PhotonClusterDiameterY'] = TH1D(
|
|
f'h1_2PhotonClusterDiameterY{suffix}', f'h1_2PhotonClusterDiameterY{suffix}', 10, 0, 10
|
|
)
|
|
histograms['h1_2PhotonClusterDiameterY'].SetTitle('2-Photon Cluster Diameter Y;Cluster Diameter Y [pixel];Counts')
|
|
|
|
histograms['h1_3PhotonClusterDiameterY'] = TH1D(
|
|
f'h1_3PhotonClusterDiameterY{suffix}', f'h1_3PhotonClusterDiameterY{suffix}', 15, 0, 15
|
|
)
|
|
histograms['h1_3PhotonClusterDiameterY'].SetTitle('3-Photon Cluster Diameter Y;Cluster Diameter Y [pixel];Counts')
|
|
|
|
histograms['h1_2PhotonClusterPixelEnergy'] = TH1D(
|
|
f'h1_2PhotonClusterPixelEnergy{suffix}', f'h1_2PhotonClusterPixelEnergy{suffix}', nEnergyBins, -1, energy*2.5
|
|
)
|
|
histograms['h1_2PhotonClusterPixelEnergy'].SetTitle('2-Photon Cluster Pixel Energy;Energy [keV];Counts')
|
|
|
|
histograms['h1_3PhotonClusterPixelEnergy'] = TH1D(
|
|
f'h1_3PhotonClusterPixelEnergy{suffix}', f'h1_3PhotonClusterPixelEnergy{suffix}', nEnergyBins, -1, energy*2.5
|
|
)
|
|
histograms['h1_3PhotonClusterPixelEnergy'].SetTitle('3-Photon Cluster Pixel Energy;Energy [keV];Counts')
|
|
|
|
histograms['h2_SumFrame'] = TH2D(
|
|
f'h2_SumFrame{suffix}', f'h2_SumFrame{suffix}', roi_width, roi_x0, roi_x1, roi_height, roi_y0, roi_y1
|
|
)
|
|
histograms['h2_SumFrame'].SetTitle('Sum Frame;X [pixel];Y [pixel];Energy Sum [keV]')
|
|
|
|
histograms['h2_HitsSumFrame'] = TH2D(
|
|
f'h2_HitsSumFrame{suffix}', f'h2_HitsSumFrame{suffix}', roi_width, roi_x0, roi_x1, roi_height, roi_y0, roi_y1
|
|
)
|
|
histograms['h2_HitsSumFrame'].SetTitle('Hits Sum Frame;X [pixel];Y [pixel];Energy Sum [keV]')
|
|
|
|
histograms['h2_1PhotonSumFrame'] = TH2D(
|
|
f'h2_1PhotonSumFrame{suffix}', f'h2_1PhotonSumFrame{suffix}', roi_width, roi_x0, roi_x1, roi_height, roi_y0, roi_y1
|
|
)
|
|
histograms['h2_1PhotonSumFrame'].SetTitle('1-Photon Hits Sum Frame;X [pixel];Y [pixel];Energy Sum [keV]')
|
|
|
|
histograms['h2_1PhotonSumSample'] = TH2D(
|
|
f'h2_1PhotonSumSample{suffix}', f'h2_1PhotonSumSample{suffix}', clusterSize1Photon, 0, clusterSize1Photon, clusterSize1Photon, 0, clusterSize1Photon
|
|
)
|
|
histograms['h2_1PhotonSumSample'].SetTitle('1-Photon Sum Sample;Sum Sample;Counts')
|
|
|
|
histograms['h2_2PhotonSumSample'] = TH2D(
|
|
f'h2_2PhotonSumSample{suffix}', f'h2_2PhotonSumSample{suffix}', clusterSize2Photon, 0, clusterSize2Photon, clusterSize2Photon, 0, clusterSize2Photon
|
|
)
|
|
histograms['h2_2PhotonSumSample'].SetTitle('2-Photon Sum Sample;Sum Sample;Counts')
|
|
|
|
histograms['h2_3PhotonSumSample'] = TH2D(
|
|
f'h2_3PhotonSumSample{suffix}', f'h2_3PhotonSumSample{suffix}', clusterSize3Photon, 0, clusterSize3Photon, clusterSize3Photon, 0, clusterSize3Photon
|
|
)
|
|
histograms['h2_3PhotonSumSample'].SetTitle('3-Photon Sum Sample;Sum Sample;Counts')
|
|
|
|
histograms['h2_2PhotonSumFrame'] = TH2D(
|
|
f'h2_2PhotonSumFrame{suffix}', f'h2_2PhotonSumFrame{suffix}', roi_width, roi_x0, roi_x1, roi_height, roi_y0, roi_y1
|
|
)
|
|
histograms['h2_2PhotonSumFrame'].SetTitle('2-Photon Hits Sum Frame;X [pixel];Y [pixel];Energy Sum [keV]')
|
|
|
|
histograms['h2_3PhotonSumFrame'] = TH2D(
|
|
f'h2_3PhotonSumFrame{suffix}', f'h2_3PhotonSumFrame{suffix}', roi_width, roi_x0, roi_x1, roi_height, roi_y0, roi_y1
|
|
)
|
|
histograms['h2_3PhotonSumFrame'].SetTitle('3-Photon Hits Sum Frame;X [pixel];Y [pixel];Energy Sum [keV]')
|
|
|
|
histograms['h2_ClusterSizeVsEnergy'] = TH2D(
|
|
f'h2_ClusterSizeVsEnergy{suffix}', f'h2_ClusterSizeVsEnergy{suffix}', nEnergyBins, -1, histMaxEnergy, 30, 0, 30
|
|
)
|
|
histograms['h2_ClusterSizeVsEnergy'].SetTitle('Cluster Size vs Energy;Energy [keV];Cluster Size [pixel]')
|
|
|
|
histograms['h2_DiameterVsEnergy'] = TH2D(
|
|
f'h2_DiameterVsEnergy{suffix}', f'h2_DiameterVsEnergy{suffix}', nEnergyBins, -1, histMaxEnergy, 15, 0, 15
|
|
)
|
|
histograms['h2_DiameterVsEnergy'].SetTitle('Cluster Diameter vs Energy;Energy [keV];Cluster Diameter [pixel]')
|
|
|
|
for hist in histograms.values():
|
|
hist.SetDirectory(0)
|
|
|
|
return histograms
|
|
|
|
def _processFrames(idxChunk): ### for both single and double photon events, using
|
|
startFrame, endFrame = _cfg['NFrame'] * idxChunk // nChunks, min(_cfg['NFrame'] * (idxChunk + 1) // nChunks, _cfg['NFrame'])
|
|
print(f'Processing frames from {startFrame} to {endFrame}...')
|
|
Energy = _cfg['energy']
|
|
selectionRange = _cfg['selectionRange']
|
|
signalFileNames = _cfg['signalFileNames']
|
|
NX = _cfg['NX']
|
|
NY = _cfg['NY']
|
|
headerSize = _cfg['headerSize']
|
|
Roi = _cfg['Roi']
|
|
nFramePerFile = os.path.getsize(f'{signalFileNames[0]}') // (NX * NY + 56) // 2
|
|
_hists = bookHistograms(Energy, f'_{idxChunk}')
|
|
sumFrame = np.zeros((NY, NX), dtype=np.float64)
|
|
|
|
### create a cluster finder
|
|
nxROI = Roi[1] - Roi[0]
|
|
nyROI = Roi[3] - Roi[2]
|
|
CF = aare.VarClusterFinder((nyROI, nxROI), 5) ### arg1: frame size, arg2: threshold
|
|
CF.set_peripheralThresholdFactor(3)
|
|
CF.set_noiseMap(_noiseEneFrame)
|
|
CF.set_numberOfNeighbours(4)
|
|
CF.set_empty_surroundingPixels(False)
|
|
|
|
if 'writeClusters' in _cfg and _cfg['writeClusters'] == True:
|
|
h5_1Photon_file = h5py.File(f'{_cfg["outputFolder"]}/1Photon_CS{clusterSize1Photon}_chunk{idxChunk}.h5', 'w')
|
|
dset_1Photon_clusters = h5_1Photon_file.create_dataset(
|
|
'clusters', (0, clusterSize1Photon, clusterSize1Photon), maxshape=(None, clusterSize1Photon, clusterSize1Photon), dtype='f4',
|
|
chunks=True, compression='gzip'
|
|
)
|
|
dset_1photon_refs = h5_1Photon_file.create_dataset(
|
|
'referencePoint', (0, 2), maxshape=(None, 2), dtype='i4',
|
|
chunks=True
|
|
)
|
|
|
|
cluster_1Photon_list = []
|
|
refpoint_1Photon_list = []
|
|
|
|
h5_2Photon_file = h5py.File(f'{_cfg["outputFolder"]}/2Photon_CS{clusterSize2Photon}_chunk{idxChunk}.h5', 'w')
|
|
dset_2Photon_clusters = h5_2Photon_file.create_dataset(
|
|
'clusters', (0, clusterSize2Photon, clusterSize2Photon), maxshape=(None, clusterSize2Photon, clusterSize2Photon), dtype='f4',
|
|
chunks=True, compression='gzip'
|
|
)
|
|
dset_2Photon_refs = h5_2Photon_file.create_dataset(
|
|
'referencePoint', (0, 2), maxshape=(None, 2), dtype='i4',
|
|
chunks=True
|
|
)
|
|
cluster_2Photon_list = []
|
|
refpoint_2Photon_list = []
|
|
|
|
h5_3Photon_file = h5py.File(f'{_cfg["outputFolder"]}/3Photon_CS{clusterSize3Photon}_chunk{idxChunk}.h5', 'w')
|
|
dset_3Photon_clusters = h5_3Photon_file.create_dataset(
|
|
'clusters', (0, clusterSize3Photon, clusterSize3Photon), maxshape=(None, clusterSize3Photon, clusterSize3Photon), dtype='f4',
|
|
chunks=True, compression='gzip'
|
|
)
|
|
dset_3Photon_refs = h5_3Photon_file.create_dataset(
|
|
'referencePoint', (0, 2), maxshape=(None, 2), dtype='i4',
|
|
chunks=True
|
|
)
|
|
cluster_3Photon_list = []
|
|
refpoint_3Photon_list = []
|
|
|
|
BUFFER_THRESHOLD = 10000
|
|
def flush_h5_buffer():
|
|
if not cluster_1Photon_list: return # no new clusters to write
|
|
old_len = dset_1Photon_clusters.shape[0]
|
|
new_len = old_len + len(cluster_1Photon_list)
|
|
dset_1Photon_clusters.resize((new_len, clusterSize1Photon, clusterSize1Photon))
|
|
dset_1photon_refs.resize((new_len, 2))
|
|
dset_1Photon_clusters[old_len:new_len] = cluster_1Photon_list
|
|
dset_1photon_refs[old_len:new_len] = refpoint_1Photon_list
|
|
cluster_1Photon_list.clear()
|
|
refpoint_1Photon_list.clear()
|
|
|
|
if not cluster_2Photon_list: return # no new clusters to write
|
|
old_len = dset_2Photon_clusters.shape[0]
|
|
new_len = old_len + len(cluster_2Photon_list)
|
|
dset_2Photon_clusters.resize((new_len, clusterSize2Photon, clusterSize2Photon))
|
|
dset_2Photon_refs.resize((new_len, 2))
|
|
dset_2Photon_clusters[old_len:new_len] = cluster_2Photon_list
|
|
dset_2Photon_refs[old_len:new_len] = refpoint_2Photon_list
|
|
cluster_2Photon_list.clear()
|
|
refpoint_2Photon_list.clear()
|
|
|
|
if not cluster_3Photon_list: return # no new clusters to write
|
|
old_len = dset_3Photon_clusters.shape[0]
|
|
new_len = old_len + len(cluster_3Photon_list)
|
|
dset_3Photon_clusters.resize((new_len, clusterSize3Photon, clusterSize3Photon))
|
|
dset_3Photon_refs.resize((new_len, 2))
|
|
dset_3Photon_clusters[old_len:new_len] = cluster_3Photon_list
|
|
dset_3Photon_refs[old_len:new_len] = refpoint_3Photon_list
|
|
cluster_3Photon_list.clear()
|
|
refpoint_3Photon_list.clear()
|
|
|
|
for idxFrame in range(startFrame, endFrame):
|
|
idxFile, idxFrame = divmod(idxFrame, nFramePerFile)
|
|
try:
|
|
if 'nFiber' in _cfg and _cfg['nFiber'] == 2:
|
|
offset = (headerSize + idxFrame * (NX * NY//2 + headerSize)) * 2
|
|
fileName1 = signalFileNames[idxFile]
|
|
fileName2 = fileName1.replace('d0', 'd1')
|
|
_signalAduFrame1 = np.fromfile(f'{fileName1}', dtype=np.uint16, offset=offset, count=NX * NY //2).astype(np.int32).reshape(NY//2, NX)
|
|
_signalAduFrame2 = np.fromfile(f'{fileName2}', dtype=np.uint16, offset=offset, count=NX * NY //2).astype(np.int32).reshape(NY//2, NX)
|
|
signalAduFrame = np.concatenate([_signalAduFrame1, _signalAduFrame2], axis=0)
|
|
del _signalAduFrame1, _signalAduFrame2
|
|
else:
|
|
offset = (headerSize + idxFrame * (NX * NY + headerSize)) * 2
|
|
signalAduFrame = np.fromfile(f'{signalFileNames[idxFile]}', dtype=np.uint16, offset=offset, count=NX * NY).astype(np.int32).reshape(NX, NY)
|
|
except Exception as e:
|
|
print(f'Error reading frame {idxFrame+startFrame} from file {signalFileNames[idxFile]}: {e}, stop processing this chunk ({startFrame}-{endFrame})')
|
|
return _hists
|
|
|
|
signalAduFrame = signalAduFrame - _pedestalAduFrame
|
|
signalEneFrame = convertAduFrameToEnergyFrame(signalAduFrame)
|
|
sumFrame += signalEneFrame
|
|
|
|
signalEneFrame = signalEneFrame[Roi[2]:Roi[3], Roi[0]:Roi[1]].copy() ### to avoid the 'view' problem: the modified signalEneFrame will be discarded otherwise
|
|
_signalEneFrame = np.copy(signalEneFrame) ### make a copy of the original energy frame for cluster energy correction later, since the cluster finder will modify the input energy frame
|
|
CF.find_clusters_X(signalEneFrame)
|
|
clusters = CF.hits()
|
|
for idxCluster in range(len(clusters)):
|
|
clusterSize = clusters['size'][idxCluster]
|
|
energy = clusters['energy'][idxCluster]
|
|
_hists['h1_ClusterEnergy'].Fill(energy)
|
|
xs = clusters['cols'][idxCluster][:clusterSize]
|
|
ys = clusters['rows'][idxCluster][:clusterSize]
|
|
enes = clusters['enes'][idxCluster][:clusterSize]
|
|
|
|
### single photon events
|
|
if Energy - selectionRange < energy < Energy + selectionRange:
|
|
ref_x = clusters['col'][idxCluster] - clusterSize1Photon//2 ### refered to the lower-left corner of the cluster
|
|
ref_y = clusters['row'][idxCluster] - clusterSize1Photon//2
|
|
if int(ref_x) < 0 or int(ref_x)+clusterSize1Photon > signalEneFrame.shape[1] or int(ref_y) < 0 or int(ref_y)+clusterSize1Photon > signalEneFrame.shape[0]:
|
|
continue ### skip clusters too close to the border
|
|
for i in range(len(xs)):
|
|
_hists['h2_1PhotonSumFrame'].Fill(xs[i]+Roi[0], ys[i]+Roi[2], enes[i])
|
|
_hists['h1_1PhotonClusterSize'].Fill(clusterSize)
|
|
diameterX = max(xs) - min(xs) + 1
|
|
diameterY = max(ys) - min(ys) + 1
|
|
_hists['h1_1PhotonClusterDiameterX'].Fill(diameterX)
|
|
_hists['h1_1PhotonClusterDiameterY'].Fill(diameterY)
|
|
|
|
cluster_1Photon = np.zeros((clusterSize1Photon, clusterSize1Photon), dtype=np.float32)
|
|
### var cluster is less accurate than the 3x3 fixed cluster, since the zero pixels are incontinuous, not friendly for ML.
|
|
# for i in range(len(xs)):
|
|
# x_rel = xs[i] - int(ref_x)
|
|
# y_rel = ys[i] - int(ref_y)
|
|
# # _hists['h1_1PhotonClusterPixelEnergy'].Fill(enes[i])
|
|
# if 0 <= x_rel < clusterSize1Photon and 0 <= y_rel < clusterSize1Photon:
|
|
# cluster_1Photon[y_rel, x_rel] = enes[i]
|
|
|
|
# use the sum of 3x3 cluster as the cluster energy for single photon events, which is more accurate than the original cluster energy given by the cluster finder, since the cluster finder may miss some pixels with low energy far from the center pixel
|
|
cluster_1Photon = _signalEneFrame[int(ref_y):int(ref_y)+clusterSize1Photon, int(ref_x):int(ref_x)+clusterSize1Photon]
|
|
_hists['h1_1PhotonClusterEnergy'].Fill(np.sum(cluster_1Photon))
|
|
for i in range(clusterSize1Photon):
|
|
for j in range(clusterSize1Photon):
|
|
_hists['h2_1PhotonSumSample'].Fill(i, j, cluster_1Photon[i, j])
|
|
if 'writeClusters' in _cfg and _cfg['writeClusters'] == True:
|
|
cluster_1Photon_list.append(cluster_1Photon)
|
|
refpoint_1Photon_list.append([int(ref_x)+Roi[0], int(ref_y)+Roi[2]])
|
|
|
|
sumEne = np.sum(cluster_1Photon)
|
|
### calculate eta
|
|
projectedX = np.sum(cluster_1Photon, axis=0)
|
|
etaX = (projectedX[2] - projectedX[0]) / sumEne
|
|
projectedY = np.sum(cluster_1Photon, axis=1)
|
|
etaY = (projectedY[2] - projectedY[0]) / sumEne
|
|
_hists['h1_1PhotonEta_X'].Fill(etaX)
|
|
_hists['h1_1PhotonEta_Y'].Fill(etaY)
|
|
|
|
### double photon events
|
|
if 2 * Energy - 2 * selectionRange < energy < 2 * Energy + 2 * selectionRange:
|
|
x_center = np.sum(xs * enes) / np.sum(enes)
|
|
y_center = np.sum(ys * enes) / np.sum(enes)
|
|
ref_x = int(x_center - clusterSize2Photon / 2) + 1 ### refered to the lower-left corner of the cluster
|
|
ref_y = int(y_center - clusterSize2Photon / 2) + 1
|
|
|
|
if int(ref_x) < 0 or int(ref_x)+clusterSize2Photon > signalEneFrame.shape[1] or int(ref_y) < 0 or int(ref_y)+clusterSize2Photon > signalEneFrame.shape[0]:
|
|
continue ### skip clusters too close to the border
|
|
for i in range(len(xs)):
|
|
_hists['h2_2PhotonSumFrame'].Fill(xs[i]+Roi[0], ys[i]+Roi[2], enes[i])
|
|
_hists['h1_2PhotonClusterPixelEnergy'].Fill(enes[i])
|
|
_hists['h1_2PhotonClusterSize'].Fill(clusterSize)
|
|
diameterX = max(xs) - min(xs) + 1
|
|
diameterY = max(ys) - min(ys) + 1
|
|
_hists['h1_2PhotonClusterDiameterX'].Fill(diameterX)
|
|
_hists['h1_2PhotonClusterDiameterY'].Fill(diameterY)
|
|
|
|
### filling the 2-photon cluster. Add background as well.
|
|
cluster_2Photon = np.zeros((clusterSize2Photon, clusterSize2Photon), dtype=np.float32)
|
|
for i in range(len(xs)):
|
|
x_rel = xs[i] - int(ref_x)
|
|
y_rel = ys[i] - int(ref_y)
|
|
if 0 <= x_rel < clusterSize2Photon and 0 <= y_rel < clusterSize2Photon:
|
|
cluster_2Photon[y_rel, x_rel] = enes[i]
|
|
_hists['h2_2PhotonSumSample'].Fill(x_rel, y_rel, enes[i])
|
|
cluster_2Photon += signalEneFrame[int(ref_y):int(ref_y)+clusterSize2Photon, int(ref_x):int(ref_x)+clusterSize2Photon]
|
|
|
|
_hists['h1_2PhotonClusterEnergy'].Fill(np.sum(cluster_2Photon))
|
|
for i in range(clusterSize2Photon):
|
|
for j in range(clusterSize2Photon):
|
|
_hists['h2_2PhotonSumSample'].Fill(i, j, cluster_2Photon[i, j])
|
|
if 'writeClusters' in _cfg and _cfg['writeClusters'] == True:
|
|
cluster_2Photon_list.append(cluster_2Photon)
|
|
refpoint_2Photon_list.append([int(ref_x)+Roi[0], int(ref_y)+Roi[2]])
|
|
|
|
if 3 * Energy - 3 * selectionRange < energy < 3 * Energy + 3 * selectionRange:
|
|
x_center = np.sum(xs * enes) / np.sum(enes)
|
|
y_center = np.sum(ys * enes) / np.sum(enes)
|
|
ref_x = int(x_center - clusterSize3Photon / 2) + 1 ### refered to the lower-left corner of the cluster
|
|
ref_y = int(y_center - clusterSize3Photon / 2) + 1
|
|
|
|
if int(ref_x) < 0 or int(ref_x)+clusterSize3Photon > signalEneFrame.shape[1] or int(ref_y) < 0 or int(ref_y)+clusterSize3Photon > signalEneFrame.shape[0]:
|
|
continue ### skip clusters too close to the border
|
|
for i in range(len(xs)):
|
|
_hists['h2_3PhotonSumFrame'].Fill(xs[i]+Roi[0], ys[i]+Roi[2], enes[i])
|
|
_hists['h1_3PhotonClusterPixelEnergy'].Fill(enes[i])
|
|
_hists['h1_3PhotonClusterSize'].Fill(clusterSize)
|
|
diameterX = max(xs) - min(xs) + 1
|
|
diameterY = max(ys) - min(ys) + 1
|
|
_hists['h1_3PhotonClusterDiameterX'].Fill(diameterX)
|
|
_hists['h1_3PhotonClusterDiameterY'].Fill(diameterY)
|
|
|
|
### filling the 3-photon cluster. Add background as well.
|
|
cluster_3Photon = np.zeros((clusterSize3Photon, clusterSize3Photon), dtype=np.float32)
|
|
for i in range(len(xs)):
|
|
x_rel = xs[i] - int(ref_x)
|
|
y_rel = ys[i] - int(ref_y)
|
|
if 0 <= x_rel < clusterSize3Photon and 0 <= y_rel < clusterSize3Photon:
|
|
cluster_3Photon[y_rel, x_rel] = enes[i]
|
|
_hists['h2_3PhotonSumSample'].Fill(x_rel, y_rel, enes[i])
|
|
cluster_3Photon += signalEneFrame[int(ref_y):int(ref_y)+clusterSize3Photon, int(ref_x):int(ref_x)+clusterSize3Photon]
|
|
_hists['h1_3PhotonClusterEnergy'].Fill(np.sum(cluster_3Photon))
|
|
for i in range(clusterSize3Photon):
|
|
for j in range(clusterSize3Photon):
|
|
_hists['h2_3PhotonSumSample'].Fill(i, j, cluster_3Photon[i, j])
|
|
if 'writeClusters' in _cfg and _cfg['writeClusters'] == True:
|
|
cluster_3Photon_list.append(cluster_3Photon)
|
|
refpoint_3Photon_list.append([int(ref_x)+Roi[0], int(ref_y)+Roi[2]])
|
|
|
|
_hists['h2_ClusterSizeVsEnergy'].Fill(energy, clusterSize)
|
|
_diameterX = max(xs) - min(xs) + 1
|
|
_diameterY = max(ys) - min(ys) + 1
|
|
_diameter = max(_diameterX, _diameterY)
|
|
_hists['h2_DiameterVsEnergy'].Fill(energy, _diameter)
|
|
for i in range(len(xs)):
|
|
_hists['h1_PixelEnergy'].Fill(enes[i])
|
|
_hists['h2_HitsSumFrame'].Fill(xs[i]+Roi[0], ys[i]+Roi[2], enes[i])
|
|
if 'writeClusters' in _cfg and _cfg['writeClusters'] == True:
|
|
if len(cluster_1Photon_list) > BUFFER_THRESHOLD or len(cluster_2Photon_list) > BUFFER_THRESHOLD:
|
|
flush_h5_buffer()
|
|
|
|
for _x in range(Roi[0], Roi[1]):
|
|
for _y in range(Roi[2], Roi[3]):
|
|
_hists['h2_SumFrame'].Fill(_x, _y, sumFrame[_y, _x])
|
|
if 'writeClusters' in _cfg and _cfg['writeClusters'] == True:
|
|
flush_h5_buffer()
|
|
h5_1Photon_file.close()
|
|
h5_2Photon_file.close()
|
|
return _hists
|
|
|
|
def process():
|
|
import os
|
|
os.makedirs(_cfg['outputFolder'], exist_ok=True)
|
|
with Pool(_cfg['NThread'], maxtasksperchild=1) as p:
|
|
results = p.map(_processFrames, range(nChunks))
|
|
|
|
global hists
|
|
hists = bookHistograms(_cfg['energy'])
|
|
for h in hists.values():
|
|
h.SetDirectory(0)
|
|
|
|
for _hists in results:
|
|
for key in hists.keys():
|
|
hists[key].Add(_hists[key])
|
|
del _hists
|
|
|
|
outputTFileName = f'/home/xie_x1/MLXID/DataProcess/Results/{_cfg["runName"]}.root'
|
|
outputTFile = TFile(outputTFileName, 'RECREATE')
|
|
for hist in hists.values():
|
|
hist.Write()
|
|
outputTFile.Close()
|
|
|
|
def getPedestalAndNoise():
|
|
NX, NY = _cfg['NX'], _cfg['NY']
|
|
pedestalFileName = _cfg['pedestalFileName']
|
|
if 'nFiber' in _cfg and _cfg['nFiber'] == 2:
|
|
pedestalFileName2 = pedestalFileName.replace('d0', 'd1')
|
|
_pedestalAduFrames1 = np.fromfile(f'{pedestalFileName}', dtype=np.uint16).astype(np.int32)
|
|
_pedestalAduFrames1 = _pedestalAduFrames1.reshape(-1, NX * NY //2 + 56)
|
|
_pedestalAduFrames1 = _pedestalAduFrames1[:, 56:].reshape(-1, NY//2, NX)
|
|
_pedestalAduFrames2 = np.fromfile(f'{pedestalFileName2}', dtype=np.uint16).astype(np.int32)
|
|
_pedestalAduFrames2 = _pedestalAduFrames2.reshape(-1, NX * NY //2 + 56)
|
|
_pedestalAduFrames2 = _pedestalAduFrames2[:, 56:].reshape(-1, NY//2, NX)
|
|
pedestalAduFrames = np.concatenate([_pedestalAduFrames1, _pedestalAduFrames2], axis=1)
|
|
del _pedestalAduFrames1, _pedestalAduFrames2
|
|
else:
|
|
pedestalAduFrames = np.fromfile(f'{pedestalFileName}', dtype=np.uint16).astype(np.int32)
|
|
pedestalAduFrames = pedestalAduFrames.reshape(-1, NX * NY + 56)
|
|
pedestalAduFrames = pedestalAduFrames[:, 56:].reshape(-1, NX, NY)
|
|
|
|
pedestalAduFrames = pedestalAduFrames[pedestalAduFrames.shape[0]//10:] # skip the first 10% frames
|
|
global _pedestalAduFrame, _noiseEneFrame
|
|
_pedestalAduFrame = np.mean(pedestalAduFrames, axis=0)
|
|
noiseAduFrame = np.std(pedestalAduFrames, axis=0, ddof=1)
|
|
with Pool(16) as p:
|
|
pedestalEneFrames = p.map(convertAduFrameToEnergyFrame, pedestalAduFrames)
|
|
_noiseEneFrame = np.std(pedestalEneFrames, axis=0, ddof=1)
|
|
print(f'Average noise = {np.mean(_noiseEneFrame):.3f} keV; {np.mean(noiseAduFrame):.3f} ADU')
|
|
del pedestalAduFrames, pedestalEneFrames
|
|
|
|
def getPedestalAndNoise_simplified():
|
|
NX, NY = _cfg['NX'], _cfg['NY']
|
|
pedestalFileName = _cfg['pedestalFileName']
|
|
pedestalAduFrames = np.fromfile(f'{pedestalFileName}', dtype=np.uint16).astype(np.int32)
|
|
pedestalAduFrames = pedestalAduFrames.reshape(-1, NX * NY + 56)
|
|
pedestalAduFrames = pedestalAduFrames[:, 56:].reshape(-1, NX, NY)
|
|
pedestalAduFrames = pedestalAduFrames[pedestalAduFrames.shape[0]//10:] # skip the first 10% frames
|
|
global _pedestalAduFrame, _noiseEneFrame
|
|
_pedestalAduFrame = np.mean(pedestalAduFrames, axis=0)
|
|
noiseAduFrame = np.std(pedestalAduFrames, axis=0, ddof=1)
|
|
_noiseEneFrame = convertAduFrameToEnergyFrame(noiseAduFrame)
|
|
|
|
print(f'Average noise = {np.mean(_noiseEneFrame):.3f} keV; {np.mean(noiseAduFrame):.3f} ADU')
|
|
del pedestalAduFrames
|