#!/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())