Example #1
0
    def __init__(self, name, ele_file_name=ELE_FILE_NAME):
        ele_file = file(ele_file_name)
        ele_lines = ele_file.readlines()
        self.ChemicalSymbol = None
        for ll in ele_lines:
            l = ll.split()
            if len(l) > 0 and l[0] == name:
                self.ChemicalSymbol = name
                self.AtomicNumber = int(l[1])
                self.AtomicWeight = float(l[2])
                self.kEdge = float(l[3])
                self.FluorescenceYield = float(l[4])
                break
        if self.ChemicalSymbol == None:
            logger.error("No element %s found, please update file %s" %\
                          (name, ele_file_name))

        # The Density is re-calculated in gasmix:eval_properties
        # as partial density
        self.Density = self.AtomicWeight / MOLAR_VOLUME

        # Returns the mean ionization potential.
        # This parametrization is from Berger and Seltzer (1964);
        # see Joy's book for the reference.
        # The ionization potential is returned in keV.
        self.MeanIonizationPotential = 0.001*(9.76*self.AtomicNumber +\
                                              58.5/np.power(self.AtomicNumber, 0.19))
        # eval X section
        self.GetPhotoelectricCrossSection = self.EvalPhotoelectricCrossSection(
        )
Example #2
0
    def __init__(self, name, ele_file_name = ELE_FILE_NAME):
        ele_file  = file(ele_file_name)
        ele_lines = ele_file.readlines()
        self.ChemicalSymbol = None
        for ll in ele_lines:
            l = ll.split()
            if len(l)>0 and l[0] == name:
                self.ChemicalSymbol    = name
                self.AtomicNumber      =  int(l[1])
                self.AtomicWeight      =  float(l[2])
                self.kEdge             =  float(l[3])
                self.FluorescenceYield =  float(l[4])
                break
        if self.ChemicalSymbol == None:
            logger.error("No element %s found, please update file %s" %\
                          (name, ele_file_name))

        # The Density is re-calculated in gasmix:eval_properties
        # as partial density
        self.Density = self.AtomicWeight/MOLAR_VOLUME;  
  
        # Returns the mean ionization potential.
        # This parametrization is from Berger and Seltzer (1964);
        # see Joy's book for the reference.
        # The ionization potential is returned in keV.
        self.MeanIonizationPotential = 0.001*(9.76*self.AtomicNumber +\
                                              58.5/np.power(self.AtomicNumber, 0.19))
        # eval X section
        self.GetPhotoelectricCrossSection = self.EvalPhotoelectricCrossSection()
