Module xenodiffusionscope.TopArray

Expand source code
import pickle

import matplotlib.pyplot as plt
import numpy as np
import scipy.integrate
import scipy.interpolate
from matplotlib.patches import Circle, Rectangle
from tqdm import tqdm

# Plots should be handled in separate Plotter file.

class TopArray:
    '''Every TPC needs a readout. Ours is, by default, a top array of SiPMs.'''
    def __init__(self, tpc, mesh,model,path_to_patterns,path_to_model):
        self.model = model
        self.tpc = tpc
        self.path_to_patterns = path_to_patterns
        self.mesh = mesh
        self.path_to_model = path_to_model
        
        self.make_results_grid()
        
        
    def make_results_grid(self, x_step=1, y_step=1):
        '''Define the grid to discritize the LCE pattern.'''
        self.grid_x_step = x_step
        self.grid_y_step = y_step
        self.grid_x_max = self.tpc.radius
        self.grid_y_max = self.tpc.radius
        self.grid_x_min = -self.tpc.radius
        self.grid_y_min = -self.tpc.radius
        self.grid_x = np.arange(self.grid_x_min, 
                                self.grid_x_max,
                                self.grid_x_step)
        self.grid_y = np.arange(self.grid_y_min,
                                self.grid_y_max,
                                self.grid_y_step)
        self.grid_xx,self.grid_yy = np.meshgrid(self.grid_x,
                                                self.grid_y,
                                                indexing='ij')
        self.grid_zz = np.zeros((self.grid_yy.shape))
        return None
    
    def load_top_array(self):
        '''Load the top array from file.
        **THIS USES PICKLE, IT SHOULD BE CHANGED TO SOMETHING MORE ROBUST**.'''
        with open('%s/%s.pck'%(self.path_to_model, self.model), 'rb') as file:
            self.sensors = pickle.load(file)
        self.n_sensors = len(self.sensors)
        
        return None
    
    def plot_toparray(self,ax, pe_in_sensors = False):
        '''Plot the top array and, optionally, fill with pattern from 
        results.'''

        ax.set_aspect('equal')
        for _quad_i,_quad in enumerate(self.sensors):
            xy = (_quad[0],_quad[2])
            width = _quad[1]-_quad[0]
            height = _quad[3]-_quad[2]
            if pe_in_sensors == False:
                ax.add_patch(Rectangle(xy,width,height, 
                                       fill = False, 
                                       color = 'k'))
            else:
                #TO DO
                #check if results exist and default to False
                
                cm = plt.get_cmap('gnuplot')
                log_pe = np.log10(self.pe_in_sensors)
                results_max = np.max(log_pe)
                results_min = np.min(log_pe[np.isfinite(log_pe)])
                log_pe = np.nan_to_num(log_pe, copy = True,neginf=results_min)
                results_max = np.max(log_pe)
                results_min = np.min(log_pe)
                pe = log_pe[_quad_i]

                ax.add_patch(Rectangle(xy,width,height, 
                                       fill = True, 
                                       edgecolor = 'k',
                                       facecolor = cm((pe-results_min)/
                                                      (results_max-results_min)),
                                      )
                            )
        ax.set_ylim(-90,90)
        ax.set_xlim(-90,90)
        ax.set_aspect('equal')
        ax.set_xlabel('x [mm]')
        ax.set_ylabel('y [mm]')
        ax.add_patch(Circle((0,0),75, color = 'r',fill = False))
        return ax
    
    def integrate_in_photosensor(self,quad):
        '''Integrate the PEs in a given photosensor.'''
        ans = self.results_interp.integral(quad[0],quad[1],quad[2],quad[3])
        return ans
    
    def load_pattern(self, hex_id):
        '''Load the pattern for a given hex focus point.'''
        with open(self.path_to_patterns + 'hex_%d.pck'%hex_id, 'rb') as file:
            pattern = pickle.load(file)
        return pattern
    
    def load_all_patterns(self, all_at_once = False):
        '''Load all the patterns for all the hex focus points.'''
        if all_at_once:
            with open(self.path_to_patterns+'all_patterns.pck', 'rb') as file:
                patterns = pickle.load(file)
            self.patterns = patterns
            return None
        
        patterns = dict()
        for _hex_i in tqdm(range(self.mesh.n_hexes),
                           'Loading LCE patterns.',
                           total = self.mesh.n_hexes):
            patterns[_hex_i] = self.load_pattern(_hex_i)
        
        self.patterns = patterns
        
        return None
    
    def plot_pattern(self, hex_id, save_fig = False):
        '''Plot the pattern from a given focusing point.'''

        if hasattr(self, 'patterns'):
            pattern = self.patterns[hex_id]
        else:
            pattern = self.load_pattern(hex_id)

        fig,ax = plt.subplots(1,1,figsize = (9,9))
        ax.set_title('Pattern interpolation\n(spline, k=3)')
        _x = np.arange(-100,100,1)
        _y = np.arange(-100,100,1)
        _xx,_yy = np.meshgrid(_x,_y, indexing='ij')
        _rr = self.tpc.get_r(_xx,_yy)
        _xx = _xx[_rr < 100]
        _yy = _yy[_rr < 100]
        _zz = pattern.ev(_xx,_yy)
        interpolated = ax.scatter(_xx, _yy, c=np.log10(_zz), marker = 's',
                                  s = 3, vmin = -6.2)

        ax.add_patch(Circle((0,0),self.tpc.radius, color = 'r',fill = False, 
                            linewidth = 1, ls ='--', label = 'TPC'))
        ax.set_aspect('equal')
        ax.legend()
        fig.colorbar(interpolated, ax = ax)
        if save_fig:
            plt.savefig('figures/patterns/hex_v0_%d' %hex_id)
        else:
            plt.show()
        return None
    
    def fill_grid_from_events(self, counts_pe_on_hex):
        '''
        Sum over all the patterns of LCE x number of pe per hex to
        get the final pe pattern in the array.
        '''
        
        for hex_i in tqdm(range(self.mesh.n_hexes),
                          'Summing all normalized patterns. 1+1+2+3+5+8+...',
                          total = self.mesh.n_hexes):
            #pattern = load_pattern(self, hex_i)
            pattern = self.patterns[hex_i]
            if counts_pe_on_hex[hex_i] > 0:
                _zz = pattern.ev(self.grid_xx,self.grid_yy) * counts_pe_on_hex[hex_i]
                self.grid_zz += _zz
            else:
                continue
        
        self.results_interp = scipy.interpolate.RectBivariateSpline(
            self.grid_x, 
            self.grid_y,
            self.grid_zz,
            s = 0)
        return None
    
    def n_pe_in_sensors(self):
        '''Integrate the PEs in each photosensor.'''
        pe_in_sensors = np.apply_along_axis(self.integrate_in_photosensor,
                                          1, 
                                          self.sensors)
        self.pe_in_sensors = pe_in_sensors
        return np.abs(pe_in_sensors)
        

