示例#1
0
 def _getChantler(self, element, energy, column='f1', smoothing=0):
     """return energy-dependent data from Chantler table
     columns: f1, f2, mu_photo, mu_incoh, mu_total
     """
     tab = ChantlerTable
     row = self.query(tab)
     if isinstance(element, int):
         row = row.filter(tab.id == element).all()
     else:
         row = row.filter(tab.element == element.title()).all()
     if len(row) > 0:
         row = row[0]
     if isinstance(row, tab):
         energy = as_ndarray(energy)
         emin, emax = min(energy), max(energy)
         # te = self.chantler_energies(element, emin=emin, emax=emax)
         te = np.array(json.loads(row.energy))
         nemin = max(0, -5 + max(np.where(te <= emin)[0]))
         nemax = min(len(te), 6 + max(np.where(te <= emax)[0]))
         region = np.arange(nemin, nemax)
         te = te[region]
         if column == 'mu':
             column = 'mu_total'
         ty = np.array(json.loads(getattr(row, column)))[region]
         if column == 'f1':
             out = UnivariateSpline(te, ty, s=smoothing)(energy)
         else:
             out = np.exp(np.interp(np.log(energy), np.log(te), np.log(ty)))
         if isinstance(out, np.ndarray) and len(out) == 1:
             return out[0]
         return out
示例#2
0
 def _getChantler(self, element, energy, column='f1', smoothing=0):
     """return energy-dependent data from Chantler table
     columns: f1, f2, mu_photo, mu_incoh, mu_total
     """
     tab = ChantlerTable
     row = self.query(tab)
     if isinstance(element, int):
         row = row.filter(tab.id==element).all()
     else:
         row = row.filter(tab.element==element.title()).all()
     if len(row) > 0:
         row = row[0]
     if isinstance(row, tab):
         energy = as_ndarray(energy)
         emin, emax = min(energy), max(energy)
         # te = self.chantler_energies(element, emin=emin, emax=emax)
         te = np.array(json.loads(row.energy))
         nemin = max(0, -5 + max(np.where(te<=emin)[0]))
         nemax = min(len(te), 6 + max(np.where(te<=emax)[0]))
         region = np.arange(nemin, nemax)
         te = te[region]
         if column == 'mu':
             column = 'mu_total'
         ty = np.array(json.loads(getattr(row, column)))[region]
         if column == 'f1':
             out = UnivariateSpline(te, ty, s=smoothing)(energy)
         else:
             out = np.exp(np.interp(np.log(energy),
                                    np.log(te),
                                    np.log(ty)))
         if isinstance(out, np.ndarray) and len(out) == 1:
             return out[0]
         return out
示例#3
0
    def f0(self, ion, q):
        """Calculate f0(q) -- elastic x-ray scattering factor
        from Waasmaier and Kirfel

        arguments
        ---------
        ion:  atomic number, atomic symbol or ionic symbol
              (case insensitive) of scatterer

        q: single q value, list, tuple, or numpy array of q value
             q = sin(theta) / lambda
             theta = incident angle, lambda = x-ray wavelength

        Z values from 1 to 98 (and symbols 'H' to 'Cf') are supported.
        The list of ionic symbols can be read with the function .f0_ions()
        """
        tab = WaasmaierTable
        row = self.query(tab)
        if isinstance(ion, int):
            row = row.filter(tab.atomic_number == ion).all()
        else:
            row = row.filter(tab.ion == ion.title()).all()
        if len(row) > 0:
            row = row[0]
        if isinstance(row, tab):
            q = as_ndarray(q)
            f0 = row.offset
            for s, e in zip(json.loads(row.scale), json.loads(row.exponents)):
                f0 += s * np.exp(-e * q * q)
            return f0
示例#4
0
    def f0(self, ion, q):
        """Calculate f0(q) -- elastic x-ray scattering factor
        from Waasmaier and Kirfel

        arguments
        ---------
        ion:  atomic number, atomic symbol or ionic symbol
              (case insensitive) of scatterer

        q: single q value, list, tuple, or numpy array of q value
             q = sin(theta) / lambda
             theta = incident angle, lambda = x-ray wavelength

        Z values from 1 to 98 (and symbols 'H' to 'Cf') are supported.
        The list of ionic symbols can be read with the function .f0_ions()
        """
        tab = WaasmaierTable
        row = self.query(tab)
        if isinstance(ion, int):
            row = row.filter(tab.atomic_number==ion).all()
        else:
            row = row.filter(tab.ion==ion.title()).all()
        if len(row) > 0:
            row = row[0]
        if isinstance(row, tab):
            q = as_ndarray(q)
            f0 = row.offset
            for s, e in zip(json.loads(row.scale), json.loads(row.exponents)):
                f0 += s * np.exp(-e*q*q)
            return f0
