Example #1
0
def test_xray_line():
    cuk = xray_line('Cu', 'K')
    assert_allclose(cuk.energy, 8039.626, rtol=0.001)
    assert_allclose(cuk.intensity, 0.8716833, rtol=0.001)
    assert cuk.final_level == 'L'

    cuka = xray_line('Cu', 'Ka1')
    assert_allclose(cuka.energy, 8046.3, rtol=0.001)
    assert_allclose(cuka.intensity, 0.5771, rtol=0.001)
    assert cuka.final_level == 'L3'

    ti_klines = xray_lines('Ti', 'K')
    for line in ('Ka1', 'Ka2', 'Ka3', 'Kb1', 'Kb3', 'Kb5'):
        assert ti_klines[line].initial_level == 'K'

    assert_allclose(ti_klines['Ka1'].energy, 4512.2, rtol=0.001)
    assert_allclose(ti_klines['Ka2'].energy, 4505.8, rtol=0.001)
    assert_allclose(ti_klines['Ka3'].energy, 4405.1, rtol=0.001)
    assert_allclose(ti_klines['Kb1'].energy, 4933.4, rtol=0.001)
    assert_allclose(ti_klines['Kb3'].energy, 4933.4, rtol=0.001)
    assert_allclose(ti_klines['Kb5'].energy, 4964.0, rtol=0.001)

    assert_allclose(ti_klines['Ka1'].intensity, 0.58455, rtol=0.001)
    assert_allclose(ti_klines['Ka2'].intensity, 0.29369, rtol=0.001)
    assert_allclose(ti_klines['Ka3'].intensity, 0.000235, rtol=0.01)
    assert_allclose(ti_klines['Kb1'].intensity, 0.07965, rtol=0.001)
    assert_allclose(ti_klines['Kb3'].intensity, 0.04126, rtol=0.001)
    assert_allclose(ti_klines['Kb5'].intensity, 0.000607, rtol=0.01)
    assert_allclose(ti_klines['Ka1'].intensity, 0.58455, rtol=0.001)

    assert ti_klines['Ka1'].final_level == 'L3'
    assert ti_klines['Ka2'].final_level == 'L2'
    assert ti_klines['Ka3'].final_level == 'L1'
    assert ti_klines['Kb1'].final_level == 'M3'
    assert ti_klines['Kb3'].final_level == 'M2'
    assert ti_klines['Kb5'].final_level == 'M4,5'
Example #2
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
Example #3
0
def xrf_calib_fitrois(mca):
    """initial calibration step for MCA:
    find energy locations for all ROIs

    """
    if not isLarchMCAGroup(mca):
        print('Not a valid MCA')
        return

    energy = 1.0 * mca.energy
    chans = 1.0 * np.arange(len(energy))
    counts = mca.counts
    bgr = getattr(mca, 'bgr', None)
    if bgr is not None:
        counts = counts - bgr
    calib = OrderedDict()
    for roi in mca.rois:
        words = roi.name.split()
        elem = words[0].title()
        family = 'ka'
        if len(words) > 1:
            family = words[1]
        try:
            eknown = xray_line(elem, family).energy / 1000.0
        except:
            continue
        llim = max(0, roi.left - roi.bgr_width)
        hlim = min(len(chans) - 1, roi.right + roi.bgr_width)
        fit = fit_peak(chans[llim:hlim],
                       counts[llim:hlim],
                       'Gaussian',
                       background='constant')

        ccen = fit.params['center'].value
        ecen = ccen * mca.slope + mca.offset
        fwhm = 2.354820 * fit.params['sigma'].value * mca.slope
        calib[roi.name] = (eknown, ecen, fwhm, ccen, fit)
    mca.init_calib = calib
