Esempio n. 1
0
    def predict_escape(self, det='Si', scale=1.0):
        """
        predict detector escape for a spectrum, save to 'escape' attribute

        X-rays penetrate a depth 1/mu(material, energy) and the
        detector fluorescence escapes from that depth as
            exp(-mu(material, KaEnergy)*thickness)
        with a fluorecence yield of the material

        """
        fluor_en = xray_line(det, 'Ka').energy / 1000.0
        edge = xray_edge(det, 'K')

        # here we use the 1/e depth for the emission
        # and the 1/e depth of the incident beam:
        # the detector fluorescence can escape on either side
        mu_emit = material_mu(det, fluor_en * 1000)
        mu_input = material_mu(det, self.energy * 1000)
        escape = 0.5 * scale * edge.fyield * np.exp(-mu_emit / (2 * mu_input))
        escape[np.where(self.energy * 1000 < edge.energy)] = 0.0
        escape *= interp(self.energy - fluor_en,
                         self.counts * 1.0,
                         self.energy,
                         kind='cubic')
        self.escape = escape
Esempio n. 2
0
def test_material_mu_components2():
    mu = material_mu('TiO2', 10000, density=4.23)
    assert_allclose(mu, 290.7, rtol=0.001)

    mu = material_mu('TiO2', 10000)
    assert_allclose(mu, 290.7, rtol=0.001)

    mu = material_mu('TiO2', 10000, density=4.5)
    assert_allclose(mu, 309.26, rtol=0.001)

    comps = material_mu_components('TiO2', 10000, density=4.23)

    known_comps = {
        'mass': 79.88,
        'density': 4.23,
        'elements': ['Ti', 'O'],
        'Ti': (1, 47.88, 110.676),
        'O': (2.0, 15.9994, 5.953)
    }

    assert 'Ti' in comps['elements']
    assert 'O' in comps['elements']

    for attr in ('mass', 'density'):
        assert_allclose(comps[attr], known_comps[attr], rtol=0.01)

    for attr in ('Ti', 'O'):
        assert_allclose(comps[attr][0], known_comps[attr][0], rtol=0.01)
        assert_allclose(comps[attr][1], known_comps[attr][1], rtol=0.01)
        assert_allclose(comps[attr][2], known_comps[attr][2], rtol=0.01)

    with pytest.raises(Warning):
        c = material_mu_components('TiO2', 10000)
 def genSampleComponent(row):
     sCompKeys = [  # for setting datatypes of the logbook columns
         "componentId",
         "componentSurroundedBy",
         "componentName",
         "composition",
         "density",
         "volFrac",
         "massFrac",
         "associatedHazards",
         "MSDSAvailable",
         "eLogId",
     ]
     sComp = dict.fromkeys(sCompKeys)
     sComp.update(row.loc[sCompKeys].to_dict())
     # try adding an X-ray absorption coefficient
     try:
         logging.debug(f'composition: {sComp["composition"]}, density: {sComp["density"]}, mu: { xraydb.material_mu(sComp["composition"], 8.04e3, density = sComp["density"], kind = "total" )}')
         # kind can be adjusted to 'photo' to calculate just the photo-absorption... calculate not in 1/cm but in 1/m.. SI please.
         sComp.update({"absCoeffCuTotal": xraydb.material_mu(sComp['composition'], 8.04e3, density = sComp['density'], kind = 'total' ) * 100})
         sComp.update({"absCoeffCuPhoto": xraydb.material_mu(sComp['composition'], 8.04e3, density = sComp['density'], kind = 'photo' ) * 100}) 
         sComp.update({"absCoeffMoTotal": xraydb.material_mu(sComp['composition'], 17.4e3, density = sComp['density'], kind = 'total' ) * 100})
         sComp.update({"absCoeffMoPhoto": xraydb.material_mu(sComp['composition'], 17.4e3, density = sComp['density'], kind = 'photo' ) * 100})
     except:
         logging.warning('X-ray absorption coefficient could not be calculated')
     return sComp
Esempio n. 4
0
 def calc_mu(self, energy):
     "calculate mu for energy in keV"
     # note material_mu works in eV!
     self.mu_total = material_mu(self.material,
                                 1000 * energy,
                                 density=self.density,
                                 kind='total')
     self.mu_photo = material_mu(self.material,
                                 1000 * energy,
                                 density=self.density,
                                 kind='photo')