Example #3
0
 def GetRutherfordScreeningFactor(self, energy):
     """ \brief Returns the Rutherford screening factor at a given anergy.
     This parametrization is from Bishop (1976); see Joy's book for the
     reference.                   
     Energy to be provided in keV (accurate down to 50 eV)
     """
     if isinstance( energy , (int, float) ):
         energy = np.array([energy])
     if energy.any()< MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
         logger.error("Cannot eval screening factor below %f keV"%\
                       MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
         return -1
     return (3.4E-3)*np.power(self.AtomicNumber, 0.67)/energy
Example #4
0
 def GetRutherfordScreeningFactor(self, energy):
     """ \brief Returns the Rutherford screening factor at a given anergy.
     This parametrization is from Bishop (1976); see Joy's book for the
     reference.                   
     Energy to be provided in keV (accurate down to 50 eV)
     """
     if isinstance(energy, (int, float)):
         energy = np.array([energy])
     if energy.any() < MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
         logger.error("Cannot eval screening factor below %f keV"%\
                       MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
         return -1
     return (3.4E-3) * np.power(self.AtomicNumber, 0.67) / energy
Example #5
0
 def GetStoppingPower(self, energy):
     """ \brief Returns the stopping power at a given energy.
     This parametrization is from Joy and Luo (1989); 
     see Joy's book for the reference.
     Energy to be provided in keV, outcome in keV/cm.
     """
     if isinstance( energy , (int, float) ):
         energy = np.array([energy])
     if energy.any()< MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
         logger.error("Cannot eval StoppingPower below %f keV"%\
                       MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
         return -1
     stop_pwr = 78500*self.AtomicNumber*np.log(1.166*(energy + 0.85*self.MeanIonizationPotential)/self.MeanIonizationPotential)/(energy*self.AtomicWeight)*self.Density
     return stop_pwr
Example #6
0
 def GetElasticMeanFreePath(self, energy, mode):
     """\brief Returns the the total elestic mean free path for the mixture.
     The mean free path is evaluated by summing the inverse of the mean free
     paths for all the elements.
     Energy to be provided in keV, mode cam be either RUTHERFORD or MOTT.
     """
     if mode.lower() != "rutherford" and mode.lower() != "mott":
         logger.error("Mode can be only rutherford or mott, not %s" %\
                       mode)
         return -1
     MeanFreePath = 0.
     for elem in self.elements_list:
         MeanFreePath += 1. / (elem.GetElasticMeanFreePath(
             energy, elem.Density, mode))
     return 1. / MeanFreePath
Example #7
0
 def GetElasticMeanFreePath(self, energy, mode):
     """\brief Returns the the total elestic mean free path for the mixture.
     The mean free path is evaluated by summing the inverse of the mean free
     paths for all the elements.
     Energy to be provided in keV, mode cam be either RUTHERFORD or MOTT.
     """
     if mode.lower() != "rutherford" and mode.lower() != "mott":
         logger.error("Mode can be only rutherford or mott, not %s" %\
                       mode)
         return -1
     MeanFreePath = 0.
     for elem in self.elements_list:
         MeanFreePath += 1./(elem.GetElasticMeanFreePath(energy,
                                                         elem.Density,
                                                         mode))
     return 1./MeanFreePath
Example #8
0
 def GetStoppingPower(self, energy):
     """ \brief Returns the stopping power at a given energy.
     This parametrization is from Joy and Luo (1989); 
     see Joy's book for the reference.
     Energy to be provided in keV, outcome in keV/cm.
     """
     if isinstance(energy, (int, float)):
         energy = np.array([energy])
     if energy.any() < MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
         logger.error("Cannot eval StoppingPower below %f keV"%\
                       MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
         return -1
     stop_pwr = 78500 * self.AtomicNumber * np.log(
         1.166 * (energy + 0.85 * self.MeanIonizationPotential) /
         self.MeanIonizationPotential) / (energy *
                                          self.AtomicWeight) * self.Density
     return stop_pwr
Example #9
0
 def GetMottTotalCrossSection(self, energy):
     """\brief Returns the Mott integral cross section at a given energy.
     This parametrization is given to Browning (1992); see Joy's book 
     for the reference
     Energy to be provided in keV, cross section returned in cm^2/atom.
     (accurate down to 50 eV).
     """
     if isinstance( energy , (int, float) ):
         energy = np.array([energy])
     if energy.any()< MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
         logger.error("Cannot eval Mott X section below %f keV"%\
                       MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
         return -1
     
     u = np.log10(8*energy*np.power(self.AtomicNumber, -1.33))
     out = (4.7E-18)*(np.power(self.AtomicNumber, 1.33) + 0.032*np.power(self.AtomicNumber, 2.0))/((energy + 0.0155*np.power(self.AtomicNumber, 1.33)*np.power(energy, 0.5))*(1 - 0.02*np.power(self.AtomicNumber, 0.5)*np.exp(-u*u)))
     return out
Example #10
0
 def GetScatteringElement(self, energy, mode, r0):
     """ \brief EXTRACTthe element scattering a travelling photoelectron.
     The element in the mixture is extracted according to the relative 
     values ofthe elastic cross sections at a given energy.
     Energy to be provided in keV, mode can be either RUTHERFORD OR MOTT.
     """
     total_x_sect = self.GetElasticMeanFreePath(energy, mode)  # 1/x-section
     partial_probability = 0
     for elem in self.elements_list:
         scat_prob = total_x_sect / elem.GetElasticMeanFreePath(
             energy, elem.Density, mode)
         if (r0 < partial_probability + scat_prob):
             return elem
         partial_probability += scat_prob
     # this should never happen!
     logger.error("Scattering element not extracted!!!")
     return None
Example #11
0
 def GetConvertingElement(self, energy, r0):
     """ \brief EXTRACT the element converting an incoming photon.
     The element in the mixture is extracted according to 
     the relative values of the photoelectric cross sections 
     at a given energy.
     Energy to be provided in keV.
     """
     total_x_sect = self.GetPhotoelectricCrossSection(energy)*self.Density
     partial_probability = 0
     for elem in self.elements_list:
         absorption_prob = elem.GetPhotoelectricCrossSection(energy)*elem.Density/total_x_sect
         if (r0 < partial_probability+absorption_prob):
             return elem
         partial_probability += absorption_prob
     # this should never happen!
     logger.error("Converting element not extracted!!!")
     return None
Example #12
0
 def GetConvertingElement(self, energy, r0):
     """ \brief EXTRACT the element converting an incoming photon.
     The element in the mixture is extracted according to 
     the relative values of the photoelectric cross sections 
     at a given energy.
     Energy to be provided in keV.
     """
     total_x_sect = self.GetPhotoelectricCrossSection(energy) * self.Density
     partial_probability = 0
     for elem in self.elements_list:
         absorption_prob = elem.GetPhotoelectricCrossSection(
             energy) * elem.Density / total_x_sect
         if (r0 < partial_probability + absorption_prob):
             return elem
         partial_probability += absorption_prob
     # this should never happen!
     logger.error("Converting element not extracted!!!")
     return None
Example #13
0
 def GetScatteringElement(self, energy, mode, r0):
     """ \brief EXTRACTthe element scattering a travelling photoelectron.
     The element in the mixture is extracted according to the relative 
     values ofthe elastic cross sections at a given energy.
     Energy to be provided in keV, mode can be either RUTHERFORD OR MOTT.
     """
     total_x_sect = self.GetElasticMeanFreePath(energy, mode) # 1/x-section
     partial_probability = 0
     for elem in self.elements_list:
         scat_prob = total_x_sect/elem.GetElasticMeanFreePath(energy,
                                                              elem.Density,
                                                              mode)
         if (r0 < partial_probability+scat_prob):
             return elem
         partial_probability += scat_prob
     # this should never happen!
     logger.error("Scattering element not extracted!!!")
     return None
Example #14
0
    def GetRutherfordTotalCrossSection(self, energy):
        """\brief Returns the Rutherford integral cross section.  
        This parametrization is given to Newbury and Myklebust (1981); see
        Joy's book for the reference.  
        Energy to be provided in keV, cross section returned in cm^2/atom 
        (accurate down to 50 eV). 
        """
        if isinstance(energy, (int, float)):
            energy = np.array([energy])
        if energy.any() < MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
            logger.error("Cannot eval Rutherford X section below %f keV"%\
                          MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
            return -1

        alpha = self.GetRutherfordScreeningFactor(energy)
        xsection = 5.21e-21
        xsection *= (np.power(self.AtomicNumber, 2.0) / np.power(energy, 2.0))
        xsection *= (4 * np.pi / (alpha * (1 + alpha)))
        xsection *= np.power(((energy + 511) / (energy + 1024)), 2.0)
        return xsection
Example #15
0
 def GetRutherfordTotalCrossSection(self, energy):
     """\brief Returns the Rutherford integral cross section.  
     This parametrization is given to Newbury and Myklebust (1981); see
     Joy's book for the reference.  
     Energy to be provided in keV, cross section returned in cm^2/atom 
     (accurate down to 50 eV). 
     """
     if isinstance( energy , (int, float) ):
         energy = np.array([energy])
     if energy.any()< MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
         logger.error("Cannot eval Rutherford X section below %f keV"%\
                       MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
         return -1
     
     alpha = self.GetRutherfordScreeningFactor(energy);
     xsection = 5.21e-21
     xsection *= (np.power(self.AtomicNumber, 2.0)/np.power(energy, 2.0))
     xsection *= (4*np.pi/(alpha*(1 + alpha)))
     xsection *= np.power(((energy + 511)/(energy + 1024)), 2.0)
     return xsection
Example #16
0
 def __init__(self, name, fraction, comp_file_name = COMP_FILE_NAME):
     """ Init compound and eval properties from table
     """
     self.name = name
     self.fraction = fraction
     comp_file = file(comp_file_name)
     comp_lines = comp_file.readlines()
     self.n_elements = 0
     self.elements = []
     self.atoms    = []        
     for ll in comp_lines:
         l = ll.split()
         if l[0] == self.name:
             self.n_elements = int(l[1])
             self.NIonsT     = float(l[2]) # total ionization/cm
             self.StoppingP  = float(l[3]) # de/dx in ev/cm
             for i in range(4, len(l), 2):
                 self.elements.append(l[i])
                 self.atoms.append(int(l[i+1]))
     if self.n_elements == 0:
         logger.error("No compound %s found, please update file %s" %\
                       (self.name, comp_file_name))
Example #17
0
 def GetScatteringAngle(self, energy, mode, r0, r1):
     """Returns a RANDOM scattering angle at a given energy.
     Energy to be provided in keV; mode can be either RUTHERFORD or MOTT.
     The cosine of the angle is returned.
     r0 and r1 are 2 random number (from external generator)
     """
     if isinstance( energy , (int, float) ):
         energy = np.array([energy])
     if energy.any()< MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
         logger.error("Cannot eval Scattering Angle below %f keV"%\
                       MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
         return -1
     screening_factor = self.GetRutherfordScreeningFactor(energy)
     if mode.lower()=='rutherford':
         return np.arccos(1.-(2.*screening_factor*r0)/(1.+screening_factor-r1))
     elif mode.lower()=='mott':
         CorrectionFactor = 2.2 - ((92.0 - self.AtomicNumber)/92.0);
         return np.arccos(1.-(2.*screening_factor*np.power((r0), CorrectionFactor))/(1.+screening_factor-r1))
     else:
         logger.error("Mode can be only rutherford or mott, not %s" %\
                       mode)
         return -1
Example #18
0
    def GetMottTotalCrossSection(self, energy):
        """\brief Returns the Mott integral cross section at a given energy.
        This parametrization is given to Browning (1992); see Joy's book 
        for the reference
        Energy to be provided in keV, cross section returned in cm^2/atom.
        (accurate down to 50 eV).
        """
        if isinstance(energy, (int, float)):
            energy = np.array([energy])
        if energy.any() < MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
            logger.error("Cannot eval Mott X section below %f keV"%\
                          MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
            return -1

        u = np.log10(8 * energy * np.power(self.AtomicNumber, -1.33))
        out = (4.7E-18) * (
            np.power(self.AtomicNumber, 1.33) +
            0.032 * np.power(self.AtomicNumber, 2.0)) / (
                (energy + 0.0155 * np.power(self.AtomicNumber, 1.33) *
                 np.power(energy, 0.5)) *
                (1 - 0.02 * np.power(self.AtomicNumber, 0.5) * np.exp(-u * u)))
        return out
Example #19
0
 def __init__(self, name, fraction, comp_file_name=COMP_FILE_NAME):
     """ Init compound and eval properties from table
     """
     self.name = name
     self.fraction = fraction
     comp_file = file(comp_file_name)
     comp_lines = comp_file.readlines()
     self.n_elements = 0
     self.elements = []
     self.atoms = []
     for ll in comp_lines:
         l = ll.split()
         if l[0] == self.name:
             self.n_elements = int(l[1])
             self.NIonsT = float(l[2])  # total ionization/cm
             self.StoppingP = float(l[3])  # de/dx in ev/cm
             for i in range(4, len(l), 2):
                 self.elements.append(l[i])
                 self.atoms.append(int(l[i + 1]))
     if self.n_elements == 0:
         logger.error("No compound %s found, please update file %s" %\
                       (self.name, comp_file_name))
Example #20
0
    def GetElasticMeanFreePath(self, energy, density, mode):
        """\brief Returns the mean free path for elastic collisions 
        at a given energy.
        Energy to be provided in keV, density in g/cm^3; mode can be either
        RUTHERFORD or MOTT. The mean free path is returned in cm.
        """
        if isinstance( energy , (int, float) ):
            energy = np.array([energy])
        if energy.any()< MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
            logger.error("Cannot eval ElasticMeanFreePath below %f keV"%\
                          MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
            return -1

        MeanFreePath = self.AtomicWeight/(AVOGADRO_NUMBER*density)
        if mode.lower()=='rutherford':
            MeanFreePath /= self.GetRutherfordTotalCrossSection(energy);
            return MeanFreePath;
        elif mode.lower()=='mott':
            MeanFreePath /= self.GetMottTotalCrossSection(energy);
            return MeanFreePath;
        else:
            logger.error("Mode can be only rutherford or mott, not %s" %\
                          mode)
            return -1
Example #21
0
    def GetElasticMeanFreePath(self, energy, density, mode):
        """\brief Returns the mean free path for elastic collisions 
        at a given energy.
        Energy to be provided in keV, density in g/cm^3; mode can be either
        RUTHERFORD or MOTT. The mean free path is returned in cm.
        """
        if isinstance(energy, (int, float)):
            energy = np.array([energy])
        if energy.any() < MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
            logger.error("Cannot eval ElasticMeanFreePath below %f keV"%\
                          MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
            return -1

        MeanFreePath = self.AtomicWeight / (AVOGADRO_NUMBER * density)
        if mode.lower() == 'rutherford':
            MeanFreePath /= self.GetRutherfordTotalCrossSection(energy)
            return MeanFreePath
        elif mode.lower() == 'mott':
            MeanFreePath /= self.GetMottTotalCrossSection(energy)
            return MeanFreePath
        else:
            logger.error("Mode can be only rutherford or mott, not %s" %\
                          mode)
            return -1
Example #22
0
 def GetScatteringAngle(self, energy, mode, r0, r1):
     """Returns a RANDOM scattering angle at a given energy.
     Energy to be provided in keV; mode can be either RUTHERFORD or MOTT.
     The cosine of the angle is returned.
     r0 and r1 are 2 random number (from external generator)
     """
     if isinstance(energy, (int, float)):
         energy = np.array([energy])
     if energy.any() < MIN_ANALYTIC_CROSS_SECTIONS_ENERGY:
         logger.error("Cannot eval Scattering Angle below %f keV"%\
                       MIN_ANALYTIC_CROSS_SECTIONS_ENERGY)
         return -1
     screening_factor = self.GetRutherfordScreeningFactor(energy)
     if mode.lower() == 'rutherford':
         return np.arccos(1. - (2. * screening_factor * r0) /
                          (1. + screening_factor - r1))
     elif mode.lower() == 'mott':
         CorrectionFactor = 2.2 - ((92.0 - self.AtomicNumber) / 92.0)
         return np.arccos(1. - (2. * screening_factor * np.power(
             (r0), CorrectionFactor)) / (1. + screening_factor - r1))
     else:
         logger.error("Mode can be only rutherford or mott, not %s" %\
                       mode)
         return -1