Example #4
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
Example #5
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']
Example #6
0
    def __init__(self, parent, mca, size=(-1, -1), callback=None):
        self.mca = mca
        self.callback = callback
        wx.Frame.__init__(self,
                          parent,
                          -1,
                          'Calibrate MCA',
                          size=size,
                          style=wx.DEFAULT_FRAME_STYLE)

        opanel = scrolled.ScrolledPanel(self)
        osizer = wx.BoxSizer(wx.VERTICAL)
        panel = GridPanel(opanel)
        self.calib_updated = False
        panel.AddText("Calibrate MCA Energy (Energies in eV)",
                      colour='#880000',
                      dcol=7)
        panel.AddText("ROI", newrow=True, style=CEN)
        panel.AddText("Predicted", style=CEN)
        panel.AddText("Peaks with Current Calibration", dcol=3, style=CEN)
        panel.AddText("Peaks with Refined Calibration", dcol=3, style=CEN)

        panel.AddText("Name", newrow=True, style=CEN)
        panel.AddText("Energy", style=CEN)
        panel.AddText("Center", style=CEN)
        panel.AddText("Difference", style=CEN)
        panel.AddText("FWHM", style=CEN)
        panel.AddText("Center", style=CEN)
        panel.AddText("Difference", style=CEN)
        panel.AddText("FWHM", style=CEN)
        panel.AddText("Use? ", style=CEN)

        panel.Add(HLine(panel, size=(700, 3)), dcol=9, newrow=True)
        self.wids = []

        # find ROI peak positions
        self.init_wids = {}
        for roi in self.mca.rois:
            eknown, ecen, fwhm = 1, 1, 1

            words = roi.name.split()
            elem = words[0].title()
            family = 'ka'
            if len(words) > 1:
                family = words[1]
            try:
                eknown = xray_line(elem, family).energy / 1000.0
            except (AttributeError, ValueError):
                eknown = 0.0001
            mid = (roi.right + roi.left) / 2
            wid = (roi.right - roi.left) / 2
            ecen = mid * mca.slope + mca.offset
            fwhm = 2.354820 * wid * mca.slope

            diff = ecen - eknown
            name = ('   ' + roi.name + ' ' * 10)[:10]
            opts = {'style': CEN, 'size': (75, -1)}
            w_name = SimpleText(panel, name, **opts)
            w_pred = SimpleText(panel, "% .1f" % (1000 * eknown), **opts)
            w_ccen = SimpleText(panel, "% .1f" % (1000 * ecen), **opts)
            w_cdif = SimpleText(panel, "% .1f" % (1000 * diff), **opts)
            w_cwid = SimpleText(panel, "% .1f" % (1000 * fwhm), **opts)
            w_ncen = SimpleText(panel, "-----", **opts)
            w_ndif = SimpleText(panel, "-----", **opts)
            w_nwid = SimpleText(panel, "-----", **opts)
            w_use = Check(panel, label='', size=(40, -1), default=0)
            panel.Add(w_name, style=LEFT, newrow=True)
            panel.AddMany((w_pred, w_ccen, w_cdif, w_cwid, w_ncen, w_ndif,
                           w_nwid, w_use))
            self.init_wids[roi.name] = [
                False, w_pred, w_ccen, w_cdif, w_cwid, w_use
            ]
            self.wids.append(
                (roi.name, eknown, ecen, w_ncen, w_ndif, w_nwid, w_use))

        panel.Add(HLine(panel, size=(700, 3)), dcol=9, newrow=True)
        offset = 1000.0 * self.mca.offset
        slope = 1000.0 * self.mca.slope
        panel.AddText("Current Calibration:", dcol=2, newrow=True)
        panel.AddText("offset(eV):")
        panel.AddText("%.3f" % (offset), dcol=1, style=RIGHT)
        panel.AddText("slope(eV/chan):")
        panel.AddText("%.3f" % (slope), dcol=1, style=RIGHT)

        panel.AddText("Refined Calibration:", dcol=2, newrow=True)
        self.new_offset = FloatCtrl(panel,
                                    value=offset,
                                    precision=3,
                                    size=(80, -1))
        self.new_slope = FloatCtrl(panel,
                                   value=slope,
                                   precision=3,
                                   size=(80, -1))
        panel.AddText("offset(eV):")
        panel.Add(self.new_offset, dcol=1, style=RIGHT)
        panel.AddText("slope(eV/chan):")
        panel.Add(self.new_slope, dcol=1, style=RIGHT)

        self.calib_btn = Button(panel,
                                'Compute Calibration',
                                size=(175, -1),
                                action=self.onCalibrate)
        self.calib_btn.Disable()
        panel.Add(self.calib_btn, dcol=3, newrow=True)
        panel.Add(Button(panel,
                         'Use New Calibration',
                         size=(175, -1),
                         action=self.onUseCalib),
                  dcol=3,
                  style=RIGHT)
        panel.Add(Button(panel, 'Done', size=(125, -1), action=self.onClose),
                  dcol=2,
                  style=RIGHT)
        panel.pack()
        a = panel.GetBestSize()
        self.SetSize((a[0] + 25, a[1] + 50))
        osizer.Add(panel)
        pack(opanel, osizer)
        opanel.SetupScrolling()
        self.Show()
        self.Raise()
        self.init_proc = False
        self.init_t0 = time.time()
        self.init_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onInitTimer, self.init_timer)
        self.init_timer.Start(2)