Esempio n. 5
0
def attendata(formula, rho, t, e1, e2, estep):
    en_array = np.arange(float(e1), float(e2)+float(estep), float(estep))
    rho = float(rho)
    mu_array = xraydb.material_mu(formula, en_array, density=rho)
    t = float(t)
    trans = np.exp(-0.1*t*mu_array)
    atten = 1 - trans

    header = (' X-ray attenuation data from xrayweb  %s ' % time.ctime(),
              ' Material.formula   : %s ' % formula,
              ' Material.density   : %.3f gr/cm^3 ' % rho,
              ' Material.thickness : %.3f mm ' % t,
              ' Column.1: energy (eV)',
              ' Column.2: atten_length (mm)' ,
              ' Column.3: trans_fraction',
              ' Column.4: atten_fraction')

    arr_names = ('energy       ', 'atten_length ',
                 'trans_fract  ', 'atten_fract  ')

    txt = make_asciifile(header, arr_names,
                         (en_array, 10/mu_array, trans, atten))

    fname = 'xrayweb_atten_%s_%s.txt' % (formula,
                                         time.strftime('%Y%h%d_%H%M%S'))
    return Response(txt, mimetype='text/plain',
                    headers={"Content-Disposition":
                             "attachment;filename=%s" % fname})
Esempio n. 6
0
def test_material_mu1():
    en = np.linspace(8500, 9500, 21)
    known_mu = np.array([236.2, 232.4, 228.7, 225.1, 221.5, 218.1, 214.7,
                         211.4, 208.1, 204.9, 1403.6, 1385.6, 1367.9, 1350.6,
                         1333.5, 1316.7, 1300.3, 1284.0, 1268.1, 1252.4,
                         1237.0])

    mu = material_mu('CuO', en, density=6.3)
    assert_allclose(mu, known_mu, rtol=0.005)
Esempio n. 7
0
def test_material_mu4():
    en = np.linspace(5000, 10000, 21)

    known_mu = np.array([42.592, 36.801, 32.006, 28.005, 24.641, 21.794,
                         19.367, 17.288, 15.496, 13.943, 12.592, 11.411,
                         10.373, 9.458, 8.649, 7.931, 7.291, 6.719, 6.206,
                         5.745, 5.330])

    with pytest.raises(Warning):
        out = material_mu('H2SO4', en)
Esempio n. 8
0
def test_material_mu3():
    en = np.linspace(5000, 10000, 21)

    known_mu = np.array([42.592, 36.801, 32.006, 28.005, 24.641, 21.794,
                         19.367, 17.288, 15.496, 13.943, 12.592, 11.411,
                         10.373, 9.458, 8.649, 7.931, 7.291, 6.719, 6.206,
                         5.745, 5.330])

    mu = material_mu('H2O', en)
    assert_allclose(mu, known_mu, rtol=0.05)
Esempio n. 9
0
def test_material_mu2():
    en = np.linspace(5000, 10000, 21)
    known_mu = np.array([
        0.04934, 0.04267, 0.03715, 0.03254, 0.02866, 0.02538, 0.02257, 0.02016,
        0.01809, 0.01629, 0.01472, 0.01334, 0.01214, 0.01108, 0.01014, 0.00930,
        0.00856, 0.00789, 0.00729, 0.00675, 0.00626
    ])

    mu = material_mu('air', en)
    assert_allclose(mu, known_mu, rtol=0.05)

    air_formula, air_density = get_material('air')

    air_comps = chemparse(air_formula)

    assert air_comps['Ar'] < 0.013
    assert air_comps['Ar'] > 0.007

    mu = material_mu('air', en, density=2.0 * air_density)
    assert_allclose(mu, 2.0 * known_mu, rtol=0.05)
