Source code for sirepo.crystal

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Get polarizability from X0h server (http://x-server.gmca.aps.anl.gov/x0h.html).
For details see http://x-server.gmca.aps.anl.gov/pub/Stepanov_CR_1991_08.pdf.
"""
from __future__ import division

import math
import re

import requests

X0H_SERVER = 'http://x-server.gmca.aps.anl.gov/cgi/x0h_form.exe'


[docs]def calc_bragg_angle(d, energy_eV, n=1): """Calculate Bragg angle from the provided energy and d-spacing. Args: d (float): interplanar spacing (d-spacing) [A]. energy_eV (float): photon energy [eV]. n (int): number of diffraction peak. Returns: dict: the resulted dictionary with: lamda (float): wavelength [nm]. bragg_angle (float): Bragg angle [rad]. bragg_angle_deg (float): Bragg angle [deg]. """ # Check/convert types first: d = float(d) energy_eV = float(energy_eV) n = int(n) lamda = 1239.84193 / energy_eV # lamda in [nm] bragg_angle = math.asin(n * lamda / (2 * d * 0.1)) # convert d from [A] to [nm]. bragg_angle_deg = 180. / math.pi * bragg_angle return { 'lamda': lamda, 'bragg_angle': bragg_angle, 'bragg_angle_deg': bragg_angle_deg, }
[docs]def get_crystal_parameters(material, energy_eV, h, k, l): """Obtain parameters for the specified crystal and energy. Args: material (str): material full name (e.g., 'Silicon'). energy_eV (float): photon energy [eV]. h (int): Miller's index h. k (int): Miller's index k. l (int): Miller's index l. Returns: dict: crystal parameters: d (float): interplanar spacing (d-spacing) [A]. xr0 (float): real part of the 0-th Fourier component of crystal's polarizability. xi0 (float): imaginary part of the 0-th Fourier component of crystal's polarizability. xrh (float): real part of the H-th Fourier component of crystal's polarizability (Sigma polarization). xih (float): imaginary part of the H-th Fourier component of crystal's polarizability (Sigma polarization). bragg_angle_deg (float): Bragg angle [deg]. """ # Check/convert types first: energy_eV = float(energy_eV) h = int(h) k = int(k) l = int(l) energy_keV = energy_eV / 1000.0 # convert to keV content = _get_server_data(energy_keV, material, h, k, l) crystal_parameters = _get_crystal_parameters(content, [h, k, l]) return crystal_parameters
def _get_crystal_parameters(content, miller_indices=None): """Get reflecting planes distance and polarizability from the server's response. Args: content: split content of the server's response. miller_indices: Miller's indices of reflection. Returns: dict: crystal parameters. """ a1_list = [] # lattice parameter d_server_list = [] # d-spacing from the server bragg_angle_list = [] xr0_list = [] xi0_list = [] xrh_list = [] xih_list = [] for row in content: if re.search('a1=', row): a1_list.append(row) elif re.search(' d=', row): d_server_list.append(row) elif re.search('QB=', row): bragg_angle_list.append(row) elif re.search('xr0=', row): xr0_list.append(row) elif re.search('xi0=', row): xi0_list.append(row) elif re.search('xrh', row): xrh_list.append(row) elif re.search('xih', row): xih_list.append(row) assert len(a1_list) > 0 a1 = _parse_xr_xi(a1_list[0]) d_calculated = a1 if miller_indices: d_calculated /= (sum(n ** 2 for n in miller_indices)) ** 0.5 assert len(d_server_list) > 0 d_server = _parse_xr_xi(d_server_list[0]) assert len(bragg_angle_list) > 0 bragg_angle_deg = _parse_xr_xi(bragg_angle_list[0]) assert len(xr0_list) > 0 xr0 = _parse_xr_xi(xr0_list[0]) xi0 = _parse_xr_xi(xi0_list[0]) xrh = _parse_xr_xi(xrh_list[0]) xih = _parse_xr_xi(xih_list[0]) return { 'a1': a1, 'd': d_calculated, 'd_calculated': d_calculated, 'd_server': d_server, 'bragg_angle_deg': bragg_angle_deg, 'xr0': xr0, 'xi0': xi0, 'xrh': xrh, 'xih': xih, } def _get_server_data(energy, material, h, k, l): """ The function gets data from the server and splits it by lines. :param energy: energy [keV]. :param material: material, e.g. Silicon or Germanium :param h: Miller's index h. :param k: Miller's index k. :param l: Miller's index l. :return content: split server's response. """ payload = { 'xway': 2, 'wave': energy, 'coway': 0, 'code': material, 'i1': h, 'i2': k, 'i3': l, 'df1df2': -1, 'modeout': 1, } r = requests.get(X0H_SERVER, params=payload) content = r.text content = content.split('\n') return content def _parse_xr_xi(string): return float(string.split('=')[-1].strip())