示例#5
0
    def Elam_CrossSection(self, element, energies, kind='photo'):
        """returns Elam Cross Section values for an element and energies

        arguments
        ---------
        element:  atomic number, atomic symbol for element

        energies: energies in eV to calculate cross-sections
        kind:     one of 'photo', 'coh', and 'incoh' for photo-absorption,
                  coherent scattering, and incoherent scattering
                  cross sections, respectively.

        Data from Elam, Ravel, and Sieber.
        """
        if isinstance(element, int):
            element = self.symbol(element)
        energies = 1.0 * as_ndarray(energies)

        tab = ScatteringTable
        if kind == 'photo':
            tab = PhotoAbsorptionTable
        row = self.query(tab).filter(tab.element == element.title()).all()
        if len(row) > 0:
            row = row[0]
        if not isinstance(row, tab):
            return None

        tab_lne = np.array(json.loads(row.log_energy))
        if kind.lower().startswith('coh'):
            tab_val = np.array(json.loads(row.log_coherent_scatter))
            tab_spl = np.array(json.loads(row.log_coherent_scatter_spline))
        elif kind.lower().startswith('incoh'):
            tab_val = np.array(json.loads(row.log_incoherent_scatter))
            tab_spl = np.array(json.loads(row.log_incoherent_scatter_spline))
        else:
            tab_val = np.array(json.loads(row.log_photoabsorption))
            tab_spl = np.array(json.loads(row.log_photoabsorption_spline))

        emin_tab = 10 * int(0.102 * np.exp(tab_lne[0]))
        energies[np.where(energies < emin_tab)] = emin_tab
        out = np.exp(elam_spline(tab_lne, tab_val, tab_spl, np.log(energies)))
        if len(out) == 1:
            return out[0]
        return out
示例#6
0
    def Elam_CrossSection(self, element, energies, kind='photo'):
        """returns Elam Cross Section values for an element and energies

        arguments
        ---------
        element:  atomic number, atomic symbol for element

        energies: energies in eV to calculate cross-sections
        kind:     one of 'photo', 'coh', and 'incoh' for photo-absorption,
                  coherent scattering, and incoherent scattering
                  cross sections, respectively.

        Data from Elam, Ravel, and Sieber.
        """
        if isinstance(element, int):
            element = self.symbol(element)
        energies = 1.0 * as_ndarray(energies)

        tab = ScatteringTable
        if kind == 'photo':
            tab = PhotoAbsorptionTable
        row = self.query(tab).filter(tab.element==element.title()).all()
        if len(row) > 0:
            row = row[0]
        if not isinstance(row, tab):
            return None

        tab_lne = np.array(json.loads(row.log_energy))
        if kind.lower().startswith('coh'):
            tab_val = np.array(json.loads(row.log_coherent_scatter))
            tab_spl = np.array(json.loads(row.log_coherent_scatter_spline))
        elif kind.lower().startswith('incoh'):
            tab_val = np.array(json.loads(row.log_incoherent_scatter))
            tab_spl = np.array(json.loads(row.log_incoherent_scatter_spline))
        else:
            tab_val = np.array(json.loads(row.log_photoabsorption))
            tab_spl = np.array(json.loads(row.log_photoabsorption_spline))

        emin_tab = 10*int(0.102*np.exp(tab_lne[0]))
        energies[np.where(energies < emin_tab)] = emin_tab
        out = np.exp(elam_spline(tab_lne, tab_val, tab_spl, np.log(energies)))
        if len(out) == 1:
            return out[0]
        return out
示例#7
0
def elam_spline(xin, yin, yspl_in, x):
    """ interpolate values from Elam photoabsorption and scattering tables,
    according to Elam, Numerical Recipes.  Calc borrowed from D. Dale.
    """
    x = as_ndarray(x)
    x[np.where(x < min(xin))] = min(xin)
    x[np.where(x > max(xin))] = max(xin)

    lo, hi = np.array([
        (np.flatnonzero(xin < e)[-1], np.flatnonzero(xin > e)[0]) for e in x
    ]).transpose()

    diff = xin[hi] - xin[lo]
    if any(diff <= 0):
        raise ValueError('x must be strictly increasing')
    a = (xin[hi] - x) / diff
    b = (x - xin[lo]) / diff
    return (a * yin[lo] + b * yin[hi] + (diff * diff / 6) *
            ((a * a - 1) * a * yspl_in[lo] + (b * b - 1) * b * yspl_in[hi]))
示例#8
0
def elam_spline(xin, yin, yspl_in, x):
    """ interpolate values from Elam photoabsorption and scattering tables,
    according to Elam, Numerical Recipes.  Calc borrowed from D. Dale.
    """
    x = as_ndarray(x)
    x[np.where(x < min(xin))] =  min(xin)
    x[np.where(x > max(xin))] =  max(xin)

    lo, hi = np.array([(np.flatnonzero(xin < e)[-1],
                        np.flatnonzero(xin > e)[0])
                       for e in x]).transpose()

    diff = xin[hi] - xin[lo]
    if any(diff <= 0):
        raise ValueError('x must be strictly increasing')
    a = (xin[hi] - x) / diff
    b = (x - xin[lo]) / diff
    return (a * yin[lo] + b * yin[hi] +
            (diff*diff/6) * ((a*a - 1) * a * yspl_in[lo] +
                             (b*b - 1) * b * yspl_in[hi] ))