Classes

class TopArray (tpc, mesh, model, path_to_patterns, path_to_model)

Every TPC needs a readout. Ours is, by default, a top array of SiPMs.

Expand source code
class TopArray:
    '''Every TPC needs a readout. Ours is, by default, a top array of SiPMs.'''
    def __init__(self, tpc, mesh,model,path_to_patterns,path_to_model):
        self.model = model
        self.tpc = tpc
        self.path_to_patterns = path_to_patterns
        self.mesh = mesh
        self.path_to_model = path_to_model
        
        self.make_results_grid()
        
        
    def make_results_grid(self, x_step=1, y_step=1):
        '''Define the grid to discritize the LCE pattern.'''
        self.grid_x_step = x_step
        self.grid_y_step = y_step
        self.grid_x_max = self.tpc.radius
        self.grid_y_max = self.tpc.radius
        self.grid_x_min = -self.tpc.radius
        self.grid_y_min = -self.tpc.radius
        self.grid_x = np.arange(self.grid_x_min, 
                                self.grid_x_max,
                                self.grid_x_step)
        self.grid_y = np.arange(self.grid_y_min,
                                self.grid_y_max,
                                self.grid_y_step)
        self.grid_xx,self.grid_yy = np.meshgrid(self.grid_x,
                                                self.grid_y,
                                                indexing='ij')
        self.grid_zz = np.zeros((self.grid_yy.shape))
        return None
    
    def load_top_array(self):
        '''Load the top array from file.
        **THIS USES PICKLE, IT SHOULD BE CHANGED TO SOMETHING MORE ROBUST**.'''
        with open('%s/%s.pck'%(self.path_to_model, self.model), 'rb') as file:
            self.sensors = pickle.load(file)
        self.n_sensors = len(self.sensors)
        
        return None
    
    def plot_toparray(self,ax, pe_in_sensors = False):
        '''Plot the top array and, optionally, fill with pattern from 
        results.'''

        ax.set_aspect('equal')
        for _quad_i,_quad in enumerate(self.sensors):
            xy = (_quad[0],_quad[2])
            width = _quad[1]-_quad[0]
            height = _quad[3]-_quad[2]
            if pe_in_sensors == False:
                ax.add_patch(Rectangle(xy,width,height, 
                                       fill = False, 
                                       color = 'k'))
            else:
                #TO DO
                #check if results exist and default to False
                
                cm = plt.get_cmap('gnuplot')
                log_pe = np.log10(self.pe_in_sensors)
                results_max = np.max(log_pe)
                results_min = np.min(log_pe[np.isfinite(log_pe)])
                log_pe = np.nan_to_num(log_pe, copy = True,neginf=results_min)
                results_max = np.max(log_pe)
                results_min = np.min(log_pe)
                pe = log_pe[_quad_i]

                ax.add_patch(Rectangle(xy,width,height, 
                                       fill = True, 
                                       edgecolor = 'k',
                                       facecolor = cm((pe-results_min)/
                                                      (results_max-results_min)),
                                      )
                            )
        ax.set_ylim(-90,90)
        ax.set_xlim(-90,90)
        ax.set_aspect('equal')
        ax.set_xlabel('x [mm]')
        ax.set_ylabel('y [mm]')
        ax.add_patch(Circle((0,0),75, color = 'r',fill = False))
        return ax
    
    def integrate_in_photosensor(self,quad):
        '''Integrate the PEs in a given photosensor.'''
        ans = self.results_interp.integral(quad[0],quad[1],quad[2],quad[3])
        return ans
    
    def load_pattern(self, hex_id):
        '''Load the pattern for a given hex focus point.'''
        with open(self.path_to_patterns + 'hex_%d.pck'%hex_id, 'rb') as file:
            pattern = pickle.load(file)
        return pattern
    
    def load_all_patterns(self, all_at_once = False):
        '''Load all the patterns for all the hex focus points.'''
        if all_at_once:
            with open(self.path_to_patterns+'all_patterns.pck', 'rb') as file:
                patterns = pickle.load(file)
            self.patterns = patterns
            return None
        
        patterns = dict()
        for _hex_i in tqdm(range(self.mesh.n_hexes),
                           'Loading LCE patterns.',
                           total = self.mesh.n_hexes):
            patterns[_hex_i] = self.load_pattern(_hex_i)
        
        self.patterns = patterns
        
        return None
    
    def plot_pattern(self, hex_id, save_fig = False):
        '''Plot the pattern from a given focusing point.'''

        if hasattr(self, 'patterns'):
            pattern = self.patterns[hex_id]
        else:
            pattern = self.load_pattern(hex_id)

        fig,ax = plt.subplots(1,1,figsize = (9,9))
        ax.set_title('Pattern interpolation\n(spline, k=3)')
        _x = np.arange(-100,100,1)
        _y = np.arange(-100,100,1)
        _xx,_yy = np.meshgrid(_x,_y, indexing='ij')
        _rr = self.tpc.get_r(_xx,_yy)
        _xx = _xx[_rr < 100]
        _yy = _yy[_rr < 100]
        _zz = pattern.ev(_xx,_yy)
        interpolated = ax.scatter(_xx, _yy, c=np.log10(_zz), marker = 's',
                                  s = 3, vmin = -6.2)

        ax.add_patch(Circle((0,0),self.tpc.radius, color = 'r',fill = False, 
                            linewidth = 1, ls ='--', label = 'TPC'))
        ax.set_aspect('equal')
        ax.legend()
        fig.colorbar(interpolated, ax = ax)
        if save_fig:
            plt.savefig('figures/patterns/hex_v0_%d' %hex_id)
        else:
            plt.show()
        return None
    
    def fill_grid_from_events(self, counts_pe_on_hex):
        '''
        Sum over all the patterns of LCE x number of pe per hex to
        get the final pe pattern in the array.
        '''
        
        for hex_i in tqdm(range(self.mesh.n_hexes),
                          'Summing all normalized patterns. 1+1+2+3+5+8+...',
                          total = self.mesh.n_hexes):
            #pattern = load_pattern(self, hex_i)
            pattern = self.patterns[hex_i]
            if counts_pe_on_hex[hex_i] > 0:
                _zz = pattern.ev(self.grid_xx,self.grid_yy) * counts_pe_on_hex[hex_i]
                self.grid_zz += _zz
            else:
                continue
        
        self.results_interp = scipy.interpolate.RectBivariateSpline(
            self.grid_x, 
            self.grid_y,
            self.grid_zz,
            s = 0)
        return None
    
    def n_pe_in_sensors(self):
        '''Integrate the PEs in each photosensor.'''
        pe_in_sensors = np.apply_along_axis(self.integrate_in_photosensor,
                                          1, 
                                          self.sensors)
        self.pe_in_sensors = pe_in_sensors
        return np.abs(pe_in_sensors)

