"""This module defines the settings and parameters handled by xrsdkit.
TODO: document the following module attributes:
- xrsdkit.definitions.setting_descriptions
- xrsdkit.definitions.parameter_descriptions
- xrsdkit.definitions.parameter_units
- xrsdkit.definitions.structures
- xrsdkit.definitions.structure_settings
- xrsdkit.definitions.modelable_structure_settings
- xrsdkit.definitions.form_factors
- xrsdkit.definitions.form_settings
- xrsdkit.definitions.modelable_form_factor_settings
- xrsdkit.definitions.form_factor_params
- xrsdkit.definitions.noise_models
- xrsdkit.definitions.noise_params
- xrsdkit.definitions.crystal_systems
- xrsdkit.definitions.crystal_point_groups
- xrsdkit.definitions.bravais_lattices
- xrsdkit.definitions.lattice_space_groups
- xrsdkit.definitions.sg_point_groups
"""
from collections import OrderedDict
import copy
import os
import numpy as np
import yaml
structure_names = ['diffuse','disordered','crystalline']
structures = OrderedDict.fromkeys(structure_names)
form_factor_names = ['atomic','polyatomic','guinier_porod','spherical']
form_factors = OrderedDict.fromkeys(form_factor_names)
noise_model_names = ['flat','low_q_scatter']
noise_models = OrderedDict.fromkeys(noise_model_names)
# supported structures, forms, and noise models
structures.update(
diffuse = 'disordered, non-interacting particles',
disordered = 'disordered, interacting particles',
crystalline = 'particles arranged in a lattice'
)
form_factors.update(
atomic = 'Single atom',
polyatomic = 'Multiple atoms',
guinier_porod = 'Scatterer described by Guinier-Porod equations',
spherical = 'Spherical particle'
)
noise_models.update(
flat = 'Flat noise floor for all q',
low_q_scatter = 'Flat noise floor plus a Guinier-Porod-like contribution'
)
# load parameters for all atomic scattering form factors
fpath = os.path.join(os.path.dirname(__file__),'scattering','atomic_scattering_params.yml')
f = open(fpath,'r')
atomic_params = yaml.load(f)
f.close()
def validate(structure,form,settings):
if structure in ['diffuse','disordered']:
# polyatomic forms are not allowed- everything else is ok
if form == 'polyatomic':
raise ValueError('{} structure does not support polyatomic forms'.format(structure))
elif structure == 'crystalline':
# guinier_porod forms are not allowed
if form == 'guinier_porod':
raise ValueError('crystalline structure does not support guinier_porod forms')
elif form == 'spherical':
# crystalline structure with spherical form factor:
# distributions of size are not allowed
if ('distribution' in settings) and (not settings['distribution'] == 'single'):
msg = 'crystalline structure does not support size distribution {}'\
.format(settings['distribution'])
raise ValueError(msg)
# top-level settings, along with default values:
# these settings must exist for the corresponding
# structures and form factors
#
# specify setting names for all structures:
# use fromkeys(list) get proper ordering
structure_settings = dict(
diffuse = OrderedDict(),
disordered = OrderedDict.fromkeys(['interaction']),
crystalline = OrderedDict.fromkeys(['lattice','space_group',\
'texture','integration_mode','use_symmetry',\
'structure_factor_mode','profile',\
'polarization_correction','lorentz_correction']
)
)
# use update() to specify default values
structure_settings['disordered'].update(interaction='hard_spheres'),
structure_settings['crystalline'].update(
lattice = 'P_cubic',
space_group = '',
structure_factor_mode = 'local',
integration_mode = 'spherical',
texture = 'random',
profile = 'voigt',
polarization_correction = True,
lorentz_correction = True,
use_symmetry = True
)
form_settings = dict(
atomic = OrderedDict.fromkeys(['symbol']),
polyatomic = OrderedDict.fromkeys(['n_atoms']),
guinier_porod = OrderedDict(),
spherical = OrderedDict.fromkeys(['distribution'])
)
form_settings['atomic'].update(symbol='C')
form_settings['polyatomic'].update(n_atoms=2)
form_settings['spherical'].update(distribution='single')
# top-level parameters, along with default definitions:
# these parameters are always valid for the corresponding
# form factors and noise models,
# regardless of settings, etc.
form_factor_params = dict(
atomic = OrderedDict(),
polyatomic = OrderedDict(),
guinier_porod = OrderedDict.fromkeys(['rg','D']),
spherical = OrderedDict.fromkeys(['r'])
)
form_factor_params['guinier_porod'].update(
rg = {'value':10.,'fixed':False,'bounds':[0.1,None],'constraint_expr':None},
D = {'value':4.,'fixed':True,'bounds':[0.,4.],'constraint_expr':None}
)
form_factor_params['spherical'].update(
r={'value':20.,'fixed':False,'bounds':[0.1,None],'constraint_expr':None}
)
noise_params = dict(
flat = OrderedDict.fromkeys(['I0']),
low_q_scatter = OrderedDict.fromkeys(
['I0','I0_flat_fraction','effective_rg','effective_D'])
)
noise_params['flat'].update(
I0={'value':1.E-3,'fixed':False,'bounds':[0.,None],'constraint_expr':None}
)
noise_params['low_q_scatter'].update(
I0 = {'value':100,'fixed':False,'bounds':[0.,None],'constraint_expr':None},
I0_flat_fraction = {'value':0.01,'fixed':False,'bounds':[0.,1.],'constraint_expr':None},
effective_rg = {'value':100.,'fixed':False,'bounds':[0.1,None],'constraint_expr':None},
effective_D = {'value':4.,'fixed':False,'bounds':[0.,4.],'constraint_expr':None}
)
# crystal system and lattice definitions
crystal_systems = ['triclinic','monoclinic','orthorhombic','tetragonal','trigonal','hexagonal','cubic']
bravais_lattices = [\
'triclinic','P_monoclinic','C_monoclinic',\
'P_orthorhombic','C_orthorhombic','A_orthorhombic',\
'I_orthorhombic','F_orthorhombic',\
'P_tetragonal','I_tetragonal',\
'rhombohedral','hexagonal',\
'P_cubic','I_cubic','F_cubic',\
]
all_lattices = bravais_lattices+['hcp','diamond']
# TODO: deprecate this,
# and find a better way to deal with modelable settings:
# consider that after classifying lattice,
# the next layer will be to classify space group,
# and after classifying n_atoms, the next layer should attempt
# to classify the atom symbols for all n_atoms species.
modelable_structure_settings = dict(
diffuse = [],
disordered = ['interaction'],
crystalline = ['lattice']
)
modelable_form_factor_settings = dict(
atomic = ['symbol'],
polyatomic = ['n_atoms'],
guinier_porod = [],
spherical = ['distribution']
)
[docs]def secondary_settings(structure,form,primary_settings):
"""Return secondary settings, along with sensible default values.
Secondary settings depend on the structure, form,
and possibly primary setting values.
Primary settings are defined by xrsdkit.definitions.structure_settings
and xrsdkit.definitions.form_factor_settings.
Parameters
----------
structure : str
Population structure designation, for fetching valid structure settings
form : str
Population form factor designation, for fetching valid form factor settings
primary_settings : dict
Dict of primary settings
Returns
-------
sec_stgs : OrderedDict
Dict of secondary settings along with sensible default values
"""
sec_stgs = OrderedDict()
for stg_nm,stg_val in primary_settings.items():
if stg_nm == 'n_atoms':
for iat in range(stg_val):
sec_stgs['symbol_{}'.format(iat)] = 'H'
if stg_nm == 'integration_mode':
if stg_val == 'spherical':
sec_stgs['q_min'] = 0.
sec_stgs['q_max'] = 1.
if stg_nm == 'distribution' and form == 'spherical':
if stg_val == 'r_normal':
sec_stgs['sampling_width']=3.5
sec_stgs['sampling_step']=0.05
return sec_stgs
# datatypes for all settings
def setting_datatypes(stg_nm):
if stg_nm in ['lattice','space_group',\
'texture','profile','structure_factor_mode',\
'integration_mode','interaction','distribution']:
return str
if stg_nm in ['q_min','q_max','sampling_width','sampling_step']:
return float
if stg_nm == 'n_atoms': return int
if 'symbol' in stg_nm: return str
if stg_nm in ['polarization_correction','lorentz_correction','use_symmetry']:
return bool
# all possible options for all settings (empty list if not enumerable)
def setting_selections(stg_nm,structure=None,form=None,prior_settings={}):
if setting_datatypes(stg_nm) == bool:
return [True,False]
if stg_nm == 'lattice': return all_lattices
if stg_nm == 'space_group':
if 'lattice' in prior_settings:
valid_sgs = list(lattice_space_groups[prior_settings['lattice']].values())
return ['']+valid_sgs
else:
return ['']
if stg_nm == 'texture': return ['random']
if stg_nm == 'profile': return ['gaussian','lorentzian','voigt']
if stg_nm == 'structure_factor_mode': return ['local','radial']
if stg_nm == 'integration_mode': return ['spherical']
if stg_nm == 'interaction': return ['hard_spheres']
if stg_nm == 'distribution':
if form == 'spherical':
return ['single','r_normal']
if stg_nm in ['q_min','q_max','sampling_width','sampling_step']: return []
if stg_nm == 'n_atoms': return []
if 'symbol' in stg_nm: return list(atomic_params.keys())
# generate any additional parameters that depend on setting selections
def structure_params(structure,prior_settings):
params = OrderedDict()
if structure == 'disordered':
if 'interaction' in prior_settings:
if prior_settings['interaction'] == 'hard_spheres':
params['r_hard'] = {'value':20.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['v_fraction'] = {'value':0.5,'fixed':False,'bounds':[0.01,0.7405],'constraint_expr':None}
# NOTE: parameters for new interactions potentials would go here
if structure == 'crystalline':
if 'lattice' in prior_settings:
if prior_settings['lattice'] in ['P_cubic','I_cubic','F_cubic','diamond','hcp']:
params['a']={'value':10.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
if prior_settings['lattice'] in ['hexagonal','P_tetragonal','I_tetragonal']:
params['a'] = {'value':10.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['c'] = {'value':20.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
if prior_settings['lattice'] == 'rhombohedral':
params['a'] = {'value':10.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['alpha'] = {'value':90.,'fixed':False,'bounds':[0,180.],'constraint_expr':None}
if prior_settings['lattice'] in ['P_orthorhombic','C_orthorhombic','I_orthorhombic','F_orthorhombic']:
params['a'] = {'value':10.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['b'] = {'value':12.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['c'] = {'value':15.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
if prior_settings['lattice'] in ['P_monoclinic','C_monoclinic']:
params['a'] = {'value':10.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['b'] = {'value':12.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['c'] = {'value':15.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['beta'] = {'value':90.,'fixed':False,'bounds':[0,180.],'constraint_expr':None}
if prior_settings['lattice'] == 'triclinic':
params['a'] = {'value':10.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['b'] = {'value':12.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['c'] = {'value':15.,'fixed':False,'bounds':[1.E-1,None],'constraint_expr':None}
params['alpha'] = {'value':90.,'fixed':False,'bounds':[0,180.],'constraint_expr':None}
params['beta'] = {'value':90.,'fixed':False,'bounds':[0,180.],'constraint_expr':None}
params['gamma'] = {'value':90.,'fixed':False,'bounds':[0,180.],'constraint_expr':None}
if 'profile' in prior_settings:
if prior_settings['profile'] == 'voigt':
params['hwhm_g'] = {'value':1.E-3,'fixed':False,'bounds':[1.E-9,None],'constraint_expr':None}
params['hwhm_l'] = {'value':1.E-3,'fixed':False,'bounds':[1.E-9,None],'constraint_expr':None}
if prior_settings['profile'] in ['gaussian','lorentzian']:
params['hwhm']={'value':1.E-3,'fixed':False,'bounds':[1.E-9,None],'constraint_expr':None}
return params
def additional_form_factor_params(form,prior_settings):
params = OrderedDict()
if form == 'polyatomic':
if 'n_atoms' in prior_settings:
for iat in range(prior_settings['n_atoms']):
params['occupancy_{}'.format(iat)] = {'value':1.,'fixed':True,'bounds':[0.,1.],'constraint_expr':None}
params['u_{}'.format(iat)] = {'value':0.1*iat,'fixed':True,'bounds':[-1.,1.],'constraint_expr':None}
params['v_{}'.format(iat)] = {'value':0.1*iat,'fixed':True,'bounds':[-1.,1.],'constraint_expr':None}
params['w_{}'.format(iat)] = {'value':0.1*iat,'fixed':True,'bounds':[-1.,1.],'constraint_expr':None}
if form == 'spherical':
if 'distribution' in prior_settings:
if prior_settings['distribution'] == 'r_normal':
params['sigma'] = {'value':0.05,'fixed':False,'bounds':[0.,2.],'constraint_expr':None}
return params
def all_params(structure,form=None,prior_settings={}):
all_pars = OrderedDict()
all_pars['I0'] = {'value':1.,'fixed':False,'bounds':[0.,None],'constraint_expr':None}
all_pars.update(structure_params(structure,prior_settings))
if form: all_pars.update(copy.deepcopy(form_factor_params[form]))
if form: all_pars.update(additional_form_factor_params(form,prior_settings))
return all_pars
# point groups associated with each crystal system
crystal_point_groups = dict(
triclinic = ['1','-1'],
monoclinic = ['2','2/m','222','m','mm2','mmm'],
orthorhombic = ['2','2/m','222','m','mm2','mmm'],
tetragonal = ['4','-4','4/m','422','4mm','-42m','4/mmm'],
trigonal = ['3','-3','32','3m','-3m'],
hexagonal = ['6','-6','6/m','622','6mm','-6m2','6/mmm'],
cubic = ['23','m-3','432','-43m','m-3m']
)
all_point_groups = []
for xtlsys in crystal_systems: all_point_groups.extend(crystal_point_groups[xtlsys])
# space groups associated with each lattice
lattice_space_groups = dict(
triclinic = {
1:'P1',2:'P-1'
},
P_monoclinic = {
3:'P2',4:'P2(1)',6:'Pm',7:'Pc',10:'P2/m',
11:'P2(1)/m',13:'P2/c',14:'P2(1)/c'
},
C_monoclinic = {
5:'C2',8:'Cm',9:'Cc',12:'C2/m',15:'C2/c'
},
P_orthorhombic = {
16:'P222',17:'P222(1)',18:'P2(1)2(1)2',19:'P2(1)2(1)2(1)',
25:'Pmm2',26:'Pmc2(1)',27:'Pcc2',28:'Pma2',29:'Pca2(1)',
30:'Pnc2',31:'Pmn2(1)',32:'Pba2',33:'Pna2(1)',34:'Pnn2',
47:'Pmmm',48:'Pnnn',49:'Pccm',50:'Pban',51:'Pmma',52:'Pnna',
53:'Pmna',54:'Pcca',55:'Pbam',56:'Pccn',57:'Pbcm',58:'Pnnm',
59:'Pmmn',60:'Pbcn',61:'Pbca',62:'Pnma'
},
C_orthorhombic = {
20:'C222(1)',21:'C222',35:'Cmm2',36:'Cmc2(1)',37:'Ccc2',
63:'Cmcm',64:'Cmce',65:'Cmmm',66:'Cccm',67:'Cmme',68:'Ccce'
},
A_orthorhombic = {
38:'Amm2',39:'Aem2',40:'Ama2',41:'Aea2'
},
I_orthorhombic = {
23:'I222',24:'I2(1)2(1)2(1)',44:'Imm2',45:'Iba2',
46:'Ima2',71:'Immm',72:'Ibam',73:'Ibca',74:'Imma'
},
F_orthorhombic = {
22:'F222',42:'Fmm2',43:'Fdd2',69:'Fmmm',70:'Fddd'
},
P_tetragonal = {
75:'P4',76:'P4(1)',77:'P4(2)',78:'P4(3)',81:'P-4',
83:'P4/m',84:'P4(2)/m',85:'P4/n',86:'P4(2)/n',
89:'P422',90:'P42(1)2',91:'P4(1)22',92:'P4(1)2(1)2',
93:'P4(2)22',94:'P4(2)2(1)2',95:'P4(3)22',96:'P4(3)2(1)2',
99:'P4mm',100:'P4bm',101:'P4(2)cm',102:'P4(2)nm',
103:'P4cc',104:'P4nc',105:'P4(2)mc',106:'P4(2)bc',
111:'P-42m',112:'P-42c',113:'P-42(1)m',114:'P-42(1)c',
115:'P-4m2',116:'P-4c2',117:'P-4b2',118:'P-4n2',123:'P4/mmm',
124:'P4/mcc',125:'P4/nbm',126:'P4/nnc',127:'P4/mbm',
128:'P4/mnc',129:'P4/nmm',130:'P4/ncc',131:'P4(2)/mmc',
132:'P4(2)/mcm',133:'P4(2)/nbc',134:'P4(2)/nnm',
135:'P4(2)/mbc',136:'P4(2)/mnm',137:'P4(2)/nmc',138:'P4(2)/ncm'
},
I_tetragonal = {
79:'I4',80:'I4(1)',82:'I-4',87:'I4/m',88:'I4(1)/a',97:'I422',
98:'I4(1)22',107:'I4mm',108:'I4cm',109:'I4(1)md',110:'I4(1)cd',
119:'I-4m2',120:'I-4c2',121:'I-42m',122:'I-42d',139:'I4/mmm',
140:'I4/mcm',141:'I4(1)/amd',142:'I4(1)/acd'
},
hexagonal = {
143:'P3',144:'P3(1)',145:'P3(2)',147:'P-3',
149:'P312',150:'P321',151:'P3(1)12',152:'P3(1)21',153:'P3(2)12',
154:'P3(2)21',156:'P3m1',157:'P31m',158:'P3c1',159:'P31c',
162:'P-31m',163:'P-31c',164:'P-3m1',165:'P-3c1',
168:'P6',169:'P6(1)',170:'P6(5)',171:'P6(2)',172:'P6(4)',
173:'P6(3)',174:'P-6',175:'P6/m',176:'P6(3)/m',177:'P622',
178:'P6(1)22',179:'P6(5)22',180:'P6(2)22',181:'P6(4)22',
182:'P6(3)22',183:'P6mm',184:'P6cc',185:'P6(3)cm',186:'P6(3)mc',
187:'P-6m2',188:'P-6c2',189:'P-62m',190:'P-62c',191:'P6/mmm',
192:'P6/mcc',193:'P6(3)/mcm',194:'P6(3)/mmc'
},
rhombohedral = {
146:'R3',148:'R-3',155:'R32',160:'R3m',
161:'R3c',166:'R-3m',167:'R-3c'
},
P_cubic = {
195:'P23',198:'P2(1)3',200:'Pm-3',201:'Pn-3',205:'Pa-3',
207:'P432',208:'P4(2)32',212:'P4(3)32',213:'P4(1)32',215:'P-43m',
218:'P-43n',221:'Pm-3m',222:'Pn-3n',223:'Pm-3n',224:'Pn-3m'
},
I_cubic = {
197:'I23',199:'I2(1)3',204:'Im-3',206:'Ia-3',211:'I432',
214:'I4(1)32',217:'I-43m',220:'I-43d',229:'Im-3m',230:'Ia-3d'
},
F_cubic = {
196:'F23',202:'Fm-3',203:'Fd-3',209:'F432',210:'F4(1)32',216:'F4-3m',
219:'F-43c',225:'Fm-3m',226:'Fm-3c',227:'Fd-3m',228:'Fd-3c'
},
hcp = {194:'P6(3)/mmc'},
diamond = {227:'Fd-3m'}
)
all_space_groups = {}
for lat in bravais_lattices:
for isg in lattice_space_groups[lat].keys():
all_space_groups[isg] = lattice_space_groups[lat][isg]
# point groups associated with each space group
sg_point_groups = OrderedDict()
sg_point_groups[all_space_groups[1]] = '1'
sg_point_groups[all_space_groups[2]] = '-1'
for isg in range(3,6): sg_point_groups[all_space_groups[isg]] = '2'
for isg in range(6,10): sg_point_groups[all_space_groups[isg]] = 'm'
for isg in range(10,16): sg_point_groups[all_space_groups[isg]] = '2/m'
for isg in range(16,25): sg_point_groups[all_space_groups[isg]] = '222'
for isg in range(25,47): sg_point_groups[all_space_groups[isg]] = 'mm2'
for isg in range(47,75): sg_point_groups[all_space_groups[isg]] = 'mmm'
for isg in range(75,81): sg_point_groups[all_space_groups[isg]] = '4'
sg_point_groups[all_space_groups[81]] = '-4'
sg_point_groups[all_space_groups[82]] = '-4'
for isg in range(83,89): sg_point_groups[all_space_groups[isg]] = '4/m'
for isg in range(89,99): sg_point_groups[all_space_groups[isg]] = '422'
for isg in range(99,111): sg_point_groups[all_space_groups[isg]] = '4mm'
for isg in range(111,123): sg_point_groups[all_space_groups[isg]] = '-42m'
for isg in range(123,143): sg_point_groups[all_space_groups[isg]] = '4/mmm'
for isg in range(143,147): sg_point_groups[all_space_groups[isg]] = '3'
sg_point_groups[all_space_groups[147]] = '-3'
sg_point_groups[all_space_groups[148]] = '-3'
for isg in range(149,156): sg_point_groups[all_space_groups[isg]] = '32'
for isg in range(156,162): sg_point_groups[all_space_groups[isg]] = '3m'
for isg in range(162,168): sg_point_groups[all_space_groups[isg]] = '-3m'
for isg in range(168,174): sg_point_groups[all_space_groups[isg]] = '6'
sg_point_groups[all_space_groups[174]] = '-6'
sg_point_groups[all_space_groups[175]] = '6/m'
sg_point_groups[all_space_groups[176]] = '6/m'
for isg in range(177,183): sg_point_groups[all_space_groups[isg]] = '622'
for isg in range(183,187): sg_point_groups[all_space_groups[isg]] = '6mm'
for isg in range(187,191): sg_point_groups[all_space_groups[isg]] = '-6m2'
for isg in range(191,195): sg_point_groups[all_space_groups[isg]] = '6/mmm'
for isg in range(195,200): sg_point_groups[all_space_groups[isg]] = '23'
for isg in range(200,207): sg_point_groups[all_space_groups[isg]] = 'm-3'
for isg in range(207,215): sg_point_groups[all_space_groups[isg]] = '432'
for isg in range(215,221): sg_point_groups[all_space_groups[isg]] = '-43m'
for isg in range(221,231): sg_point_groups[all_space_groups[isg]] = 'm-3m'
def lattice_coords(lattice):
if lattice in ['triclinic','P_monoclinic','P_orthorhombic','P_tetragonal','rhombohedral','hexagonal','P_cubic']:
return np.array([[0.,0.,0.]])
elif lattice in ['C_monoclinic','C_orthorhombic']:
return np.array([
[0.,0.,0.],
[0.,0.5,0.5]
])
elif lattice in ['A_orthorhombic']:
return np.array([
[0.,0.,0.],
[0.5,0.5,0.]
])
elif lattice in ['I_orthorhombic','I_tetragonal','I_cubic']:
return np.array([
[0.,0.,0.],
[0.5,0.5,0.5]
])
elif lattice in ['F_orthorhombic','F_cubic']:
return np.array([
[0.,0.,0.],
[0.5,0.5,0.],
[0.5,0.,0.5],
[0.,0.5,0.5]
])
elif lattice == 'hcp':
return np.array([
[0.,0.,0.],
[2./3,1./3,0.5]
])
elif lattice == 'diamond':
return np.array([
[0.,0.,0.],
[0.5,0.5,0.],
[0.5,0.,0.5],
[0.,0.5,0.5],
[0.25,0.25,0.25],
[0.75,0.75,0.25],
[0.75,0.25,0.75],
[0.25,0.75,0.75]
])
def lattice_vectors(lattice,a=None,b=None,c=None,alpha=None,beta=None,gamma=None):
if lattice in ['P_cubic','I_cubic','F_cubic','diamond']:
a1 = [a, 0., 0.]
a2 = [0., a, 0.]
a3 = [0., 0., a]
elif lattice in ['hcp']:
a1 = [a, 0., 0.]
a2 = [0.5*a, np.sqrt(3.)/2*a, 0.]
a3 = [0., 0., np.sqrt(8./3.)*a]
elif lattice in ['hexagonal']:
a1 = [a, 0., 0.]
a2 = [0.5*a, np.sqrt(3.)/2*a, 0.]
a3 = [0., 0., c]
elif lattice in ['P_orthorhombic','C_orthorhombic',\
'A_orthorhombic','I_orthorhombic','F_orthorhombic']:
a1 = [a, 0., 0.]
a2 = [0., b, 0.]
a3 = [0., 0., c]
elif lattice in ['P_tetragonal','I_tetragonal']:
a1 = [a, 0., 0.]
a2 = [0., a, 0.]
a3 = [0., 0., c]
elif lattice in ['P_monoclinic','C_monoclinic']:
beta_rad = float(beta)*np.pi/180.
a1 = [a, 0., 0.]
a2 = [0., b, 0.]
a3 = [c*np.cos(beta_rad), 0., c*np.sin(beta_rad)]
elif lattice in ['rhombohedral']:
alpha_rad = float(alpha)*np.pi/180.
omega = a**3*np.sqrt(1.-np.cos(alpha_rad)**2-np.cos(alpha_rad)**2-np.cos(alpha_rad)**2
+2*np.cos(alpha_rad)*np.cos(alpha_rad)*np.cos(alpha_rad))
cy = a*(np.cos(alpha_rad)-np.cos(alpha_rad)**2)/np.sin(alpha_rad)
cz = omega/(a**2*np.sin(alpha_rad))
a1 = [a, 0., 0.]
a2 = [a*np.cos(alpha_rad), a*np.sin(alpha_rad), 0.]
a3 = [a*np.cos(alpha_rad), cy, cz]
elif lattice in ['triclinic']:
alpha_rad = float(alpha)*np.pi/180.
beta_rad = float(beta)*np.pi/180.
gamma_rad = float(gamma)*np.pi/180.
omega = a*b*c*np.sqrt(1.-np.cos(alpha_rad)**2-np.cos(beta_rad)**2-np.cos(gamma_rad)**2
+2*np.cos(alpha_rad)*np.cos(beta_rad)*np.cos(gamma_rad))
cy = c*(np.cos(alpha_rad)-np.cos(beta_rad)*np.cos(gamma_rad))/np.sin(gamma_rad)
cz = omega/(a*b*np.sin(gamma_rad))
a1 = [a, 0., 0.]
a2 = [b*np.cos(gamma_rad), b*np.sin(gamma_rad), 0.]
a3 = [c*np.cos(beta_rad),cy,cz]
return a1,a2,a3
[docs]def reciprocal_lattice_vectors(lat1, lat2, lat3, crystallographic=True):
"""Compute the reciprocal lattice vectors.
If not `crystallographic`, the computation includes
the factor of 2*pi that is commmon in solid state physics
"""
rlat1_xprod = np.cross(lat2,lat3)
rlat2_xprod = np.cross(lat3,lat1)
rlat3_xprod = np.cross(lat1,lat2)
cellvol = np.dot(lat1,rlat1_xprod)
rlat1 = rlat1_xprod/cellvol
rlat2 = rlat2_xprod/cellvol
rlat3 = rlat3_xprod/cellvol
if not crystallographic:
rlat1 *= 2*np.pi
rlat2 *= 2*np.pi
rlat3 *= 2*np.pi
return rlat1, rlat2, rlat3
setting_descriptions = dict(
lattice = 'Lattice identifier for crystalline populations',
space_group = 'Crystalline space group specification (International symbol)',
texture = 'Distribution of orientations for crystalline populations',
profile = 'Selection of peak profile for broadening diffraction peaks',
structure_factor_mode = 'Strategy for computing off-peak structure factors',
integration_mode = 'Strategy for integrating over the reciprocal lattice',
q_min = 'minimum q-value for reciprocal space integration',
q_max = 'maximum q-value for reciprocal space integration',
interaction = 'Interaction potential describing disordered populations',
symbol = 'Atomic symbol',
n_atoms = 'Number of atoms',
distribution = 'Specifies a distribution for parameter values over a population',
sampling_width = 'Number of standard deviations to sample from distribution',
sampling_step = 'Resolution of sampling, in units of standard deviations'
)
parameter_units = dict(
I0 = 'arbitrary',
rg = 'Angstrom',
D = 'unitless',
r = 'Angstrom',
sigma = 'unitless',
r_hard = 'Angstrom',
v_fraction = 'unitless',
hwhm = '1/Angstrom',
hwhm_g = '1/Angstrom',
hwhm_l = '1/Angstrom',
a = 'Angstrom',
b = 'Angstrom',
c = 'Angstrom',
alpha = 'degree',
beta = 'degree',
gamma = 'degree'
)
parameter_descriptions = dict(
I0 = 'Intensity prefactor',
rg = 'Guinier-Porod model radius of gyration',
D = 'Guinier-Porod model Porod exponent',
r = 'Radius of spherical population',
sigma = 'standard deviation of normally distributed parameter divided by the parameter mean',
r_hard = 'Radius of hard-sphere potential for hard sphere (Percus-Yevick) structure factor',
v_fraction = 'volume fraction of particles in hard sphere (Percus-Yevick) structure factor',
hwhm_g = 'Gaussian profile half-width at half-max',
hwhm_l = 'Lorentzian profile half-width at half-max',
a = 'First lattice parameter',
b = 'Second lattice parameter',
c = 'Third lattice parameter',
alpha = 'Angle between second and third lattice vectors',
beta = 'Angle between first and third lattice vectors',
gamma = 'Angle between first and second lattice vectors',
u = 'fractional coordinate along first lattice vector',
v = 'fractional coordinate along second lattice vector',
w = 'fractional coordinate along third lattice vector',
occupancy = 'likelihood of finding an atomic specie at its lattice site'
)