Esempio n. 10
0
    def calc_escape_scale(self, energy, thickness=None):
        """
        calculate energy dependence of escape effect

        X-rays penetrate a depth 1/mu(material, energy) and the
        detector fluorescence escapes from that depth as
            exp(-mu(material, KaEnergy)*thickness)
        with a fluorecence yield of the material

        """
        det = self.detector
        # note material_mu, xray_edge, xray_line work in eV!
        escape_energy_ev = xray_line(det.material, 'Ka').energy
        mu_emit = material_mu(det.material, escape_energy_ev)
        self.escape_energy = 0.001 * escape_energy_ev

        mu_input = material_mu(det.material, 1000 * energy)

        edge = xray_edge(det.material, 'K')
        self.escape_scale = edge.fyield * np.exp(-mu_emit / (2 * mu_input))
        self.escape_scale[np.where(energy < 0.001 * edge.energy)] = 0.0
Esempio n. 11
0
def fluo_corr(norm, formula, elem, edge, line, anginp, angout):
    """
    Correct over-absorption (self-absorption) for fluorescene XAFS
    using the based on the `larch` implementation of the FLUO alogrithm of
    D. Haskel. See FLUO manual_ for details.

    .. _manual: https://www3.aps.anl.gov/haskel/fluo.html

    Parameters
    ----------
    norm : iter
        Normalized fluorescence
    formula : str
        Chemical formula of the compound. For example: 'EuO'.
    elem : str
        Element of interest. For example: 'Eu'.
    edge : str
        Absorption edge of interest. For example: 'L3'.
    line : str
        Fluorescence line measured. For example: 'La'.
    anginp : float
        Input angle with respect to the sample surface. See FLUO manual.
    anginp : float
        Output angle with respect to the sample surface. See FLUO manual.

    Returns
    --------
    norm_corr : numpy.array
        Corrected normalized fluorescence.
    """

    # Angular correction. Avoid divide by zero.
    ang_corr = (np.sin(np.deg2rad(anginp)) /
                np.sin(max(1.e-7, np.deg2rad(angout))))

    # Find edge energies and fluorescence line energy
    e_edge = xray_edge(elem, edge).energy
    e_fluor = xray_line(elem, line).energy

    # Calculate mu(E) for fluorescence energy, above, below edge
    # alpha ends up independent of density!
    muvals = material_mu(formula,
                         np.array([e_fluor, e_edge - 10.0, e_edge + 10.0]),
                         density=1)

    # Do the correction
    alpha = (muvals[0] * ang_corr + muvals[1]) / (muvals[2] - muvals[1])
    norm_corr = np.array(norm) * alpha / (alpha + 1 - np.array(norm))

    return norm_corr
Esempio n. 12
0
def get_att_len(energy, material=None, density=None):
    """
    Get the attenuation length (in meter) of a material.

    The X-ray beam intensity I(x) at depth x in a material is a function of the
    attenuation coefficient mu, and can be calculated by the Beer-Lambert law.
    The Absorption Length (or Attenuation Length) is defined as the distance
    into a material where the x-ray beam intensity has decreased to a value of
    1/e (~ 40%) of the incident beam intensity (Io).

    (1/e) = e^(-mu * x)
    ln(1/e) = ln(e^(-mu * x))
    1 = mu * x
    x = 1/mu

    Parameters
    ----------
    energy : number
        Beam Energy given in KeV
    material : str, optional
        Atomic symbol for element, defaults to 'Be'
    density : float, optional
        Material density in g/cm^3

    Returns
    -------
    att_len : float
        Attenuation length (in meters)

    Raises
    ------
    ValueError
        If an invalid symbol is provided for material.

    Examples
    --------
    >>> get_att_len(energy=8, material='Be')
    0.004810113254120656
    """
    material = material or MATERIAL
    density = density or xdb.atomic_density(material)
    try:
        # xdb.material_my returns absorption length in 1/cm and takes energy
        # or array of energies in eV.
        att_len = 1.0 / (xdb.material_mu(material, energy * 1.0e3,
                                         density=density)) * 1.0e-2
    except Exception as ex:
        logger.error('Get Attenuation Length error: %s', ex)
        raise ex
    return att_len
Esempio n. 13
0
def test_material_mu_components1():
    mu = material_mu('quartz', 10000)
    assert_allclose(mu, 50.368, rtol=0.001)

    comps = material_mu_components('quartz', 10000)

    known_comps =  {'mass': 60.08, 'density': 2.65, 'elements': ['Si', 'O'],
                    'Si': (1, 28.1, 33.879), 'O': (2.0, 16.0, 5.953)}


    assert 'Si'in comps['elements']
    assert 'O'in comps['elements']

    for attr in ('mass', 'density'):
        assert_allclose(comps[attr], known_comps[attr], rtol=0.01)

    for attr in ('Si', 'O'):
        assert_allclose(comps[attr][0], known_comps[attr][0], rtol=0.01)
        assert_allclose(comps[attr][1], known_comps[attr][1], rtol=0.01)
        assert_allclose(comps[attr][2], known_comps[attr][2], rtol=0.01)