Methods

def fill_grid_from_events(self, counts_pe_on_hex)

Sum over all the patterns of LCE x number of pe per hex to get the final pe pattern in the array.

Expand source code
def fill_grid_from_events(self, counts_pe_on_hex):
    '''
    Sum over all the patterns of LCE x number of pe per hex to
    get the final pe pattern in the array.
    '''
    
    for hex_i in tqdm(range(self.mesh.n_hexes),
                      'Summing all normalized patterns. 1+1+2+3+5+8+...',
                      total = self.mesh.n_hexes):
        #pattern = load_pattern(self, hex_i)
        pattern = self.patterns[hex_i]
        if counts_pe_on_hex[hex_i] > 0:
            _zz = pattern.ev(self.grid_xx,self.grid_yy) * counts_pe_on_hex[hex_i]
            self.grid_zz += _zz
        else:
            continue
    
    self.results_interp = scipy.interpolate.RectBivariateSpline(
        self.grid_x, 
        self.grid_y,
        self.grid_zz,
        s = 0)
    return None
def integrate_in_photosensor(self, quad)

Integrate the PEs in a given photosensor.

Expand source code
def integrate_in_photosensor(self,quad):
    '''Integrate the PEs in a given photosensor.'''
    ans = self.results_interp.integral(quad[0],quad[1],quad[2],quad[3])
    return ans
