def material_mu(name, energy, density=None, kind='total', _larch=None): """ material_mu(name, energy, density=None, kind='total') return X-ray attenuation length (in 1/cm) for a material by name or formula arguments --------- name: chemical formul or name of material from materials list. energy: energy or array of energies in eV density: material density (gr/cm^3). If None, and material is a known material, that density will be used. kind: 'photo' or 'total' (default) for whether to return photo-absorption or total cross-section. returns ------- mu, absorption length in 1/cm notes ----- 1. material names are not case sensitive, chemical compounds are case sensitive. 2. mu_elam() is used for mu calculation. example ------- >>> print material_mu('H2O', 10000.0) 5.32986401658495 """ _materials = get_materials(_larch) formula = None mater = _materials.get(name.lower(), None) if mater is not None: formula, density = mater else: for key, val in _materials.items(): if name.lower() == val[0].lower(): # match formula formula, density = val break # default to using passed in name as a formula if formula is None: formula = name if density is None: raise Warning('material_mu(): must give density for unknown materials') mass_tot, mu = 0.0, 0.0 for elem, frac in chemparse(formula).items(): mass = frac * atomic_mass(elem, _larch=_larch) mu += mass * mu_elam(elem, energy, kind=kind, _larch=_larch) mass_tot += mass return density*mu/mass_tot
def material_mu(name, energy, density=None, kind='total', _larch=None): """ material_mu(name, energy, density=None, kind='total') return X-ray attenuation length (in 1/cm) for a material by name or formula arguments --------- name: chemical formul or name of material from materials list. energy: energy or array of energies in eV density: material density (gr/cm^3). If None, and material is a known material, that density will be used. kind: 'photo' or 'total' (default) for whether to return photo-absorption or total cross-section. returns ------- mu, absorption length in 1/cm notes ----- 1. material names are not case sensitive, chemical compounds are case sensitive. 2. mu_elam() is used for mu calculation. example ------- >>> print(material_mu('H2O', 10000.0)) 5.32986401658495 """ _materials = get_materials(_larch) formula = None mater = _materials.get(name.lower(), None) if mater is not None: formula, density = mater else: for key, val in _materials.items(): if name.lower() == val[0].lower(): # match formula formula, density = val break # default to using passed in name as a formula if formula is None: formula = name if density is None: raise Warning('material_mu(): must give density for unknown materials') mass_tot, mu = 0.0, 0.0 for elem, frac in chemparse(formula).items(): mass = frac * atomic_mass(elem, _larch=_larch) mu += mass * mu_elam(elem, energy, kind=kind, _larch=_larch) mass_tot += mass return density * mu / mass_tot
def __init__(self, symbol, xray_energy=None, energy_min=1500): 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, 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_ev = xedge.edge if (edge_ev < xray_energy and edge_ev > 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: 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: fy3 = fy3 + fy2*ck23 fy2 = fy2 * (1 - ck23) if 'L1' in self.edges: fy3 = fy3 + fy1 * (ck13 + ck12*ck23) fy2 = fy2 + fy1 * ck12 fy1 = fy1 * (1 - ck12 - ck13) self.fyields['L1'] = fy1 self.fyields['L2'] = fy2 self.fyields['L3'] = fy3 # look up xray lines self.lines = {} for ename in self.edges: self.lines.update(xray_lines(symbol, ename))
def material_mu_components(name, energy, density=None, kind='total', _larch=None): """material_mu_components: absorption coefficient (in 1/cm) for a compound arguments --------- name: material name or compound formula energy: energy or array of energies at which to calculate mu density: compound density in gr/cm^3 kind: cross-section to use ('total', 'photo') for mu_elam()) returns ------- dictionary of data for constructing mu per element, with 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 (stoichiometric fraction, atomic mass, mu) 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} """ _materials = get_materials(_larch) mater = _materials.get(name.lower(), None) if mater is None: formula = name if density is None: raise Warning( 'material_mu(): must give density for unknown materials') else: formula, density = mater out = {'mass': 0.0, 'density': density, 'elements': []} for atom, frac in chemparse(formula).items(): mass = atomic_mass(atom, _larch=_larch) mu = mu_elam(atom, energy, kind=kind, _larch=_larch) out['mass'] += frac * mass out[atom] = (frac, mass, mu) out['elements'].append(atom) return out
def material_mu_components(name, energy, density=None, kind='total', _larch=None): """material_mu_components: absorption coefficient (in 1/cm) for a compound arguments --------- name: material name or compound formula energy: energy or array of energies at which to calculate mu density: compound density in gr/cm^3 kind: cross-section to use ('total', 'photo') for mu_elam()) returns ------- dictionary of data for constructing mu per element, with 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 (stoichiometric fraction, atomic mass, mu) 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} """ _materials = get_materials(_larch) mater = _materials.get(name.lower(), None) if mater is None: formula = name if density is None: raise Warning('material_mu(): must give density for unknown materials') else: formula, density = mater out = {'mass': 0.0, 'density': density, 'elements':[]} for atom, frac in chemparse(formula).items(): mass = atomic_mass(atom, _larch=_larch) mu = mu_elam(atom, energy, kind=kind, _larch=_larch) out['mass'] += frac*mass out[atom] = (frac, mass, mu) out['elements'].append(atom) return out
def concentration_resid(pars, lineData=None, mca=None, phiPrime=np.pi / 2., phiDblPrime=np.pi / 2., xray_energy=30000., larch=None): cscPhiPrime = 1. / np.sin(phiPrime) cscPhiDblPrime = 1. / np.sin(phiDblPrime) energy = mca.get_energy() * 1000. dE = energy[1] - energy[0] probeSpectrum = np.zeros(len(energy)) ind = index_of(energy, xray_energy) probeSpectrum[ind] = 1.0 C = np.array([pars[elem + '_con'].value for elem in lineData], ndmin=2).T Cal = np.array([pars[elem + '_cal'].value for elem in lineData]) Intensity = np.array([lineData[elem][2] for elem in lineData]) mu = np.zeros((len(lineData) + 1, len(energy))) for i, elem_i in enumerate(lineData): mu[i, :] = mu_elam(elem_i, energy, kind='total', _larch=larch) mu[-1, :] += C[i, 0] * mu[i, :] beta = np.zeros((len(lineData), len(lineData), len(energy))) delta = np.zeros((len(lineData), len(lineData), len(energy))) for i, elem_i in enumerate(lineData): line_en_i = lineData[elem_i][1] edge_i = lineData[elem_i][0][len(elem_i)].title() edge_en_i, _, r_i = xray_edge(elem_i, edge_i, _larch=larch) for j, elem_j in enumerate(lineData): line_en_j = lineData[elem_j][1] edge_j = lineData[elem_j][0][len(elem_j)].title() line_j = lineData[elem_j][0][len(elem_j):].title() edge_en_j, _, r_j = xray_edge(elem_j, edge_j, _larch=larch) yield_j, _, prob_j = fluo_yield(elem_j, edge_j, line_j, np.max(energy), _larch=larch) k_j = prob_j * yield_j * (r_j - 1.) / r_j mu_s_prime = mu[-1, :] * cscPhiPrime mu_s_line_en_j = np.interp(line_en_j, energy, mu[-1, :]) mu_s_dblPrime_line_en_i = np.interp(line_en_i, energy, mu[-1, :]) * cscPhiDblPrime P_ij = np.log(1. + mu_s_prime / mu_s_line_en_j) / mu_s_prime + \ np.log(1. + mu_s_dblPrime_line_en_i / mu_s_line_en_j) / mu_s_dblPrime_line_en_i beta[i,j,:] = mu[j,:] * cscPhiPrime + \ np.interp(line_en_i, energy, mu[j,:]) * cscPhiDblPrime beta[i,j,:] /= mu[i,:] * cscPhiPrime + \ np.interp(line_en_i, energy, mu[i,:]) * cscPhiDblPrime beta[i, j, :] -= 1. delta[i, j, :] = np.where(energy >= edge_en_j, 0.5, 0.0) if line_en_j <= edge_en_i: delta[i, j, :] *= 0. delta[i, j, :] *= k_j delta[i, j, :] *= mu[j, :] * cscPhiPrime delta[i, j, :] *= np.interp(line_en_j, energy, mu[i, :]) delta[i,j,:] /= (mu[-1,:] * cscPhiPrime) + \ (np.interp(line_en_i, energy, mu[-1,:]) * cscPhiDblPrime) delta[i, j, :] *= P_ij W = np.zeros((1, len(lineData), len(energy))) for i, elem in enumerate(lineData): line_en_i = lineData[elem_i][1] mu_i_star = mu[i,:] * cscPhiPrime +\ np.interp(line_en_i, energy, mu[i,:]) * cscPhiDblPrime W[0, i, :] = mu[i, :] * probeSpectrum * dE W[0, i, :] /= mu_i_star * (1 + np.sum(C * beta[i, :, :], axis=0)) alpha = np.sum(W * beta, axis=2) / np.sum(W, axis=2) epsilon = np.sum(W * delta, axis=2) / np.sum(W, axis=2) num = 1 + np.sum(C.T * epsilon, axis=1) den = 1 + np.sum(C.T * alpha, axis=1) C = np.reshape(C, (len(C))) print(pars['cu_con'].value, pars['zn_con'].value, pars['mn_con'].value) return Intensity - Cal * C * num / den