def test_atomic_data(): assert atomic_number('zn') == 30 assert atomic_symbol(26) == 'Fe' assert atomic_mass(45) > 102.8 assert atomic_mass(45) < 103.0 assert atomic_density(29) == atomic_density('cu') assert atomic_density(22) > 4.51
def element(elem=None): edges = atomic = lines = {} if elem is not None: atomic = { 'n': xraydb.atomic_number(elem), 'mass': xraydb.atomic_mass(elem), 'density': xraydb.atomic_density(elem) } _edges = xraydb.xray_edges(elem) _lines = xraydb.xray_lines(elem) lines = OrderedDict() for k in sorted(_lines.keys()): en, inten, init, final = _lines[k] # XrayLine lines[k] = XrayLine(energy=f'{en:.1f}', intensity=f'{inten:.5f}', initial_level=init, final_level=final) edges = OrderedDict() for k in sorted(_edges.keys()): en, fy, jump = _edges[k] # XrayEdge edges[k] = XrayEdge(energy=f'{en:.1f}', fyield=f'{fy:.5f}', jump_ratio=f'{jump:.3f}') return render_template('elements.html', edges=edges, elem=elem, atomic=atomic, lines=lines, materials_dict=materials_dict)
def darwinwidth(elem=None): edges = atomic = lines = {} if elem is not None: edges= xraydb.xray_edges(elem) atomic= {'n': xraydb.atomic_number(elem), 'mass': xraydb.atomic_mass(elem), 'density': xraydb.atomic_density(elem)} lines= xraydb.xray_lines(elem) return render_template('darwinwidth.html', edges=edges, elem=elem, atomic=atomic, lines=lines, materials_dict=materials_dict)
def xanesNormalization(e, mu, e0=7125, step=None, nnorm=2, nvict=0, pre1=None, pre2=-50, norm1=100, norm2=None, method="pre_edge", useFlattened=False, Elemline="Fe_K"): elem, line = Elemline.split('_') elemZ = xraydb.atomic_number(elem) dat = Group(name='larchgroup', col1=e, col2=mu) if method == "guess": result = preedge(e, mu, e0, step=step, nnorm=nnorm, nvict=nvict) return result["pre1"], result["pre2"], result["norm1"], result["norm2"] elif method == "mback": mback(e, mu, group=dat, z=elemZ, edge=line, e0=e0, fit_erfc=False) return dat.f2, dat.fpp else: pre_edge(e, mu, group=dat, e0=e0, step=step, nnorm=nnorm, nvict=nvict, pre1=pre1, pre2=pre2, norm1=norm1, norm2=norm2, make_flat=True) if useFlattened: normSpec = dat.flat else: normSpec = dat.norm return dat.pre_edge, dat.post_edge, normSpec
def element(elem=None): edges = atomic = lines = {} if elem is not None: atomic= {'n': xraydb.atomic_number(elem), 'mass': xraydb.atomic_mass(elem), 'density': xraydb.atomic_density(elem)} _edges= xraydb.xray_edges(elem) _lines= xraydb.xray_lines(elem) lines = OrderedDict() for k in sorted(_lines.keys()): lines[k] = _lines[k] edges = OrderedDict() for k in sorted(_edges.keys()): edges[k] = _edges[k] return render_template('elements.html', edges=edges, elem=elem, atomic=atomic, lines=lines, materials_dict=materials_dict)
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 f1f2(z, energies, width=None, edge=None): """Return anomalous scattering factors f1, f2 from Cromer-Liberman Look-up and return f1, f2 for an element and array of energies from Cromer-Liberman (Cowan-Brennan implementation) Parameters ---------- z: atomic number of element energies: array of x-ray energies (in eV) width: width used to convolve values with lorentzian profile edge: x-ray edge ('K', 'L3', etc) used to lookup energy width for convolution. Returns: --------- f1, f2: anomalous scattering factors """ global CLLIB if CLLIB is None: CLLIB = get_dll('cldata') en = as_ndarray(energies) if not isinstance(z, int): z = atomic_number(z) if z is None: return None if z > 92: print( 'Cromer-Liberman data not available for Z>92') return if edge is not None or width is not None: natwid = core_width(element=z, edge=edge) if width is None and natwid not in (None, []): width = natwid if width is not None: # will convolve! e_extra = int(width*80.0) estep = (en[1:] - en[:-1]).min() emin = min(en) - e_extra emax = max(en) + e_extra npts = 1 + abs(emax-emin+estep*0.02)/abs(estep) en = np.linspace(emin, emax, int(npts)) nk = int(e_extra / estep) sig = width/2.0 lor = (1./(1 + ((np.arange(2*nk+1)-nk*1.0)/sig)**2))/(np.pi*sig) scale = lor.sum() # create ctypes pointers for the C function npts = len(en) p_z = ctypes.pointer(ctypes.c_int(int(z))) p_npts = ctypes.pointer(ctypes.c_int(npts)) p_en = (npts*ctypes.c_double)() p_f1 = (npts*ctypes.c_double)() p_f2 = (npts*ctypes.c_double)() for i in range(npts): p_en[i] = en[i] nout = CLLIB.f1f2(p_z, p_npts, p_en, p_f1, p_f2) f1 = np.array([i for i in p_f1[:]]) f2 = np.array([i for i in p_f2[:]]) if width is not None: # do the convolution f1 = np.interp(energies, en, convolve(f1, lor)[nk:-nk])/scale f2 = np.interp(energies, en, convolve(f2, lor)[nk:-nk])/scale return (f1, f2)
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 process(self, dgroup=None, force_mback=False, noskip=False, **kws): """ handle process (pre-edge/normalize) of XAS data from XAS form """ if self.skip_process and not noskip: return if dgroup is None: dgroup = self.controller.get_group() if dgroup is None: return self.skip_process = True conf = self.get_config(dgroup) dgroup.custom_plotopts = {} form = self.read_form() form['group'] = dgroup.groupname if dgroup.datatype != 'xas': self.skip_process = False dgroup.mu = dgroup.ydat * 1.0 opts = {'group': dgroup.groupname, 'scale': conf.get('scale', 1.0)} self.larch_eval("{group:s}.scale = {scale:.8f}".format(**opts)) self.larch_eval( "{group:s}.norm = {scale:.8f}*{group:s}.ydat".format(**opts)) return en_units = getattr(dgroup, 'energy_units', None) if en_units is None: en_units = guess_energy_units(dgroup.energy) if en_units != 'eV': mono_dspace = getattr(dgroup, 'mono_dspace', 1) dlg = EnergyUnitsDialog(self.parent, dgroup.energy, unitname=en_units, dspace=mono_dspace) res = dlg.GetResponse() dlg.Destroy() if res.ok: en_units = res.units dgroup.mono_dspace = res.dspace dgroup.xdat = dgroup.energy = res.energy dgroup.energy_units = en_units e0 = form['e0'] edge_step = form['edge_step'] copts = [dgroup.groupname] if not form['auto_e0']: if e0 < max(dgroup.energy) and e0 > min(dgroup.energy): copts.append("e0=%.4f" % float(e0)) if not form['auto_step']: copts.append("step=%s" % gformat(float(edge_step))) for attr in ('pre1', 'pre2', 'nvict', 'nnorm', 'norm1', 'norm2'): if form[attr] is None: copts.append("%s=None" % attr) else: copts.append("%s=%.2f" % (attr, form[attr])) self.larch_eval("pre_edge(%s)" % (', '.join(copts))) self.larch_eval( "{group:s}.norm_poly = 1.0*{group:s}.norm".format(**form)) norm_method = form['norm_method'].lower() form['normmeth'] = 'poly' if force_mback or norm_method.startswith('mback'): form['normmeth'] = 'mback' copts = [dgroup.groupname] copts.append("z=%d" % atomic_number(form['atsym'])) copts.append("edge='%s'" % form['edge']) for attr in ('pre1', 'pre2', 'nvict', 'nnorm', 'norm1', 'norm2'): if form[attr] is None: copts.append("%s=None" % attr) else: copts.append("%s=%.2f" % (attr, form[attr])) self.larch_eval("mback_norm(%s)" % (', '.join(copts))) if form['auto_step']: norm_expr = """{group:s}.norm = 1.0*{group:s}.norm_{normmeth:s} {group:s}.edge_step = 1.0*{group:s}.edge_step_{normmeth:s}""" self.larch_eval(norm_expr.format(**form)) else: norm_expr = """{group:s}.norm = 1.0*{group:s}.norm_{normmeth:s} {group:s}.norm *= {group:s}.edge_step_{normmeth:s}/{edge_step:.8f}""" self.larch_eval(norm_expr.format(**form)) if norm_method.startswith('area'): form['normmeth'] = 'area' expr = """{group:s}.norm = 1.0*{group:s}.norm_{normmeth:s} {group:s}.edge_step = 1.0*{group:s}.edge_step_{normmeth:s}""" self.larch_eval(expr.format(**form)) self.make_dnormde(dgroup) if form['auto_e0']: self.wids['e0'].SetValue(dgroup.e0) if form['auto_step']: self.wids['step'].SetValue(dgroup.edge_step) autoset_fs_increment(self.wids['step'], dgroup.edge_step) self.wids['atsym'].SetStringSelection(dgroup.atsym) self.wids['edge'].SetStringSelection(dgroup.edge) self.set_nnorm_widget(dgroup.pre_edge_details.nnorm) for attr in ('e0', 'edge_step'): conf[attr] = getattr(dgroup, attr) for attr in ('pre1', 'pre2', 'norm1', 'norm2'): conf[attr] = val = getattr(dgroup.pre_edge_details, attr, None) if val is not None: self.wids[attr].SetValue(val) if hasattr(dgroup, 'mback_params'): # from mback conf['atsym'] = getattr(dgroup.mback_params, 'atsym') conf['edge'] = getattr(dgroup.mback_params, 'edge') self.update_config(conf, dgroup=dgroup) wx.CallAfter(self.unset_skip_process)
def mback_norm(energy, mu=None, group=None, z=None, edge='K', e0=None, pre1=None, pre2=None, norm1=None, norm2=None, nnorm=None, nvict=1, _larch=None): """ simplified version of MBACK to Match mu(E) data for tabulated f''(E) for normalization Arguments: energy, mu: arrays of energy and mu(E) group: output group (and input group for e0) z: Z number of absorber e0: edge energy pre1: low E range (relative to E0) for pre-edge fit pre2: high E range (relative to E0) for pre-edge fit norm1: low E range (relative to E0) for post-edge fit norm2: high E range (relative to E0) for post-edge fit nnorm: degree of polynomial (ie, nnorm+1 coefficients will be found) for post-edge normalization curve fit to the scaled f2. Default=1 (linear) Returns: group.norm_poly: normalized mu(E) from pre_edge() group.norm: normalized mu(E) from this method group.mback_mu: tabulated f2 scaled and pre_edge added to match mu(E) group.mback_params: Group of parameters for the minimization References: * MBACK (Weng, Waldo, Penner-Hahn): http://dx.doi.org/10.1086/303711 * Chantler: http://dx.doi.org/10.1063/1.555974 """ ### 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) group.norm_poly = group.norm*1.0 if z is not None: # need to run find_e0: e0_nominal = xray_edge(z, edge).energy if e0 is None: e0 = getattr(group, 'e0', None) if e0 is None: find_e0(energy, mu, group=group) e0 = group.e0 atsym = None if z is None or z < 2: atsym, edge = guess_edge(group.e0) z = atomic_number(atsym) if atsym is None and z is not None: atsym = atomic_symbol(z) if getattr(group, 'pre_edge_details', None) is None: # pre_edge never run preedge(energy, mu, pre1=pre1, pre2=pre2, nvict=nvict, norm1=norm1, norm2=norm2, e0=e0, nnorm=nnorm) mu_pre = mu - group.pre_edge f2 = f2_chantler(z, energy) weights = np.ones(len(energy))*1.0 if norm2 is None: norm2 = max(energy) - e0 if norm2 < 0: norm2 = max(energy) - e0 - norm2 # avoid l2 and higher edges if edge.lower().startswith('l'): if edge.lower() == 'l3': e_l2 = xray_edge(z, 'L2').energy norm2 = min(norm2, e_l2-e0) elif edge.lower() == 'l2': e_l2 = xray_edge(z, 'L1').energy norm2 = min(norm2, e_l1-e0) ipre2 = index_of(energy, e0+pre2) inor1 = index_of(energy, e0+norm1) inor2 = index_of(energy, e0+norm2) + 1 weights[ipre2:] = 0.0 weights[inor1:inor2] = np.linspace(0.1, 1.0, inor2-inor1) params = Parameters() params.add(name='slope', value=0.0, vary=True) params.add(name='offset', value=-f2[0], vary=True) params.add(name='scale', value=f2[-1], vary=True) out = minimize(f2norm, 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_pre, f2=f2, weights=weights)) p = out.params.valuesdict() model = (p['offset'] + p['slope']*energy + f2) * p['scale'] group.mback_mu = model + group.pre_edge pre_f2 = preedge(energy, model, nnorm=nnorm, nvict=nvict, e0=e0, pre1=pre1, pre2=pre2, norm1=norm1, norm2=norm2) step_new = pre_f2['edge_step'] group.edge_step_poly = group.edge_step group.edge_step_mback = step_new group.norm_mback = mu_pre / step_new group.mback_params = Group(e0=e0, pre1=pre1, pre2=pre2, norm1=norm1, norm2=norm2, nnorm=nnorm, fit_params=p, fit_weights=weights, model=model, f2=f2, pre_f2=pre_f2, atsym=atsym, edge=edge) if (abs(step_new - group.edge_step)/(1.e-13+group.edge_step)) > 0.75: print("Warning: mback edge step failed....") else: group.edge_step = step_new group.norm = group.norm_mback