Esempio n. 14
0
def attendata(formula, rho, t, e1, e2, de, fname):
    en_array = energy_array(e1, e2, de)
    rho = float(rho)
    mu_array = xraydb.material_mu(formula, en_array, density=rho)
    t = float(t)
    trans = np.exp(-0.1 * t * mu_array)
    atten = 1 - trans

    header = (' X-ray attenuation data from xrayweb  %s ' % time.ctime(),
              ' Material.formula   : %s ' % formula,
              ' Material.density   : %.3f gr/cm^3 ' % rho,
              ' Material.thickness : %.3f mm ' % t, ' Column.1: energy (eV)',
              ' Column.2: attenuation_length (mm)',
              ' Column.3: transmitted_fraction',
              ' Column.4: attenuated_fraction')

    arr_names = ('energy       ', 'atten_length ', 'trans_fract  ',
                 'atten_fract  ')

    txt = make_asciifile(header, arr_names,
                         (en_array, 10 / mu_array, trans, atten))

    return Response(txt, mimetype='text/plain')
Esempio n. 15
0
#!/usr/bin/env python
# XrayDB example script    python/examples/mu_water.py
#
# calculate the fraction of X-rays transmitted through 1 mm of water
#
import numpy as np
import matplotlib.pyplot as plt

from xraydb import material_mu

energy = np.linspace(1000, 41000, 201)

mu = material_mu('H2O', energy)

# mu is returned in 1/cm
trans = np.exp(-0.1 * mu)

plt.plot(energy, trans, label='transmitted')
plt.plot(energy, 1 - trans, label='attenuated')
plt.title('X-ray absorption by 1 mm of water')
plt.xlabel('Energy (eV)')
plt.ylabel('Transmitted / Attenuated fraction')
plt.legend()
plt.show()
Esempio n. 16
0
def fluo_corr(energy,
              mu,
              formula,
              elem,
              group=None,
              edge='K',
              anginp=45,
              angout=45,
              _larch=None,
              **pre_kws):
    """correct over-absorption (self-absorption) for fluorescene XAFS
    using the FLUO alogrithm of D. Haskel.

    Arguments
    ---------
      energy    array of energies
      mu        uncorrected fluorescence mu
      formula   string for sample stoichiometry
      elem      atomic symbol or Z of absorbing element
      group     output group [default None]
      edge      name of edge ('K', 'L3', ...) [default 'K']
      anginp    input angle in degrees  [default 45]
      angout    output angle in degrees  [default 45]

    Additional keywords will be passed to pre_edge(), which will be used
    to ensure consistent normalization.

    Returns
    --------
       None, writes `mu_corr` and `norm_corr` (normalized `mu_corr`)
       to output group.

    Notes
    -----
       Support First Argument Group convention, requiring group
       members 'energy' and 'mu'
    """
    energy, mu, group = parse_group_args(energy,
                                         members=('energy', 'mu'),
                                         defaults=(mu, ),
                                         group=group,
                                         fcn_name='fluo_corr')
    # gather pre-edge options
    pre_opts = {
        'e0': None,
        'nnorm': 1,
        'nvict': 0,
        'pre1': None,
        'pre2': -30,
        'norm1': 100,
        'norm2': None
    }
    if hasattr(group, 'pre_edge_details'):
        uopts = getattr(group.pre_edge_details, 'call_args', {})
        for attr in pre_opts:
            if attr in uopts:
                pre_opts[attr] = uopts[attr]
    pre_opts.update(pre_kws)
    pre_opts['step'] = None
    pre_opts['nvict'] = 0

    # generate normalized mu for correction
    preinp = preedge(energy, mu, **pre_opts)

    ang_corr = (np.sin(max(1.e-7, np.deg2rad(anginp))) /
                np.sin(max(1.e-7, np.deg2rad(angout))))

    # find edge energies and fluorescence line energy
    e_edge = xray_edge(elem, edge).energy
    e_fluor = xray_line(elem, edge).energy

    # calculate mu(E) for fluorescence energy, above, below edge

    muvals = material_mu(formula,
                         np.array([e_fluor, e_edge - 10.0, e_edge + 10.0]),
                         density=1)

    alpha = (muvals[0] * ang_corr + muvals[1]) / (muvals[2] - muvals[1])
    mu_corr = mu * alpha / (alpha + 1 - preinp['norm'])
    preout = preedge(energy, mu_corr, **pre_opts)
    if group is not None:
        if _larch is not None:
            group = set_xafsGroup(group, _larch=_larch)
        group.mu_corr = mu_corr
        group.norm_corr = preout['norm']
