| Larch: Data Analysis Tools for X-ray Spectroscopy

\(\newcommand{\AA}{\unicode{x212B}}\)

# 15. X-ray Databases

An important aspect of X-ray spectroscopies and scattering analysis is having access to tabulated values for X-ray properties of various elements and compounds. Larch provides several functions to access these X-ray properties, which can be broken into two general categories: X-ray properties of elements, and properties of materials and compounds by chemical formula.

The first category includes basic atomic properties like atomic number and mass, and consists of tabulated values of characteristic energies and transition probabilites for core electron levels, absorption cross-sections, elastic scattering terms, and anomalous scattering factors. The second category allows these elemental properties to be applied to common compounds by name or by chemical formula.

Much of the X-ray spectroscopic data comes from the compilation of Elam et al [Elam, Ravel, and Sieber (2002)]. The core-hole widths for excited electronic levels comes from Keski-Rahkonen and Krause [Keski-Rahkonen and Krause (1974)] and Krause and Oliver [Krause and Oliver (1979)], while elastic X-ray scattering data, \(f_0(q)\),is derived from Waasmaier and Kirfel [Waasmaier and Kirfel (1995)]. Anomalous cross-sections are available as based on the work of Cromer and Liberman [Cromer and Liberman (1981)], using the implementation of Brennan and Cowan [Brennan and Cowan (1992)]. In addition, values for absorption cross-sections and anomalous X-ray scattering factors from Chantler [Chanter (2000)] (as from https://www.nist.gov/pml/data/ffast/index.cfm) are available. Except for the anomalous cross-section data from Cromer and Liberman (which is implemented using the Fortran routine by Brennan and Cowan with slight modifications), the data is accessed through a portable SQLite3 database file. This implementation was originally done by Darren Dale from CHESS (see https://github.com/praxes/elam_physical_reference), with some additions and alterations made for Larch.

## 15.1. X-ray Properties of the Elements

The Table of X-ray data functions gives a brief description to the available functions for accessing these data. More detailed descriptions of function arguments, returned values, and so on are then given.

> Table of X-ray database functions for the Elements. These functions calculate and return some element-specific properties, given the element symbol or atomic number. Most data extends to Z=98 (Cf). Data for elements with atomic number > 92 (U) may not be available and when provided may not be very reliable. Except where noted, the data comes from Elam, Ravel, and Sieber.

> > function | description
> > --- | ---
> > `atomic_number()` | atomic number from symbol
> > `atomic_symbol()` | atomic symbol from number
> > `atomic_mass()` | atomic mass
> > `atomic_density()` | atomic density (for pure element)
> > `xray_edge()` | xray edge data for a particular element and edge
> > `xray_line()` | xray emission line data for an element and line
> > `xray_edges()` | dictionary of all X-ray edges data for an element
> > `xray_lines()` | dictionary of all X-ray emission line data for an element
> > `fluo_yield()` | fluorescence yield and weighted line energy
> > `core_width()` | core level width for an element and edge (Keski-Rahkonen and Krause, Krause and Oliver)
> > `mu_elam()` | absorption cross-section
> > `coherent_xsec()` | coherent cross-section
> > `incoherent_xsec()` | incoherent cross-section
> > `f0()` | elastic scattering factor (Waasmaier and Kirfel)
> > `f0_ions()` | list of valid “ions” for `f0()` (Waasmaier and Kirfel)
> > `chantler_energies()` | energies of tabulation for Chantler data (Chantler)
> > `f1_chantler()` | f’ anomalous factor (Chantler)
> > `f2_chantler()` | f’’ anomalous factor (Chantler)
> > `mu_chantler()` | absorption cross-section (Chantler)
> > `xray_delta_beta()` | anomalous components of the index of refraction for a material
> > `f1f2_cl()` | f’ and f’’ anomalous factors (Cromer and Liberman)

A few conventions used in these functions is worth mentioning. Almost all these functions require an element to be specified for the first argment, noted as `z_or_symbol` in the functions below. This can either be a valid atomic number or a case-insensitive atomic symbol. Thus, `28`, `Co` and `co` all specify cobalt. Several functions take either an `edge` or a `level` argument to signify an core electronic level. These must be one of the levels listed in the Table of X-ray edge names. Some functions take emission line arguments. These follow the latinized version of the Siegbahn notation as indicated in the Table of X-ray emission line names. Finally, all energies are in eV.

> > Table of X-ray Edge / Core electronic levels

> Name | electronic level | Name | electronic level | Name | electronic level
> --- | --- | --- | --- | --- | ---
> K | 1s | N7 | 4f7/2 | O3 | 5p3/2
> L3 | 2p3/2 | N6 | 4f5/2 | O2 | 5p1/2
> L2 | 2p1/2 | N5 | 4d5/2 | O1 | 5s
> L1 | 2s | N4 | 4d3/2 | P3 | 6p3/2
> M5 | 3d5/2 | N3 | 4p3/2 | P2 | 6p1/2
> M4 | 3d3/2 | N2 | 4p1/2 | P1 | 6s
> M3 | 3p3/2 | N1 | 4s |  |
> M2 | 3p1/2 |  |  |  |
> M1 | 3s |  |  |  |

> > Table of X-ray emission line names and the corresponding Siegbahn and IUPAC notations

> Name | Siegbahn | IUPAC | Name | Siegbahn | IUPAC
> --- | --- | --- | --- | --- | ---
> Ka1 | \(K\alpha_1\) | K-L3 | Lb4 | \(L\beta_4\) | L1-M2
> Ka2 | \(K\alpha_2\) | K-L2 | Lb5 | \(L\beta_5\) | L3-O4,5
> Ka3 | \(K\alpha_3\) | K-L1 | Lb6 | \(L\beta_6\) | L3-N1
> Kb1 | \(K\beta_1\) | K-M3 | Lg1 | \(L\gamma_1\) | L2-N4
> Kb2 | \(K\beta_2\) | K-N2,3 | Lg2 | \(L\gamma_2\) | L1-N2
> Kb3 | \(K\beta_3\) | K-M2 | Lg3 | \(L\gamma_3\) | L1-N3
> Kb4 | \(K\beta_2\) | K-N4,5 | Lg6 | \(L\gamma_6\) | L2-O4
> Kb5 | \(K\beta_3\) | K-M4,5 | Ll | \(Ll\) | L3-M1
> La1 | \(L\alpha_1\) | L3-M5 | Ln | \(L\nu\) | L2-M1
> La2 | \(L\alpha_1\) | L3-M4 | Ma | \(M\alpha\) | M5-N6,7
> Lb1 | \(L\beta_1\) | L2-M4 | Mb | \(M\beta\) | M4-N6
> Lb2,15 | \(L\beta_2,L\beta_{15}\) | L3-N4,5 | Mg | \(M\gamma\) | M3-N5
> Lb3 | \(L\beta_3\) | L1-M3 | Mz | \(M\zeta\) | M4,5-N6,7

_xray.atomic_number(symbol)

  return the atomic number from an atomic symbol (‘H’, ‘C’, ‘Fe’, etc)

_xray.atomic_symbol(z)

  return the atomic symbol from an atomic number

_xray.atomic_mass(z_or_symbol)

  return the atomic mass in amu from an atomic number or symbol

_xray.atomic_density(z_or_symbol)

  return the density of the common form of a pure element, in gr/cm^3, from an atomic number or symbol.

_xray.xray_edge(z_or_symbol, edge_name)

  return (edge energy, fluorescence yield, edge jump) for an atomic number or symbol and name of the edge. Edge energies are in eV.

_xray.xray_line(z_or_symbol, line_name)

  return (emission energy, intensity, initial level, final level)for an atomic number or symbol and name of the emission line. The intensity is the probability of emission from the given initial level.

_xray.xray_edges(z_or_symbol)

  return dictionary of all (edge energy, fluorescence yield, edge jump) for an atomic number or symbol. The keys of the dictionay are the names of the edges.

_xray.xray_lines(z_or_symbol)

  return dictionary of all (emission energy, intensity, initial level, final level for an atomic number or symbol. The keys of the dictionay are the names of the emission lines.

_xray.fluo_yield(z_or_symbol, edge, emission_family, incident_energy, energy_margin=-150)

  return (fluorescent yield, average emission energy, probability) for an atomic number or symbol, edge, emission family, and incident energy.

  Here, ‘emission family’ is the family of emission lines, ‘Ka’, ‘Lb’, etc, that is comprised of several individual lines (‘Ka1’, ‘Ka2’, ‘Lb2’, etc). The returned average emission energy will be the average of the corresponding individual sub-line energies, weighted by the probabilities of the individual lines. The returned probability will be the total probability for all lines in the family.

  The fluorescence yield will also be returned, giving the same value as `xray_edge()` if the provided incident_energy is above or near the corresponding edge energy. The energy_margin controls the allowed proximity to the edge energy, so that the returned fluorescence yield will be 0 if the incident energy < edge energy + energy_margin.

_xray.core_width(z_or_symbol, edge)

  return core electronic level width for an atomic number or symbol and name of the edge. widths are in eV.

_xray.mu_elam(z_or_symbol, energy, kind='total')

  return X-ray mass attenuation coefficient \(\mu/\rho\) in cm^2/gr for an atomic number or symbol at specified energy values.

  Parameters:

    - z_or_symbol – Integer atomic number or symbol for elemen

    - energy – energy (single value, list, array) in eV at which to calculate \(\mu\).

    - kind – one of ‘total’ (default), ‘photo’, ‘coh’, and ‘incoh’ for total, photo-absorption, coherent scattering, and incoherent scattering cross sections, respectively.

_xray.coherent_xsec(z_or_symbol, energies)

  return coherent scattering cross-section for an atomic number or symbol at specified energy values. Values returned are in cm^2/gr.

_xray.incoherent_xsec(z_or_symbol, energies)

  return incoherent scattering cross-section for an atomic number or symbol at specified energy values. Values returned are in cm^2/gr.

_xray.f0(ion, qvalues)

  return elastic scattering (Thomson) factor \(f_0(q)\) for the supplied values of `q` (\(q = \sin(\theta)/\lambda\) where \(\theta\) is the scattering angle and \(\lambda\) is the X-ray wavelength). Here, `ion` can be an atomic number or symbol, or any of the valid ion values (e.g., ‘Ga3+’) given by Waasmaier and Kirfel. The returned values are in units of electron number.

_xray.f0_ions(element=None)

  returns list of valid ions for `f0()`. If `element` is given (either an atomic number or symbol), then only the valid ions for that element will be returned.

_xray.chantler_energies(z_or_symbol, emin=0, emax=1.e9)

  returns array of energies (in eV) at whch data is tabulated in the Chantler tables. The arguments `emin` and `emax` can be used to restrict the range of returned energies.

_xray.f1_chantler(z_or_symbol, energies)

  return array of f’, the real part of the anomalous scattering factor for an element at the given energies, using the tabulation of Chantler. The returned values are in units of electron numbers, and represent the correction to Thomson scattering term.

_xray.f2_chantler(z_or_symbol, energies)

  return array of f’’, the imaginary part of the anomalous scattering factor for an element at the given energies, using the tabulation of Chantler. The returned values are in units of electron numbers. These values scale to the values of the mass attenuation coefficient.

_xray.mu_chantler(z_or_element, energies)

  return X-ray mass attenuation coefficient (\(\mu/\rho\)) for an element at the specified energy values, using the tabulation of Chantler.

_xray.f1f2_cl(z_or_element, energies, width=None, edge=None)

  return tuple of (f’, f’’), the real and imaginary anomalous scattering factors for an element at the specified energies, using the calculation scheme of Cromer and Liberman, as implemented by Brennan and Cowan. The optional argument `width` can be used to specify an energy width (in eV) to use to convolve the output with a Lorentzian profile (with `width` used as \(2\gamma\) in the Lorentzian). If `edge` is given (‘K’, ‘L3’, etc), the core-level width is looked up from `core_width()`, and its value is used.

  Note that both f’ and f’’ are returned here.

Warning

The Cromer-Liberman calculation sometimes generate spurious data, especially at high and low energies. The data from Chantler’s tables should be used in its place. That is, in almost all places where the Cromer-Liberman values differ from the Chantler values, the Cromer-Liberman data is obviously wrong.

The Cromer-Liberman tables are kept for historical reasons and backward compatibility, but may be dropped in the future.

## 15.2. X-ray Properties of Materials and Chemicals

Compositional data for several common materials are included with Larch, and can be read at run time. The variable `_xray.materials` contains a dictionary of material names, with values of (chemical forumla, density) that are read on startup, and can be appended too. There is a system-wide set of 50 or so known materials, and you can add your own favorite materials that will then be automatically available in later sessions.

The Table of X-ray functions for materials gives a brief description to the available functions for accessing these data. More detailed descriptions of function arguments, returned values, and so on are then given.

> Table of X-ray database functions for materials. These functions calculate and return X-ray properties for known materials or chemical formula. Except where noted, the data comes from Elam, Ravel, and Sieber.

> > function | description
> > --- | ---
> > `chemparse()` | parse a chemical formula to a dictionary of components
> > `material_get()` | get dictionary of elements for a known material
> > `material_add()` | add a material to list of known materials
> > `material_mu()` | calculate \(\mu\) for a material or chemical formula
> > `material_mu_components()` | calculate components of \(\mu\) for a material or chemical formula
> > `xray_delta_beta()` | anomalous index of refraction for a material, using data from Chantler.

_xray.chemparse(formula)

  parse a chemical formula, returning a dictionary with element symbols as keys and number for each element as values. For example, in Larch:

      larch> chemparse("H2O")
      {'H': 2.0, 'O': 1}
      larch> chemparse("Mg0.2Fe0.8(SO4)2")
      {'S': 2.0, 'Mg': 0.2, 'Fe': 0.8, 'O': 8.0}

  or in Python:

      >>> import larch
      >>> from larch_plugins.xray import chemparse
      >>> chemparse("H2O")
      {'H': 2.0, 'O': 1}
      >>> chemparse("Mg0.2Fe0.8(SO4)2")
      {'S': 2.0, 'Mg': 0.2, 'Fe': 0.8, 'O': 8.0}

  Note that factional weights and scientific notation for weights is supported, as long as the weight begins with a number and not ‘.’. That is ‘Fe0.8’ is supported, but ‘Fe.8’ is not.

_xray.material_get(name)

  look up chemical compound by naming returning formula (not parsed!) and density. For example, in Larch:

      larch> material_get('kapton')
      ('C22H10N2O5', 1.43)

  in python:

      >>> from larch_plugins.xray import material_get
      >>> material_get('kapton')
      ('C22H10N2O5', 1.43)

  material names are not case sensitive.

_xray.material_add(name, formula, density)

  add material with name, chemical formula, and density. This will be added to the a file in the user’s larch directory, and loaded in subsequent larch sessions.

  material names are not case sensitive.

_xray.material_mu(name_or_formula, energy, density=None)

  return X-ray attenuation length (in 1/cm) for a material, either by name or formula and density.

  > return X-ray mass attenuation coefficient \(\mu/\rho\) in cm^2/gr for an atomic number or symbol at specified energy values.

  > param name:

  >   material name or formula

  > param energy:

  >   energy (single value, list, array) in eV at which to calculate \(\mu\).

  > param kind:

  >   one of ‘total’ (default), ‘photo’, ‘coh’, and ‘incoh’ (see `mu_elam()`)

  > param density:

  >   material density (if `None`, it will be looked up for known materials)

  > return:

  >   \(\mu\) in 1/cm.

  > uses `mu_elam()`. Example:

  >     larch> print(material_mu('water', 10000.0))
  >     5.32986401658495
  >     larch> print(material_mu('H2O', 10000.0, density=1.0))
  >     5.32986401658495

_xray.material_mu_components(name_or_formula, energy, density=None)

  return dictionary of components to calculate absorption coefficient.

  Parameters:

    - name – material name or formula

    - energy – energy (single value, list, array) in eV at which to calculate \(\mu\).

    - kind – one of ‘total’ (default), ‘photo’, ‘coh’, and ‘incoh’ (see `mu_elam()`)

    - density – material density (if `None`, it will be looked up for known materials)

  Returns:

    dictionary of data for constructing \(\mu\) per element.

  The returned dictionary will have elements ‘mass’ (total mass), ‘density’, and ‘elements’ (list of atomic symbols for elements in material). For each element, there will be an item (atomic symbol as key) with tuple of (fraction, atomic mass, \(\mu\)). For example:

      larch> material_mu_components('quartz', 10000)
      {'Si': (1, 28.0855, 33.879432430185062), 'elements': ['Si', 'O'],
      'mass': 60.0843, 'O': (2.0, 15.9994, 5.9528248152970837), 'density': 2.65}

_xray.xray_delta_beta(material, density, energy, photo_only=False)

  return anomalous components of the index of refraction for a material, using the tabulated scattering components from Chantler.

  Parameters:

    - material – chemical formula (‘Fe2O3’, ‘CaMg(CO3)2’, ‘La1.9Sr0.1CuO4’)

    - density – material density in g/cm^3

    - energy – X-ray energy in eV

    - photo_only – boolean for returning only the photo cross-section component for beta and t_atten. If `False` (the default value), the total cross-section is returned.

  Returns:

    (delta, beta, t_atten)

  The material formula is parsed by `chemparse()`. The returned tuple contains the components described in the table below

  > value | symbol | description
  > --- | --- | ---
  > delta | \(\delta\) | real part of index of refraction.
  > beta | \(\beta\) | imaginary part of index of refraction.
  > t_atten | \(t_a\) | attenuation length, in cm.

  and correspond to the anomalous scattering components of the index of refraction, defined in the equation below. Here, \(t_{a} = \lambda / 4\pi\beta\), and and \(\lambda\) is the X-ray wavelength, \(r_0\) is the classical electron radius, and the sum is over the atomic species with number \(n_j\) and total complex scattering factor \(f_j\).

\[n = 1 -x \delta - i \beta = 1 - \lambda^2 \frac{r_{0}}{2\pi} \sum_j{ n_j f_j}\]