Skip to content
Snippets Groups Projects
EQSANSTransmission.py 10.8 KiB
Newer Older
from MantidFramework import *
from mantidsimple import *
import math

# Keep track of whether we have numpy since readX() may
# return a numpy array or a list depending on whether it
# is available.
try:
    import numpy
    HAS_NUMPY = True
except:
Doucet, Mathieu's avatar
Doucet, Mathieu committed
    HAS_NUMPY = False    

class EQSANSTransmission(PythonAlgorithm):
    """
        Calculate transmission for EQSANS
        
        Transmission counts is the signal going through a pinhole in the middle of the 
        beam stop (after hitting the sample). The number of counts is equal to the neutron
        flux times the transmission N_trans = T*Phi. The transmission T is obtained by normalizing
        the N_trans by the monitor or accelerator current. T = N_trans/current. 
        Dividing the pixel counts by T we account for transmission.         
    """
    
    # Size of the box around the beam center
    NX_TRANS_PIX = 10
    NY_TRANS_PIX = 10
    
    # To define transmission peak
    transmission_peak_to_bg_ratio = 1000
    
    # To define transmission peak mask
    min_transmission_peak_to_bg_ratio = 5
    
    def category(self):
        return "SANS"

    def name(self):
        return "EQSANSTransmission"

    def PyInit(self):
        # Input workspace
        self.declareWorkspaceProperty("InputWorkspace", "", Direction.Input)
        # Output workspace to put the transmission histo into
        self.declareProperty("OutputWorkspace", "")
        # X position of the beam center
        self.declareProperty("XCenter", 96.0)
        # Y position of the beam center
        self.declareProperty("YCenter", 128.0)
        # Transmission will be normalized to 1 if True
        self.declareProperty("NormalizeToUnity", False)


    def PyExec(self):
        input_ws = self.getProperty("InputWorkspace")
        output_ws = self.getProperty("OutputWorkspace")
        xcenter = int(math.floor(self.getProperty("XCenter")))
        ycenter = int(math.floor(self.getProperty("YCenter")))
        normalize = self.getProperty("NormalizeToUnity")

        nx_min = xcenter - self.NX_TRANS_PIX
        nx_max = xcenter + self.NX_TRANS_PIX
        ny_min = ycenter - self.NY_TRANS_PIX
        ny_max = ycenter + self.NY_TRANS_PIX

        # Sum up all TOF bins
        Integration(input_ws, input_ws+'_int')
        
        # Find pixel with highest and lowest signal
        counts_2D = numpy.zeros([2*self.NY_TRANS_PIX+1, 2*self.NX_TRANS_PIX+1])
        
        # Smallest count in a given pixel in the region around the center
        signal_min = None
        # Highest count in a given pixel in the region around the center
        signal_max = None
        # Position of the pixel with the highest count
        xmax = xcenter
        ymax = ycenter
        
        for ix in range(nx_min, nx_max+1):
            for iy in range(ny_min, ny_max+1):
                i_pixel = 256*ix+iy
                signal = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel)[0]
                
                if signal_min is None or signal < signal_min:
                    signal_min = signal
                if signal_max is None or signal > signal_max:
                    signal_max = signal
                    xmax = ix
                    ymax = iy
                        
        self.log().information("Transmission search [%d, %d] [%d, %d]" % (nx_min, nx_max, ny_min, ny_max))
                
        self.log().information("Max transmission counts at [%d, %d] = %g" % (xmax, ymax,signal_max))
        self.log().information("Min transmission counts = %g" % (signal_min))
        
        # Find transmission peak boundaries
        # The peak is defined by the area around the pixel with the highest count
        # that is above the background level.
        xpeakmax = nx_max
        for i in range(xmax+1, nx_max+1):
            i_pixel = 256*i+ymax
            signal = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel)[0]
            if signal*self.transmission_peak_to_bg_ratio < signal_max:
                xpeakmax = i-1
                break
            
            i_pixel_low = 256*(i-1)+ymax
            signal_low = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel_low)[0]
            if signal > signal_low:
                xpeakmax = i-1
                break
            
        xpeakmin = nx_min
        for i in range(xmax-1, nx_min+1, -1):
            i_pixel = 256*i+ymax
            signal = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel)[0]
            if signal*self.transmission_peak_to_bg_ratio < signal_max:
                xpeakmin = i+1
                break
            
            i_pixel_high = 256*(i+1)+ymax
            signal_high = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel_high)[0]
            if signal > signal_high:
                xpeakmin = i+1
                break
            
        ypeakmax = ny_max
        for i in range(ymax+1, ny_max+1):
            i_pixel = 256*xmax+i
            signal = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel)[0]
            if signal*self.transmission_peak_to_bg_ratio < signal_max:
                ypeakmax = i-1
                break
            
            i_pixel_low = 256*xmax+(i-1)
            signal_low = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel_low)[0]
            if signal > signal_low:
                ypeakmax = i-1
                break

        ypeakmin = ny_min
        for i in range(ymax-1, ny_min+1, -1):
            i_pixel = 256*xmax+i
            signal = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel)[0]
            if signal*self.transmission_peak_to_bg_ratio < signal_max:
                ypeakmin = i+1
                break
            
            i_pixel_high = 256*xmax+(i-1)
            signal_high = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel_high)[0]
            if signal > signal_high:
                ypeakmin = i+1
                break

        self.log().information("Peak range in X [%d, %d]" % (xpeakmin, xpeakmax))
        self.log().information("Peak range in Y [%d, %d]" % (ypeakmin, ypeakmax))

        # Mask monitor peak around the beam center
        # Question for JK: why do we do this?
        mask = []
        for ix in range(xpeakmin, xpeakmax+1):
            for iy in range(ypeakmin, ypeakmax+1):
                i_pixel = 256*ix+iy
                mask.append(i_pixel)
                
        for iy in range(ypeakmin, ypeakmax+1):
            for ix in range(xpeakmin, xcenter):
                i_pixel = 256*ix+iy
                signal = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel)[0]
                i_pixel_high = 256*(ix+1)+iy
                signal_high = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel_high)[0]
                
                if signal > signal_high and signal*self.min_transmission_peak_to_bg_ratio<signal_max: 
                    if i_pixel in mask:
                        mask.remove(i_pixel)
                else:
                    break
                
        for iy in range(ypeakmin, ypeakmax+1):
            for ix in range(xpeakmax, xcenter, -1):
                i_pixel = 256*ix+iy
                signal = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel)[0]
                i_pixel_high = 256*(ix-1)+iy
                signal_high = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel_high)[0]
                
                if signal > signal_high and signal*self.min_transmission_peak_to_bg_ratio<signal_max: 
                    if i_pixel in mask:
                        mask.remove(i_pixel)
                else:
                    break
                
        for iy in range(xpeakmin, xpeakmax+1):
            for ix in range(ypeakmin, ycenter):
                i_pixel = 256*ix+iy
                signal = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel)[0]
                i_pixel_high = 256*ix+iy+1
                signal_high = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel_high)[0]
                
                if signal > signal_high and signal*self.min_transmission_peak_to_bg_ratio<signal_max: 
                    if i_pixel in mask:
                        mask.remove(i_pixel)
                else:
                    break
                
        for iy in range(xpeakmin, xpeakmax+1):
            for ix in range(ypeakmax, ycenter, -1):
                i_pixel = 256*ix+iy
                signal = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel)[0]
                i_pixel_high = 256*ix+iy-1
                signal_high = mantid.getMatrixWorkspace(input_ws+'_int').readY(i_pixel_high)[0]
                
                if signal > signal_high and signal*self.min_transmission_peak_to_bg_ratio<signal_max: 
                    if i_pixel in mask:
                        mask.remove(i_pixel)
                else:
                    break
        
        # Sum transmission peak counts as a function of TOF
        dataX = mantid.getMatrixWorkspace(input_ws).readX(0)
        if HAS_NUMPY:
            dataX = dataX.tolist()
        nTOF = len(dataX)
        dataY = (nTOF-1)*[0]
        dataE = (nTOF-1)*[0]
        
        transmission_counts = 0
        total_pixels = 0

        # We will normalize the transmission by the accelerator current  
        proton_charge = mantid.getMatrixWorkspace(input_ws).getRun()["proton_charge"].getStatistics().mean
        duration = mantid.getMatrixWorkspace(input_ws).getRun()["proton_charge"].getStatistics().duration
        frequency = mantid.getMatrixWorkspace(input_ws).getRun()["frequency"].getStatistics().mean
        acc_current = 1.0e-12 * proton_charge * duration * frequency
        
        for itof in range(nTOF-1):
            for ix in range(xpeakmin, xpeakmax+1):
                for iy in range(ypeakmin, ypeakmax+1):
                    i_pixel = 256*ix+iy
                    signal = mantid.getMatrixWorkspace(input_ws).readY(i_pixel)[itof]
                    error = mantid.getMatrixWorkspace(input_ws).readE(i_pixel)[itof]
                    if i_pixel in mask:
                        total_pixels += 1
                        dataY[itof] += signal
                        dataE[itof] += error*error
                        transmission_counts += signal
            dataE[itof] = math.sqrt(dataE[itof])/acc_current
            dataY[itof] /= acc_current    
        
        if normalize:
            self.log().information("Normalizing the translation to average 1")
            factor = transmission_counts/acc_current/(nTOF-1)
            for itof in range(nTOF-1):
                dataY[itof] /= factor
                dataE[itof] /= factor
        
        unitX = mantid.getMatrixWorkspace(input_ws).getAxis(0).getUnit().name()
        CreateWorkspace(output_ws, dataX, dataY, dataE, NSpec=1, UnitX=unitX)
        
        total_pixels /= (nTOF-1)
        self.log().information("Total transmission counts (%d) = %g" % (total_pixels, transmission_counts))


mtd.registerPyAlgorithm(EQSANSTransmission())