Esempio n. 17
0
def atten(material=None,
          density=None,
          t='1.0',
          e1='1000',
          e2='51000',
          de='50'):
    message = []
    mu_plot = atten_plot = {}
    num = errors = 0
    mode = 'Linear'
    datalink = None
    do_plot = True
    if request.method == 'POST':
        formula = request.form.get('formula')
        matname = request.form.get('matname')
        mode = request.form.get('mode')
        density = float(request.form.get('density'))
        e1 = float(request.form.get('e1'))
        e2 = float(request.form.get('e2'))
        de = float(request.form.get('de'))
        t = float(request.form.get('thickness'))
        #input validation
        if not xraydb.validate_formula(formula):
            message.append("cannot interpret chemical formula")

        try:
            density = max(0, float(density))
        except:
            message.append('Density must be a positive number.')

    else:
        e1 = float(e1)
        e2 = float(e2)
        de = float(de)
        t = float(t)
        if material in materials_:
            mats = material
            formula = materials_['material'].formula
            density = materials_['material'].density

        elif material is not None and density is not None:
            formula = material
            density = float(density)
            mats = None
        else:
            do_plot = False
            mats = 'silicon'
            formula = materials_['silicon'].formula
            density = materials_['silicon'].density

        request.form = {
            'mats': mats,
            'formula': formula,
            'density': density,
            'e1': e1,
            'e2': e2,
            'de': de,
            'thickness': t,
            'mode': 'Linear'
        }

    if do_plot and formula is not None:
        # make plot
        en_array = energy_array(e1, e2, de)
        num = en_array.size
        mu_array = xraydb.material_mu(formula,
                                      en_array,
                                      density=float(density))
        trans = np.exp(-0.1 * t * mu_array)
        atten = 1 - trans
        use_log = mode.lower() == 'log'
        mu_plot = make_plot(en_array,
                            10 / mu_array,
                            material,
                            formula,
                            ylog_scale=use_log,
                            ytitle='1/e length (mm)')
        atten_plot = make_plot(en_array,
                               trans,
                               material,
                               "%.3f mm %s" % (t, formula),
                               ylog_scale=use_log,
                               y2=atten,
                               ytitle='transmitted/attenuated fraction',
                               y1label='transmitted',
                               y2label='attenuated')

    return render_template('attenuation.html',
                           message=message,
                           errors=len(message),
                           datalink=datalink,
                           mu_plot=mu_plot,
                           de=int(de),
                           atten_plot=atten_plot,
                           matlist=matlist,
                           materials_dict=materials_dict)  # , input=input)