def load_all_patterns(self, all_at_once=False)

Load all the patterns for all the hex focus points.

Expand source code
def load_all_patterns(self, all_at_once = False):
    '''Load all the patterns for all the hex focus points.'''
    if all_at_once:
        with open(self.path_to_patterns+'all_patterns.pck', 'rb') as file:
            patterns = pickle.load(file)
        self.patterns = patterns
        return None
    
    patterns = dict()
    for _hex_i in tqdm(range(self.mesh.n_hexes),
                       'Loading LCE patterns.',
                       total = self.mesh.n_hexes):
        patterns[_hex_i] = self.load_pattern(_hex_i)
    
    self.patterns = patterns
    
    return None
def load_pattern(self, hex_id)

Load the pattern for a given hex focus point.

Expand source code
def load_pattern(self, hex_id):
    '''Load the pattern for a given hex focus point.'''
    with open(self.path_to_patterns + 'hex_%d.pck'%hex_id, 'rb') as file:
        pattern = pickle.load(file)
    return pattern
def load_top_array(self)

Load the top array from file. THIS USES PICKLE, IT SHOULD BE CHANGED TO SOMETHING MORE ROBUST.

Expand source code
def load_top_array(self):
    '''Load the top array from file.
    **THIS USES PICKLE, IT SHOULD BE CHANGED TO SOMETHING MORE ROBUST**.'''
    with open('%s/%s.pck'%(self.path_to_model, self.model), 'rb') as file:
        self.sensors = pickle.load(file)
    self.n_sensors = len(self.sensors)
    
    return None
def make_results_grid(self, x_step=1, y_step=1)

Define the grid to discritize the LCE pattern.

