def scatteringdata(elem, e1, e2, de, fname): en_array = energy_array(e1, e2, de) mu_total = xraydb.mu_elam(elem, en_array, kind='total') mu_photo = xraydb.mu_elam(elem, en_array, kind='photo') mu_incoh = xraydb.mu_elam(elem, en_array, kind='incoh') mu_coher = xraydb.mu_elam(elem, en_array, kind='coh') header = [ ' X-ray Atomic Scattering Cross-Sections from xrayweb %s ' % time.ctime(), ' Element : %s ' % elem, ' Column.1: Energy (eV)', ' Column.2: mu_total (cm^2/gr)', ' Column.3: mu_photo (cm^2/gr) # Photo-electric', ' Column.4: mu_coher (cm^2/gr) # Rayleigh', ' Column.5: mu_incoh (cm^2/gr) # Compton' ] arr_names = [ 'energy ', 'mu_total ', 'mu_photo ', 'mu_coher ', 'mu_incoh ' ] arrays = [en_array, mu_total, mu_photo, mu_coher, mu_incoh] atz = xraydb.atomic_number(elem) if atz < 93: header.extend([ ' Column.6: f1 (electrons/atom) # real resonant', ' Column.7: f2 (electrons/atom) # imag resonant' ]) arr_names.extend(['f1 ', 'f2 ']) arrays.extend([ xraydb.f1_chantler(elem, en_array), xraydb.f2_chantler(elem, en_array) ]) txt = make_asciifile(header, arr_names, arrays) return Response(txt, mimetype='text/plain')
def test_f1f2_chantler(): en = np.linspace(10000, 15000, 51) f1 = np.array([-5.97, -6.08, -6.20, -6.33, -6.46, -6.60, -6.75, -6.91, -7.09, -7.28, -7.49, -7.72, -7.99, -8.28, -8.64, -9.06, -9.60, -10.33, -11.54, -15.14, -12.27, -10.64, -9.78, -9.18, -8.76, -8.43, -8.18, -7.98, -7.83, -7.73, -7.66, -7.64, -7.66, -7.73, -7.87, -8.13, -8.58, -9.91, -9.18, -8.19, -7.73, -7.46, -7.36, -7.61, -7.43, -6.61, -6.13, -5.77, -5.46, -5.20, -4.96 ]) f2 = np.array([5.12, 5.04, 4.96, 4.87, 4.80, 4.72, 4.64, 4.57, 4.50, 4.43, 4.37, 4.30, 4.24, 4.18, 4.12, 4.06, 4.01, 3.97, 3.93, 4.15, 9.94, 9.83, 9.70, 9.57, 9.43, 9.30, 9.17, 9.05, 8.92, 8.80, 8.69, 8.57, 8.46, 8.35, 8.25, 8.14, 8.05, 8.02, 10.94, 10.83, 10.71, 10.59, 10.47, 10.39, 11.75, 11.67, 11.56, 11.44, 11.33, 11.21, 11.10]) assert_allclose(f1, f1_chantler('Au', en), rtol=0.01) assert_allclose(f2, f2_chantler('Au', en), rtol=0.01) assert_allclose(f1, chantler_data('Au', en, 'f1'), rtol=0.01) assert_allclose(f2, chantler_data('Au', en, 'f2'), rtol=0.01)
def test_f1f2_chantler_mo(): en = np.linspace(1000, 500000, 501) f1 = f1_chantler('Mo', en) assert (len(f1) > 400)
def scattering(elem=None, e1='1000', e2='50000', de='50'): f1f2_plot = mu_plot = {} if len(request.form) != 0: elem = request.form.get('elem', 'None') e1 = request.form.get('e1', e1) e2 = request.form.get('e2', e2) de = request.form.get('de', de) if elem not in (None, 'None', ''): atz = xraydb.atomic_number(elem) en_array = energy_array(e1, e2, de) mu_total = xraydb.mu_elam(elem, en_array, kind='total') mu_photo = xraydb.mu_elam(elem, en_array, kind='photo') mu_incoh = xraydb.mu_elam(elem, en_array, kind='incoh') mu_coher = xraydb.mu_elam(elem, en_array, kind='coh') yrange = [ -0.25 + min(-1.8, np.log10(mu_photo.min() + 1.e-5), np.log10(mu_incoh.min() + 1.e-5), np.log10(mu_coher.min() + 1.e-5)), 0.75 + np.log10(mu_total.max() + 1.e-5) ] mu_plot = make_plot(en_array, mu_total, 'Mass Attenuation for %s' % elem, elem, ytitle='mu/rho (cm^2/gr)', xtitle='Energy (eV)', xlog_scale=False, ylog_scale=True, yrange=yrange, yformat='.2f', y1label='Total', y2=mu_photo, y2label='Photo-electric', y3=mu_incoh, y3label='Incoherent', y4=mu_coher, y4label='Coherent') if atz < 93: try: f1 = xraydb.f1_chantler(elem, en_array) except: f1 = xraydb.f1_chantler(elem, en_array, smoothing=1) f2 = xraydb.f2_chantler(elem, en_array) f1f2_plot = make_plot(en_array, f1, 'Resonant Scattering factors for %s' % elem, elem, ytitle='f1, f2 (electrons/atom)', xtitle='Energy (eV)', xlog_scale=False, ylog_scale=False, y2=f2, y1label='f1', y2label='f2') return render_template('scattering.html', elem=elem, e1=e1, e2=e2, de=int(de), f1f2_plot=f1f2_plot, mu_plot=mu_plot, materials_dict=materials_dict)
def mback(energy, mu=None, group=None, z=None, edge='K', e0=None, pre1=None, pre2=-50, norm1=100, norm2=None, order=3, leexiang=False, tables='chantler', fit_erfc=False, return_f1=False, _larch=None): """ Match mu(E) data for tabulated f''(E) using the MBACK algorithm and, optionally, the Lee & Xiang extension Arguments ---------- energy: array of x-ray energies, in eV. mu: array of mu(E). group: output group. z: atomic number of the absorber. edge: x-ray absorption edge (default 'K') e0: edge energy, in eV. If None, it will be determined here. pre1: low E range (relative to e0) for pre-edge region. pre2: high E range (relative to e0) for pre-edge region. norm1: low E range (relative to e0) for post-edge region. norm2: high E range (relative to e0) for post-edge region. order: order of the legendre polynomial for normalization. (default=3, min=0, max=5). leexiang: boolean (default False) to use the Lee & Xiang extension. tables: tabulated scattering factors: 'chantler' [deprecated] fit_erfc: boolean (default False) to fit parameters of error function. return_f1: boolean (default False) to include the f1 array in the group. Returns ------- None The following attributes will be written to the output group: group.f2: tabulated f2(E). group.f1: tabulated f1(E) (if 'return_f1' is True). group.fpp: mback atched spectrum. group.edge_step: edge step of spectrum. group.norm: normalized spectrum. group.mback_params: group of parameters for the minimization. Notes: Chantler tables is now used, with Cromer-Liberman no longer supported. References: * MBACK (Weng, Waldo, Penner-Hahn): http://dx.doi.org/10.1086/303711 * Lee and Xiang: http://dx.doi.org/10.1088/0004-637X/702/2/970 * Cromer-Liberman: http://dx.doi.org/10.1063/1.1674266 * Chantler: http://dx.doi.org/10.1063/1.555974 """ order = max(min(order, MAXORDER), 0) ### implement the First Argument Group convention energy, mu, group = parse_group_args(energy, members=('energy', 'mu'), defaults=(mu,), group=group, fcn_name='mback') if len(energy.shape) > 1: energy = energy.squeeze() if len(mu.shape) > 1: mu = mu.squeeze() if _larch is not None: group = set_xafsGroup(group, _larch=_larch) energy = remove_dups(energy) if e0 is None or e0 < energy[1] or e0 > energy[-2]: e0 = find_e0(energy, mu, group=group) print(e0) ie0 = index_nearest(energy, e0) e0 = energy[ie0] pre1_input = pre1 norm2_input = norm2 if pre1 is None: pre1 = min(energy) - e0 if norm2 is None: norm2 = max(energy) - e0 if norm2 < 0: norm2 = max(energy) - e0 - norm2 pre1 = max(pre1, (min(energy) - e0)) norm2 = min(norm2, (max(energy) - e0)) if pre1 > pre2: pre1, pre2 = pre2, pre1 if norm1 > norm2: norm1, norm2 = norm2, norm1 p1 = index_of(energy, pre1+e0) p2 = index_nearest(energy, pre2+e0) n1 = index_nearest(energy, norm1+e0) n2 = index_of(energy, norm2+e0) if p2 - p1 < 2: p2 = min(len(energy), p1 + 2) if n2 - n1 < 2: p2 = min(len(energy), p1 + 2) ## theta is a boolean array indicating the ## energy values considered for the fit. ## theta=1 for included values, theta=0 for excluded values. theta = np.zeros_like(energy, dtype='int') theta[p1:(p2+1)] = 1 theta[n1:(n2+1)] = 1 ## weights for the pre- and post-edge regions, as defined in the MBACK paper (?) weight = np.ones_like(energy, dtype=float) weight[p1:(p2+1)] = np.sqrt(np.sum(weight[p1:(p2+1)])) weight[n1:(n2+1)] = np.sqrt(np.sum(weight[n1:(n2+1)])) ## get the f'' function from CL or Chantler f1 = f1_chantler(z, energy) f2 = f2_chantler(z, energy) group.f2 = f2 if return_f1: group.f1 = f1 em = find_xray_line(z, edge).energy # erfc centroid params = Parameters() params.add(name='s', value=1.0, vary=True) # scale of data params.add(name='xi', value=50.0, vary=False, min=0) # width of erfc params.add(name='a', value=0.0, vary=False) # amplitude of erfc if fit_erfc: params['a'].vary = True params['a'].value = 0.5 params['xi'].vary = True for i in range(order+1): # polynomial coefficients params.add(name='c%d' % i, value=0, vary=True) out = minimize(match_f2, params, method='leastsq', gtol=1.e-5, ftol=1.e-5, xtol=1.e-5, epsfcn=1.e-5, kws = dict(en=energy, mu=mu, f2=f2, e0=e0, em=em, order=order, weight=weight, theta=theta, leexiang=leexiang)) opars = out.params.valuesdict() eoff = energy - e0 norm_function = opars['a']*erfc((energy-em)/opars['xi']) + opars['c0'] for i in range(order): attr = 'c%d' % (i + 1) if attr in opars: norm_function += opars[attr]* eoff**(i + 1) group.e0 = e0 group.fpp = opars['s']*mu - norm_function # calculate edge step and normalization from f2 + norm_function pre_f2 = preedge(energy, group.f2+norm_function, e0=e0, pre1=pre1, pre2=pre2, norm1=norm1, norm2=norm2, nnorm=2, nvict=0) group.edge_step = pre_f2['edge_step'] / opars['s'] group.norm = (opars['s']*mu - pre_f2['pre_edge']) / pre_f2['edge_step'] group.mback_details = Group(params=opars, pre_f2=pre_f2, f2_scaled=opars['s']*f2, norm_function=norm_function)