Esempio n. 18
0
def formula(material=None):
    message = ['']
    abslen = absq = energies = []
    mu_plot = output = {}
    num = errors = 0
    isLog = True

    if request.method == 'POST':
        formula = request.form.get('formula')
        density = request.form.get('density')
        energy1 = request.form.get('energy1')
        energy2 = request.form.get('energy2')
        step = request.form.get('step')
        mode = request.form.get('mode')
        data = request.form.get('data')

        #input validation
        output = validate_input(formula,
                                density,
                                step,
                                energy1,
                                energy2,
                                mode,
                                material,
                                page='formula')
        message = output['message']
    else:
        request.form = {
            'formula': materials_dict['silicon'].formula,
            'density': materials_dict['silicon'].density,
            'energy1': '1000',
            'energy2': '50000',
            'step': '100'
        }

    if message[0] == 'Input is valid':
        #unpack floats
        df = output['df']
        ef = output['ef']
        ef2 = output['ef2']
        sf = output['sf']
        isLog = output['isLog']

        #make plot
        while ef2 < (
                ef + (sf * 2)
        ):  #this ensures that there are always at least 3 energy values for a meaningful plot
            ef2 += sf
        ef2 += sf  #this includes energy2 in the plot, normally np.arrage excludes the upper bound
        en_array = np.arange(ef, ef2, sf)
        num = en_array.size
        mu_array = xraydb.material_mu(formula, en_array, density=df)

        if data == 'Abslen':
            len_array = np.empty((0, ))
            for i in mu_array:
                len_array = np.append(len_array, [10000 / i], axis=0)
            mu_plot = make_plot(en_array,
                                len_array,
                                material,
                                formula,
                                ytitle='10000 / mu',
                                ylog_scale=isLog)
        else:
            mu_plot = make_plot(en_array,
                                mu_array,
                                material,
                                formula,
                                ylog_scale=isLog)

        energies = [nformat(x) for x in en_array]
        absq = [nformat(x) for x in mu_array]
        abslen = [10000 / float(nformat(x)) for x in mu_array]

        message = []
    else:
        errors = len(message)

    return render_template('formulas.html',
                           message=message,
                           errors=errors,
                           abslen=abslen,
                           mu_plot=mu_plot,
                           absq=absq,
                           energies=energies,
                           num=num,
                           matlist=matlist,
                           materials_dict=materials_dict_j,
                           input=input)
Esempio n. 19
0
def atten(material=None):
    message = []
    energies = []
    mu_plot = atten_plot = {}
    num = errors = 0
    mode = 'Linear'
    datalink = None
    if request.method == 'POST':
        formula = request.form.get('formula')
        matname = request.form.get('matname')
        density = request.form.get('density')
        energy1 = request.form.get('energy1')
        energy2 = request.form.get('energy2')
        estep = request.form.get('step')
        mode = request.form.get('mode')
        thickness = request.form.get('thickness')

        #input validation
        if not xraydb.validate_formula(formula):
            message.append("cannot interpret chemical formula")

        try:
            density = max(0, float(density))
        except:
            message.append('Density must be a positive number.')

        if len(message) == 0:
            use_log = mode.lower() == 'log'
            # make plot
            en_array = np.arange(float(energy1), float(energy2)+float(estep), float(estep))

            num = en_array.size
            mu_array = xraydb.material_mu(formula, en_array, density=float(density))
            t = float(thickness)
            trans = np.exp(-0.1*t*mu_array)
            atten = 1 - trans

            mu_plot = make_plot(en_array, 10/mu_array, material, formula,
                                ylog_scale=use_log, ytitle='1/e length (mm)')
            atten_plot = make_plot(en_array, trans,
                                   material, "%.3f mm %s" % (t, formula),
                                   ylog_scale=use_log,
                                   y2=atten,
                                   ytitle='transmitted/attenuated fraction',
                                   y1label='transmitted',
                                   y2label='attenuated')
        


    else:
        request.form = {'mats': 'silicon',
                        'formula': materials_['silicon'].formula,
                        'density': materials_['silicon'].density,
                        'energy1':  1000,
                        'energy2': 51000,
                        'step': "50",
                        'thickness': 1.00,
                        'mode': 'Linear'}

    return render_template('attenuation.html', message=message, errors=len(message),
                           datalink=datalink, mu_plot=mu_plot,
                           atten_plot=atten_plot, matlist=matlist,
                           materials_dict=materials_dict, input=input)
Esempio n. 20
0
#!/usr/bin/env python
# XrayDB example script    python/examples/mu_water.py
#
# calculate the fraction of X-rays transmitted through 1 mm of calcite
#
import numpy as np
import matplotlib.pyplot as plt

from xraydb import material_mu

energy = np.linspace(1000, 41000, 201)

mu = material_mu('CaCO3', energy, density=2.71)

# mu is returned in 1/cm
trans = np.exp(-0.1 * mu)

plt.plot(energy, trans, label='transmitted')
plt.plot(energy, 1-trans, label='attenuated')
plt.title('X-ray absorption by 1 mm of calcite')
plt.xlabel('Energy (eV)')
plt.ylabel('Transmitted / Attenuated fraction')
plt.legend()
plt.show()