Пример #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(
        )
Пример #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()
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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))
Пример #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
Пример #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
Пример #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))
Пример #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
Пример #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
Пример #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