def __init__(self, symbol, xray_energy=None, energy_min=1.5, overlap_energy=None): self.symbol = symbol self.xray_energy = xray_energy self.mu = 1.0 self.edges = ['K'] self.fyields = {} if xray_energy is not None: self.mu = mu_elam(symbol, 1000 * xray_energy, kind='photo') self.edges = [] for ename, xedge in xray_edges(self.symbol).items(): if ename.lower() in ('k', 'l1', 'l2', 'l3', 'm5'): edge_kev = 0.001 * xedge.energy if (edge_kev < xray_energy and edge_kev > energy_min): self.edges.append(ename) self.fyields[ename] = xedge.fyield # currently, we consider only one edge per element if 'K' in self.edges: self.edges = ['K'] if 'L3' in self.edges: tmp = [] for ename in self.edges: if ename.lower().startswith('l'): tmp.append(ename) self.edges = tmp # apply CK corrections to fluorescent yields if 'L3' in self.edges: nlines = 1.0 ck13 = ck_probability(symbol, 'L1', 'L3') ck12 = ck_probability(symbol, 'L1', 'L2') ck23 = ck_probability(symbol, 'L2', 'L3') fy3 = self.fyields['L3'] fy2 = self.fyields.get('L2', 0) fy1 = self.fyields.get('L1', 0) if 'L2' in self.edges: nlines = 2.0 fy3 = fy3 + fy2 * ck23 fy2 = fy2 * (1 - ck23) if 'L1' in self.edges: nlines = 3.0 fy3 = fy3 + fy1 * (ck13 + ck12 * ck23) fy2 = fy2 + fy1 * ck12 fy1 = fy1 * (1 - ck12 - ck13 - ck12 * ck23) self.fyields['L1'] = fy1 self.fyields['L2'] = fy2 self.fyields['L3'] = fy3 / nlines self.fyields['L2'] = fy2 / nlines self.fyields['L1'] = fy1 / nlines # look up X-ray lines, keep track of very close lines # so that they can be consolidate # slightly confusing (and working with XrayLine energies in ev) self.lines = {} self.all_lines = {} energy0 = None for ename in self.edges: for key, xline in xray_lines(symbol, ename).items(): self.all_lines[key] = xline if xline.intensity > 0.002: self.lines[key] = xline if energy0 is None: energy0 = xline.energy if overlap_energy is None: if xray_energy is None: xray_energy = 10.0 if energy0 is not None: xray_energy = energy0 # note: at this point xray_energy is in keV overlap_energy = 5.0 * (2 + np.sqrt(5 + xray_energy)) # collect lines from the same initial level that are close in energy nlines = len(self.lines) combos = [[] for k in range(nlines)] comboe = [-1 for k in range(nlines)] combol = [None for k in range(nlines)] for key, xline in self.lines.items(): assigned = False for i, en in enumerate(comboe): if (abs(0.001 * xline.energy - en) < overlap_energy and xline.initial_level == combol[i]): combos[i].append(key) assigned = True break if not assigned: for k in range(nlines): if comboe[k] < 0: break combol[k] = xline.initial_level comboe[k] = xline.energy combos[k].append(key) # consolidate overlapping X-ray lines for comps in combos: if len(comps) > 0: key = comps[0] l0 = self.lines.pop(key) ilevel = l0.initial_level iweight = l0.intensity flevel = [l0.final_level] en = [l0.energy] wt = [l0.intensity] for other in comps[1:]: lx = self.lines.pop(other) if lx.intensity > iweight: iweight = lx.intensity ilevel = lx.initial_level flevel.append(lx.final_level) en.append(lx.energy) wt.append(lx.intensity) wt = np.array(wt) en = np.array(en) flevel = ', '.join(flevel) if len(comps) > 1: newkey = key.replace('1', '').replace('2', '').replace('3', '') newkey = newkey.replace('4', '').replace('5', '').replace(',', '') if newkey not in self.lines: key = newkey self.lines[key] = XrayLine(energy=(en * wt).sum() / wt.sum(), intensity=wt.sum(), initial_level=ilevel, final_level=flevel)
def test_ck_probability(): assert_allclose(ck_probability('W', 'L1', 'L3'), 0.3, rtol=0.01)