Expand source code
def make_results_grid(self, x_step=1, y_step=1):
    '''Define the grid to discritize the LCE pattern.'''
    self.grid_x_step = x_step
    self.grid_y_step = y_step
    self.grid_x_max = self.tpc.radius
    self.grid_y_max = self.tpc.radius
    self.grid_x_min = -self.tpc.radius
    self.grid_y_min = -self.tpc.radius
    self.grid_x = np.arange(self.grid_x_min, 
                            self.grid_x_max,
                            self.grid_x_step)
    self.grid_y = np.arange(self.grid_y_min,
                            self.grid_y_max,
                            self.grid_y_step)
    self.grid_xx,self.grid_yy = np.meshgrid(self.grid_x,
                                            self.grid_y,
                                            indexing='ij')
    self.grid_zz = np.zeros((self.grid_yy.shape))
    return None
def n_pe_in_sensors(self)

Integrate the PEs in each photosensor.

Expand source code
def n_pe_in_sensors(self):
    '''Integrate the PEs in each photosensor.'''
    pe_in_sensors = np.apply_along_axis(self.integrate_in_photosensor,
                                      1, 
                                      self.sensors)
    self.pe_in_sensors = pe_in_sensors
    return np.abs(pe_in_sensors)
def plot_pattern(self, hex_id, save_fig=False)

Plot the pattern from a given focusing point.

Expand source code
def plot_pattern(self, hex_id, save_fig = False):
    '''Plot the pattern from a given focusing point.'''

    if hasattr(self, 'patterns'):
        pattern = self.patterns[hex_id]
    else:
        pattern = self.load_pattern(hex_id)

    fig,ax = plt.subplots(1,1,figsize = (9,9))
    ax.set_title('Pattern interpolation\n(spline, k=3)')
    _x = np.arange(-100,100,1)
    _y = np.arange(-100,100,1)
    _xx,_yy = np.meshgrid(_x,_y, indexing='ij')
    _rr = self.tpc.get_r(_xx,_yy)
    _xx = _xx[_rr < 100]
    _yy = _yy[_rr < 100]
    _zz = pattern.ev(_xx,_yy)
    interpolated = ax.scatter(_xx, _yy, c=np.log10(_zz), marker = 's',
                              s = 3, vmin = -6.2)

    ax.add_patch(Circle((0,0),self.tpc.radius, color = 'r',fill = False, 
                        linewidth = 1, ls ='--', label = 'TPC'))
    ax.set_aspect('equal')
    ax.legend()
    fig.colorbar(interpolated, ax = ax)
    if save_fig:
        plt.savefig('figures/patterns/hex_v0_%d' %hex_id)
    else:
        plt.show()
    return None
def plot_toparray(self, ax, pe_in_sensors=False)

Plot the top array and, optionally, fill with pattern from results.

Expand source code
def plot_toparray(self,ax, pe_in_sensors = False):
    '''Plot the top array and, optionally, fill with pattern from 
    results.'''

    ax.set_aspect('equal')
    for _quad_i,_quad in enumerate(self.sensors):
        xy = (_quad[0],_quad[2])
        width = _quad[1]-_quad[0]
        height = _quad[3]-_quad[2]
        if pe_in_sensors == False:
            ax.add_patch(Rectangle(xy,width,height, 
                                   fill = False, 
                                   color = 'k'))
        else:
            #TO DO
            #check if results exist and default to False
            
            cm = plt.get_cmap('gnuplot')
            log_pe = np.log10(self.pe_in_sensors)
            results_max = np.max(log_pe)
            results_min = np.min(log_pe[np.isfinite(log_pe)])
            log_pe = np.nan_to_num(log_pe, copy = True,neginf=results_min)
            results_max = np.max(log_pe)
            results_min = np.min(log_pe)
            pe = log_pe[_quad_i]

            ax.add_patch(Rectangle(xy,width,height, 
                                   fill = True, 
                                   edgecolor = 'k',
                                   facecolor = cm((pe-results_min)/
                                                  (results_max-results_min)),
                                  )
                        )
    ax.set_ylim(-90,90)
    ax.set_xlim(-90,90)
    ax.set_aspect('equal')
    ax.set_xlabel('x [mm]')
    ax.set_ylabel('y [mm]')
    ax.add_patch(Circle((0,0),75, color = 'r',fill = False))
    return ax