示例#9
0
def f1f2(z, energies, width=None, edge=None, _larch=None):
    """Return anomalous scattering factors f1, f2 from Cromer-Liberman

    Look-up and return f1, f2 for an element and array of energies
    from Cromer-Liberman (Cowan-Brennan implementation)

    Parameters
    ----------
    z:         atomic number of element
    energies:  array of x-ray energies (in eV)
    width:     width used to convolve values with lorentzian profile
    edge:      x-ray edge ('K', 'L3', etc) used to lookup energy
               width for convolution.

    Returns:
    ---------
    f1, f2:    anomalous scattering factors

    """
    global CLLIB
    if CLLIB is None:
        CLLIB = get_dll('cldata')

    en = as_ndarray(energies)

    if not isinstance(z, int):
        z  = atomic_number(z, _larch=_larch)
        if z is None:
            return None

    if z > 92:
        print( 'Cromer-Liberman data not available for Z>92')
        return

    if edge is not None or width is not None and _larch is not None:
        natwid = core_width(element=z, edge=edge, _larch=_larch)
        if width is None and natwid not in (None, []):
            width = natwid

    if width is not None: # will convolve!
        e_extra = int(width*80.0)
        estep = (en[1:] - en[:-1]).min()
        emin = min(en) - e_extra
        emax = max(en) + e_extra

        npts = 1 + abs(emax-emin+estep*0.02)/abs(estep)
        en   = np.linspace(emin, emax, npts)
        nk   = int(e_extra / estep)
        sig  = width/2.0
        lor  = (1./(1 + ((np.arange(2*nk+1)-nk*1.0)/sig)**2))/(np.pi*sig)
        scale = lor.sum()

    # create ctypes pointers for the C function
    npts   = len(en)
    p_z    = ctypes.pointer(ctypes.c_int(int(z)))
    p_npts = ctypes.pointer(ctypes.c_int(npts))
    p_en   = (npts*ctypes.c_double)()
    p_f1   = (npts*ctypes.c_double)()
    p_f2   = (npts*ctypes.c_double)()

    for i in range(npts):
        p_en[i] = en[i]

    nout = CLLIB.f1f2(p_z, p_npts, p_en, p_f1, p_f2)
    f1 = np.array([i for i in p_f1[:]])
    f2 = np.array([i for i in p_f2[:]])
    if width is not None: # do the convolution
        f1 = np.interp(energies, en, convolve(f1, lor)[nk:-nk])/scale
        f2 = np.interp(energies, en, convolve(f2, lor)[nk:-nk])/scale
    return (f1, f2)
示例#10
0
def f1f2(z, energies, width=None, edge=None, _larch=None):
    """Return anomalous scattering factors f1, f2 from Cromer-Liberman

    Look-up and return f1, f2 for an element and array of energies
    from Cromer-Liberman (Cowan-Brennan implementation)

    Parameters
    ----------
    z:         atomic number of element
    energies:  array of x-ray energies (in eV)
    width:     width used to convolve values with lorentzian profile
    edge:      x-ray edge ('K', 'L3', etc) used to lookup energy
               width for convolution.

    Returns:
    ---------
    f1, f2:    anomalous scattering factors

    """
    global CLLIB
    if CLLIB is None:
        CLLIB = get_dll('cldata')

    en = as_ndarray(energies)

    if not isinstance(z, int):
        z = atomic_number(z, _larch=_larch)
        if z is None:
            return None

    if z > 92:
        print('Cromer-Liberman data not available for Z>92')
        return

    if edge is not None or width is not None and _larch is not None:
        natwid = core_width(element=z, edge=edge, _larch=_larch)
        if width is None and natwid not in (None, []):
            width = natwid

    if width is not None:  # will convolve!
        e_extra = int(width * 80.0)
        estep = (en[1:] - en[:-1]).min()
        emin = min(en) - e_extra
        emax = max(en) + e_extra

        npts = 1 + abs(emax - emin + estep * 0.02) / abs(estep)
        en = np.linspace(emin, emax, npts)
        nk = int(e_extra / estep)
        sig = width / 2.0
        lor = (1. /
               (1 +
                ((np.arange(2 * nk + 1) - nk * 1.0) / sig)**2)) / (np.pi * sig)
        scale = lor.sum()

    # create ctypes pointers for the C function
    npts = len(en)
    p_z = ctypes.pointer(ctypes.c_int(int(z)))
    p_npts = ctypes.pointer(ctypes.c_int(npts))
    p_en = (npts * ctypes.c_double)()
    p_f1 = (npts * ctypes.c_double)()
    p_f2 = (npts * ctypes.c_double)()

    for i in range(npts):
        p_en[i] = en[i]

    nout = CLLIB.f1f2(p_z, p_npts, p_en, p_f1, p_f2)
    f1 = np.array([i for i in p_f1[:]])
    f2 = np.array([i for i in p_f2[:]])
    if width is not None:  # do the convolution
        f1 = np.interp(energies, en, convolve(f1, lor)[nk:-nk]) / scale
        f2 = np.interp(energies, en, convolve(f2, lor)[nk:-nk]) / scale
    return (f1, f2)