diff --git a/Dans_Diffraction/__init__.py b/Dans_Diffraction/__init__.py index e65b822..216c361 100644 --- a/Dans_Diffraction/__init__.py +++ b/Dans_Diffraction/__init__.py @@ -208,11 +208,14 @@ def doc_str(): # tkGUI Activation def start_gui(xtl=None): """Start GUI window (requires tkinter)""" - try: - from .tkgui import CrystalGui - CrystalGui(xtl) - except ImportError: - print('GUI functionality not available, you need to install tkinter.') + from .tkgui import CrystalGui + CrystalGui(xtl) + + +def start_properties_gui(): + """Start XRay Interactions GUI""" + from .tkgui.properties import XrayInteractionsGui + XrayInteractionsGui() # FDMNES Activation @@ -224,3 +227,9 @@ def activate_fdmnes(initial_dir=None, fdmnes_filename='fdmnes_win64.exe'): :return: None """ fdmnes_checker(activate=True, fdmnes_filename=fdmnes_filename, initial_dir=initial_dir) + + +def start_fdmnes_gui(): + """Start GUI for FDMNES""" + from .tkgui.fdmnes import AnaFDMNESgui + AnaFDMNESgui() diff --git a/Dans_Diffraction/__main__.py b/Dans_Diffraction/__main__.py index 68c2cec..1da1284 100644 --- a/Dans_Diffraction/__main__.py +++ b/Dans_Diffraction/__main__.py @@ -37,4 +37,10 @@ print(xtl.info()) elif 'gui' in arg.lower(): xtl.start_gui() + elif 'properties' in arg.lower(): + from Dans_Diffraction.tkgui.properties import XrayInteractionsGui + XrayInteractionsGui() + elif 'fdmnes' in arg.lower(): + from Dans_Diffraction.tkgui.fdmnes import AnaFDMNESgui + AnaFDMNESgui() diff --git a/Dans_Diffraction/tkgui/basic_widgets.py b/Dans_Diffraction/tkgui/basic_widgets.py index ca9173d..e693d52 100644 --- a/Dans_Diffraction/tkgui/basic_widgets.py +++ b/Dans_Diffraction/tkgui/basic_widgets.py @@ -105,11 +105,14 @@ def topmenu(root, menu_dict): # Setup menubar menubar = tk.Menu(root) - for item in menu_dict: - men = tk.Menu(menubar, tearoff=0) - for label, function in menu_dict[item].items(): - men.add_command(label=label, command=function) - menubar.add_cascade(label=item, menu=men) + for item, obj in menu_dict.items(): + if isinstance(obj, dict): + men = tk.Menu(menubar, tearoff=0) + for label, function in obj.items(): + men.add_command(label=label, command=function) + menubar.add_cascade(label=item, menu=men) + else: + menubar.add_command(label=item,command=obj) root.config(menu=menubar) diff --git a/Dans_Diffraction/tkgui/properties.py b/Dans_Diffraction/tkgui/properties.py index 9a6c5c8..5557b51 100644 --- a/Dans_Diffraction/tkgui/properties.py +++ b/Dans_Diffraction/tkgui/properties.py @@ -8,7 +8,7 @@ from .. import functions_general as fg from .. import functions_crystallography as fc from .. import functions_plotting as fp -from .basic_widgets import tk, StringViewer, SelectionBox, messagebox +from .basic_widgets import tk, StringViewer, SelectionBox, messagebox, topmenu from .basic_widgets import (TF, BF, SF, LF, HF, bkg, ety, btn, opt, btn2, btn_active, opt_active, txtcol, @@ -312,9 +312,8 @@ class XrayInteractionsGui: Calculate X-Ray interactions with Matter """ - def __init__(self, xtl): + def __init__(self, xtl=None): """Initialise""" - self.xtl = xtl # Create Tk inter instance self.root = tk.Tk() self.root.wm_title('X-Ray Interactions with Matter') @@ -330,9 +329,9 @@ def __init__(self, xtl): frame.pack(side=tk.LEFT, anchor=tk.N) # Crystal info - name = xtl.name - formula = xtl.Properties.molname() - density = round(xtl.Properties.density(), 3) + name = xtl.name if xtl else 'Fe' + formula = xtl.Properties.molname() if xtl else 'Fe' + density = round(xtl.Properties.density(), 3) if xtl else 92.735 # Variables self.chem_formula = tk.StringVar(frame, formula) @@ -364,6 +363,14 @@ def __init__(self, xtl): 'Wavelength (nm)': 'nm' } + # ---Menu--- + menu = { + 'Periodic Table': self.menu_info_table, + 'Unit Converter': self.menu_converter, + 'About': self.menu_about, + } + topmenu(self.root, menu) + # ---Line 0--- line = tk.Frame(frame) line.pack(side=tk.TOP, expand=tk.TRUE, fill=tk.X, pady=5) @@ -460,6 +467,20 @@ def __init__(self, xtl): activebackground=btn_active) var.pack(side=tk.LEFT) + def menu_info_table(self): + from .periodic_table import PeriodTableGui + PeriodTableGui() + + def menu_converter(self): + """Open unit converter""" + from .converter import UnitConverter + UnitConverter() + + def menu_about(self): + about = "Xray Interactions with Matter\nBy Dan Porter 2025\n\n" + about += "Inspired by CXRO: https://henke.lbl.gov/optical_constants/\n\n" + messagebox.showinfo('X-Ray Interactions with Matter', about) + def get_scan(self): scan_type = self.scan_type.get() scan_min = self.scan_min.get() diff --git a/docs/Dans_Diffraction.classes_crystal.html b/docs/Dans_Diffraction.classes_crystal.html index b7e0df7..e23a791 100644 --- a/docs/Dans_Diffraction.classes_crystal.html +++ b/docs/Dans_Diffraction.classes_crystal.html @@ -6,7 +6,7 @@  
Dans_Diffraction.classes_crystal (version 3.3.0)
 
- 
Dans_Diffraction.classes_crystal (version 3.2.4)
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\classes_crystal.py

classes_crystal.py
@@ -34,8 +34,8 @@ Diamond
2017
 
-Version 3.2.4
-Last updated: 22/05/23
+Version 3.3.0
+Last updated: 06/02/25
 
Version History:
27/07/17 1.0    Version History started.
@@ -59,6 +59,7 @@ 15/11/21 3.2.2  Added Cell.orientation, updated Cell.UV()
12/01/21 3.2.3  Added Symmetry.axial_vector
22/05/23 3.2.4  Added Symmetry.wyckoff_label(), Symmetry.spacegroup_dict
+06/05/25 3.3.0  Symmetry.from_cif now loads operations from find_spacegroup if not already loaded
 
@author: DGPorter

@@ -70,8 +71,9 @@        
Dans_Diffraction.functions_crystallography
Dans_Diffraction.functions_general
+
Dans_Diffraction.functions_lattice
numpy
-

+

 
@@ -293,7 +295,7 @@
Bmatrix(self)
Calculate the Busing and Levy B matrix from a real space UV
 "choose the x-axis parallel to a*, the y-axis in the plane of a* and b*, and the z-axis perpendicular to
 that plane"
- W. R. Busing & H. A. Levy, Acta  Cryst.  (1967). 22,  457
+W. R. Busing & H. A. Levy, Acta  Cryst.  (1967). 22,  457
Qmag(self, HKL)
Returns the magnitude of wave-vector transfer of [h,k,l], in A-1
:param HKL: list of hkl reflections
@@ -334,11 +336,17 @@
calculateR(self, UVW)
Convert coordinates [u,v,w], in the basis of the unit cell, to
coordinates [x,y,z], in an orthogonal basis, in units of A
            R(x,y,z) = uA + vB + wC

E.G.
    R = Cell.calculateR([0.1,0,0]) # for a hexagonal system, a = 2.85
    > R = array([[0.285, 0, 0]])
+
choose_basis(self, option='default')
Choose the basis function
+Options:
+    1. c || z, b* || y - basis choice of Materials Project
+    2. a || x, c* || z - basis choice of Vesta
+    3. c || z, a* || x - basis choice of Busing & Levy (Default)
+:param option: name or number of basis
+
diff6circle(self, delta=0, gamma=0, energy_kev=None, wavelength=1.0)
Calcualte wavevector in diffractometer axis using detector angles
:param delta: float angle in degrees in vertical direction (about diff-z)
:param gamma: float angle in degrees in horizontal direction (about diff-x)
@@ -420,7 +428,7 @@ :param hkl: [3xn] array of (h, k, l) reciprocal lattice vectors
:return: [3xn] array of Q vectors in the lab coordinate system
-
latt(self, lattice_parameters=(), *args, **kwargs)
Generate lattice parameters with list
+
latt(self, *lattice_parameters, **kwargs)
Generate lattice parameters with list
  latt(1) -> a=b=c=1,alpha=beta=gamma=90
  latt([1,2,3]) -> a=1,b=2,c=3,alpha=beta=gamma=90
  latt([1,2,3,120]) -> a=1,b=2,c=3,alpha=beta=90,gamma=120
@@ -444,7 +452,7 @@ :param hkl: array : list of reflections
:return: correction
-
reciprocal_space_plane(self, x_axis=[1, 0, 0], y_axis=[0, 1, 0], centre=[0, 0, 0], q_max=4.0, cut_width=0.05)
Returns positions within a reciprocal space plane
+
reciprocal_space_plane(self, x_axis=(1, 0, 0), y_axis=(0, 1, 0), centre=(0, 0, 0), q_max=4.0, cut_width=0.05)
Returns positions within a reciprocal space plane
  x_axis = direction along x, in units of the reciprocal lattice (hkl)
  y_axis = direction along y, in units of the reciprocal lattice (hkl)
  centre = centre of the plot, in units of the reciprocal lattice (hkl)
@@ -607,10 +615,19 @@ :param mxmymz: array : atomic magnetic vectors [mu,mv,mw]
:return: None
-
new_cell(self, lattice_parameters=(), *args, **kwargs)
Replace the lattice parameters
+
new_cell(self, *lattice_parameters, **kwargs)
Replace the lattice parameters
:param lattice_parameters: [a,b,c,alpha,beta,gamma]
:return: None
+
search_distances(self, min_d=0.65, max_d=3.2, c_ele=None, elems=None, labels=None, simple=True)
Calculated atoms interatomic distances form each label.
+:param c_ele (list,string): only sites with noted elements
+                            if None all site
+:param elems (list,string): only distances with noted elements
+                            if None all site
+:param min_d: minimum distance 
+:param max_d: maximum distance
+:return dictionary:
+
start_gui(self)
Start Crystal GUI
:return: None
@@ -799,10 +816,19 @@ :param mxmymz: array : atomic magnetic vectors [mu,mv,mw]
:return: None
-
new_cell(self, lattice_parameters=(), *args, **kwargs)
Replace the lattice parameters
+
new_cell(self, *lattice_parameters, **kwargs)
Replace the lattice parameters
:param lattice_parameters: [a,b,c,alpha,beta,gamma]
:return: None
+
search_distances(self, min_d=0.65, max_d=3.2, c_ele=None, elems=None, labels=None, simple=True)
Calculated atoms interatomic distances form each label.
+:param c_ele (list,string): only sites with noted elements
+                            if None all site
+:param elems (list,string): only distances with noted elements
+                            if None all site
+:param min_d: minimum distance 
+:param max_d: maximum distance
+:return dictionary:
+
start_gui(self)
Start Crystal GUI
:return: None
diff --git a/docs/Dans_Diffraction.classes_orientation.html b/docs/Dans_Diffraction.classes_orientation.html index 7f7161e..1a30bac 100644 --- a/docs/Dans_Diffraction.classes_orientation.html +++ b/docs/Dans_Diffraction.classes_orientation.html @@ -31,11 +31,8 @@
       
Dans_Diffraction.functions_crystallography
-Dans_Diffraction.functions_general
+
Dans_Diffraction.functions_lattice
numpy
-os
-
re
-sys

@@ -59,7 +56,7 @@ class CrystalOrientation(builtins.object) -
   CrystalOrientation(lattice_parameters=(), *args, **kwargs)
+
CrystalOrientation(*lattice_parameters, **kwargs)
 
CrystalOrientation Class
 
@@ -70,7 +67,7 @@   y-axis : vector normal to x,z axes (parallel to beam (+z) in lab frame)
 
  Methods defined here:
-
__init__(self, lattice_parameters=(), *args, **kwargs)
Initialize self.  See help(type(self)) for accurate signature.
+
__init__(self, *lattice_parameters, **kwargs)
Initialize self.  See help(type(self)) for accurate signature.
__repr__(self)
Return repr(self).
@@ -195,6 +192,5 @@
       
string_matrix(m)
Convert [3*3] array to string
string_vector(v)
Convert [3] array to string
-
warn(message, category=None, stacklevel=1, source=None)
Issue a warning, or maybe ignore it or raise an exception.
\ No newline at end of file diff --git a/docs/Dans_Diffraction.classes_plotting.html b/docs/Dans_Diffraction.classes_plotting.html index 49548cf..23f5ad9 100644 --- a/docs/Dans_Diffraction.classes_plotting.html +++ b/docs/Dans_Diffraction.classes_plotting.html @@ -192,6 +192,15 @@ :param gamma:
:return: None +

plot_distance(self, min_d=0.65, max_d=3.2, labels=None, c_ele=None, elems=None, ranges=None, step=0.04)
Plot atoms interatomic distances form each label.
+:param c_ele (list,string): only sites with noted elements
+                            if None all site
+:param elems (list,string): only distances with noted elements
+                            if None all site
+:param min_d: minimum distance
+:param max_d: maximum distance
+:return:
+
plot_exchange_paths(self, cen_idx, nearest_neighbor_distance=6.6, exchange_type='O', bond_angle=90.0, search_in_cell=True, group_neighbors=True, disp=False)
Calcualtes exchange paths and adds them to the crystal structure plot
:param cen_idx: index of central ion in xtl.Structure
:param nearest_neighbor_distance: Maximum radius to serach to
@@ -210,7 +219,7 @@ :param show_labels: False*/True add text labels
:return:
-
plot_ms_azimuth(self, hkl, energy_kev, azir=[0, 0, 1], pv=[1, 0], numsteps=3, peak_width=0.1, full=False, pv1=False, pv2=False, sfonly=True, pv1xsf1=False, log=False)
Run the multiple scattering code and plot the result
+
plot_ms_azimuth(self, hkl, energy_kev, azir=[0, 0, 1], pv=[1, 0], numsteps=3, peak_width=0.1, full=False, pv1=False, pv2=False, sfonly=True, pv1xsf1=False, log=False, energy_sum_range=0.002)
Run the multiple scattering code and plot the result
See multiple_scattering.py for more details.
 
:param xtl: Crystal structure from Dans_Diffraction
@@ -225,6 +234,7 @@ :param sfonly: True/False: calculation type: sfonly *default
:param pv1xsf1: True/False: calculation type: pv1xsf1?
:param log: log y scale
+:param energy_sum_range: energy in keV to sum the calculation over (from energy_kev-range/2 to energy_kev+range/2)
:return: None
plot_multiple_scattering(self, hkl, azir=[0, 0, 1], pv=[1, 0], energy_range=[7.8, 8.2], numsteps=60, full=False, pv1=False, pv2=False, sfonly=True, pv1xsf1=False)
Run the multiple scattering code and plot the result
@@ -484,6 +494,15 @@ :param gamma:
:return: None
+
plot_distance(self, min_d=0.65, max_d=3.2, labels=None, c_ele=None, elems=None, ranges=None, step=0.04)
Plot atoms interatomic distances form each label.
+:param c_ele (list,string): only sites with noted elements
+                            if None all site
+:param elems (list,string): only distances with noted elements
+                            if None all site
+:param min_d: minimum distance
+:param max_d: maximum distance
+:return:
+
plot_exchange_paths(self, cen_idx, nearest_neighbor_distance=6.6, exchange_type='O', bond_angle=90.0, search_in_cell=True, group_neighbors=True, disp=False)
Calcualtes exchange paths and adds them to the crystal structure plot
:param cen_idx: index of central ion in xtl.Structure
:param nearest_neighbor_distance: Maximum radius to serach to
@@ -502,7 +521,7 @@ :param show_labels: False*/True add text labels
:return:
-
plot_ms_azimuth(self, hkl, energy_kev, azir=[0, 0, 1], pv=[1, 0], numsteps=3, peak_width=0.1, full=False, pv1=False, pv2=False, sfonly=True, pv1xsf1=False, log=False)
Run the multiple scattering code and plot the result
+
plot_ms_azimuth(self, hkl, energy_kev, azir=[0, 0, 1], pv=[1, 0], numsteps=3, peak_width=0.1, full=False, pv1=False, pv2=False, sfonly=True, pv1xsf1=False, log=False, energy_sum_range=0.002)
Run the multiple scattering code and plot the result
See multiple_scattering.py for more details.
 
:param xtl: Crystal structure from Dans_Diffraction
@@ -517,6 +536,7 @@ :param sfonly: True/False: calculation type: sfonly *default
:param pv1xsf1: True/False: calculation type: pv1xsf1?
:param log: log y scale
+:param energy_sum_range: energy in keV to sum the calculation over (from energy_kev-range/2 to energy_kev+range/2)
:return: None
plot_multiple_scattering(self, hkl, azir=[0, 0, 1], pv=[1, 0], energy_range=[7.8, 8.2], numsteps=60, full=False, pv1=False, pv2=False, sfonly=True, pv1xsf1=False)
Run the multiple scattering code and plot the result
diff --git a/docs/Dans_Diffraction.classes_scattering.html b/docs/Dans_Diffraction.classes_scattering.html index f77671b..ccf4587 100644 --- a/docs/Dans_Diffraction.classes_scattering.html +++ b/docs/Dans_Diffraction.classes_scattering.html @@ -6,7 +6,7 @@  
Dans_Diffraction.classes_scattering (version 2.3.5)
 
- 
Dans_Diffraction.classes_scattering (version 2.3.4)
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\classes_scattering.py

Scattering Class "classes_scattering.py"
@@ -16,8 +16,8 @@ Diamond
2017
 
-Version 2.3.4
-Last updated: 17/05/24
+Version 2.3.5
+Last updated: 23/12/24
 
Version History:
10/09/17 0.1    Program created
@@ -49,6 +49,7 @@ 15/05/24 2.3.4  Added "save" and "load" methods to structure factor calculation, improved powder for large calculations
16/05/24 2.3.4  Added printed progress bar to generate_intensity_cut during convolusion
17/05/24 2.3.4  Changed generate_intensity_cut to make it much faster
+23/12/24 2.3.5  Added polarised neutron options
 
@author: DGPorter

@@ -317,7 +318,19 @@

hkl_transmission(self, HKL, energy_kev=None)
Calculate the theta, two-theta and intensity of the given HKL in transmission geometry, display the result
-
intensity(self, hkl=None, scattering_type=None, int_hkl=True, **options)
Return the structure factor squared
+
intensity(self, hkl=None, scattering_type=None, int_hkl=None, **options)
Return the structure factor squared
+        I = |sum( f_i * occ_i * dw_i * exp( -i * 2 * pi * hkl.uvw ) |^2
+Where f_i is the elemental scattering factor, occ_i is the site occupancy, dw_i
+is the Debye-Waller thermal factor, hkl is the reflection and uvw is the site position.

+The following options for scattering_type are  supported:
+  'xray'  - uses x-ray form factors
+  'neutron' - uses neutron scattering lengths
+  'xray magnetic' - calculates the magnetic (non-resonant) component of the x-ray scattering
+  'neutron magnetic' - calculates the magnetic component of neutron scattering
+  'xray resonant' - calculates magnetic resonant scattering
+  'xray dispersion' - uses x-ray form factors including f'-if'' components

:param hkl: array[n,3] : reflection indexes (h, k, l)
:param scattering_type: str : one of ['xray','neutron', 'electron', 'xray magnetic','neutron magnetic','xray resonant']
:param int_hkl: Bool : when True, hkl values are converted to integer.
@@ -329,7 +342,7 @@   Scattering.magnetic_neutron([[1,0,0],[2,0,0],[3,0,0])
Returns an array with the same length as HKL, giving the real intensity at each reflection.
-
ms_azimuth(self, hkl, energy_kev, azir=[0, 0, 1], pv=[1, 0], numsteps=3, peak_width=0.1, full=False, pv1=False, pv2=False, sfonly=True, pv1xsf1=False)
Returns an azimuthal dependence at a particular energy
+
ms_azimuth(self, hkl, energy_kev, azir=(0, 0, 1), pv=(1, 0), numsteps=3, peak_width=0.1, full=False, pv1=False, pv2=False, sfonly=True, pv1xsf1=False, energy_sum_range=0.002)
Returns an azimuthal dependence at a particular energy
 
:param xtl: Crystal structure from Dans_Diffraction
:param hkl: [h,k,l] principle reflection
@@ -343,9 +356,10 @@ :param pv2: True/False: calculation type: pv2
:param sfonly: True/False: calculation type: sfonly *default
:param pv1xsf1: True/False: calculation type: pv1xsf1?
+:param energy_sum_range: energy in keV to sum the calculation over (from energy_kev-range/2 to energy_kev+range/2)
:return: None
-
multiple_scattering(self, hkl, azir=[0, 0, 1], pv=[1, 0], energy_range=[7.8, 8.2], numsteps=60, full=False, pv1=False, pv2=False, sfonly=True, pv1xsf1=False)
Run multiple scattering code, plot result.
+
multiple_scattering(self, hkl, azir=(0, 0, 1), pv=(1, 0), energy_range=(7.8, 8.2), numsteps=60, full=False, pv1=False, pv2=False, sfonly=True, pv1xsf1=False)
Run multiple scattering code, plot result.
 
mslist = xtl.Scatter.multiple_scattering([h,k,l], energy_range=[7.8, 8.2])
 
@@ -367,9 +381,9 @@   Scattering.neutron([[1,0,0],[2,0,0],[3,0,0])
Returns an array with the same length as HKL, giving the real intensity at each reflection.
-
new_intensity = intensity(self, hkl=None, scattering_type=None, int_hkl=True, **options)
+
new_intensity = intensity(self, hkl=None, scattering_type=None, int_hkl=None, **options)
-
new_structure_factor = structure_factor(self, hkl=None, scattering_type=None, int_hkl=True, **kwargs)
+
new_structure_factor = structure_factor(self, hkl=None, scattering_type=None, int_hkl=None, **kwargs)
old_intensity(self, HKL, scattering_type=None)
Calculate the squared structure factor for the given HKL
  Crystal.intensity([1,0,0])
@@ -467,7 +481,7 @@     self._scattering_theta_offset    :  sample offset angle
    self._scattering_specular_direction : [h,k,l] : reflections normal to sample surface
-
print_scattering_coordinates(self, hkl, azim_zero=[1, 0, 0], psi=0)
Transform magnetic vector into components within the scattering plane
+
print_scattering_coordinates(self, hkl, azim_zero=(1, 0, 0), psi=0)
Transform magnetic vector into components within the scattering plane
    ***warning - may not be correct for non-cubic systems***
print_symmetric_reflections(self, HKL)
Prints equivalent reflections
@@ -505,7 +519,7 @@ :param F0, F1, F2: Resonance factor Flm
:return: str
-
scatteringbasis(self, hkl, azim_zero=[1, 0, 0], psi=0)
Determine the scattering and polarisation vectors of a reflection based on energy, azimuth and polarisation.
+
scatteringbasis(self, hkl, azim_zero=(1, 0, 0), psi=0)
Determine the scattering and polarisation vectors of a reflection based on energy, azimuth and polarisation.
:param hkl: [n,3] array of reflections
:param azim_zero: [1,3] direction along which the azimuthal zero angle is determind
:param psi: float azimuthal angle about U3 in degrees
@@ -515,13 +529,13 @@ The azimuthal angle defines a rotation about the Q axis in a clockwise mannor, matching I16.
At an azimuth of 0degrees, U1 is perpendicular to Q, along the direction of azim_zero.
-
scatteringcomponents(self, mxmymz, hkl, azim_zero=[1, 0, 0], psi=0)
Transform magnetic vector into components within the scattering plane
+
scatteringcomponents(self, mxmymz, hkl, azim_zero=(1, 0, 0), psi=0)
Transform magnetic vector into components within the scattering plane
First transforms the moments into a cartesian reference frame.
   U1 = direction || ki - kf = Q
   U2 = direction || kf + ki (within scattering plane, pi)
   U3 = direction perp. to U1, U2 (normal to scattering plane, sigma)
-
scatteringvectors(self, hkl, energy_kev=None, azim_zero=[1, 0, 0], psi=0, polarisation='s-p')
Determine the scattering and polarisation vectors of a reflection based on energy, azimuth and polarisation.
+
scatteringvectors(self, hkl, energy_kev=None, azim_zero=(1, 0, 0), psi=0, polarisation='s-p')
Determine the scattering and polarisation vectors of a reflection based on energy, azimuth and polarisation.
:param xtl: Crystal Class
:param hkl: [n,3] array of reflections
:param energy_kev: x-ray scattering energy in keV
@@ -543,15 +557,16 @@ The basis is chosen such that Q defines the scattering plane, sigma and pi directions are normal to this plane.
Q is defined as Q = kout - kin, with kout +ve along the projection of azim_zero
-
setup_scatter(self, scattering_type=None, energy_kev=None, wavelength_a=None, powder_units=None, powder_pixels=None, powder_lorentz=None, powder_overlap=None, specular=None, parallel=None, theta_offset=None, min_theta=None, max_theta=None, min_twotheta=None, max_twotheta=None, output=True, scattering_factors=None, magnetic_formfactor=None, polarisation=None, polarisation_vector=None, azimuthal_reference=None, azimuth=None, flm=None)
Simple way to set scattering parameters, each parameter is internal to xtl (self)
+
setup_scatter(self, scattering_type=None, energy_kev=None, wavelength_a=None, powder_units=None, powder_pixels=None, powder_lorentz=None, powder_overlap=None, int_hkl=None, specular=None, parallel=None, theta_offset=None, min_theta=None, max_theta=None, min_twotheta=None, max_twotheta=None, output=True, scattering_factors=None, scattering_lengths=None, magnetic_formfactor=None, polarisation=None, polarisation_vector=None, azimuthal_reference=None, azimuth=None, flm=None)
Simple way to set scattering parameters, each parameter is internal to xtl (self)
 
-scattering_type: self._scattering type            :  'xray','neutron','xray magnetic','neutron magnetic','xray resonant', 'xray dispersion'
+scattering_type: self._scattering type            :  'xray','neutron','xray magnetic','neutron magnetic','xray resonant', 'xray dispersion', 'neutron polarised', 'xray polarised'
energy_kev  : self._energy_kev                    :  radiation energy in keV
wavelength_a: self._wavelength_a                  :  radiation wavelength in Angstrom
powder_units: self._powder_units                  :  units to use when displaying/ plotting ['twotheta', 'd',' 'q']
powder_pixels: self._powder_pixels                :  number of bins per inverse-angstrom in the powder spectrum
powder_lorentz: self._powder_lorentz_fraction     :  the fraction of Lorentzian in the peak function psuedo-Voight
powder_overlap: self._powder_min_overlap          :  minimum overlap of grouped reflections in powder
+int_hkl: self._integer_hkl                        :  round hkl values to integers
min_twotheta: self._scattering_min_two_theta      :  minimum detector (two-theta) angle
max_twotheta: self._scattering_max_two_theta      :  maximum detector (two-theta) angle
min_theta   : self._scattering_min_theta          :  minimum sample angle = -opening angle
@@ -560,6 +575,7 @@ specular    : self._scattering_specular_direction : [h,k,l] : reflections normal to sample surface
parallel    : self._scattering_parallel_direction : [h,k,l] : reflections normal to sample surface
scattering_factors: self._use_waaskirf_scattering_factor : xray scattering factor ['waaskirf', 'itc']
+scattering_lengths: self._use_sears_scattering_lengths : neutron scattering lengths ['sears', 'default']
magnetic_formfactor: self._use_magnetic_form_factor: True/False magnetic form factor for magnetic SF
polarisation: self._polarisation                  : beam polarisation setting ['ss', 'sp'*, 'sp', 'pp']
polarisation_vector: _polarisation_vector_incident: [x,y,z] incident polarisation vector
@@ -567,11 +583,23 @@ azimuth    : self._azimuthal_angle                : azimuthal angle in deg
flm        : self._resonant_flm                   : Resonant settings (flm1, flm2, flm3)
-
structure_factor(self, hkl=None, scattering_type=None, int_hkl=True, **kwargs)
Calculate the structure factor at reflection indexes (h,k,l)
+
structure_factor(self, hkl=None, scattering_type=None, int_hkl=None, **kwargs)
Calculate the structure factor at reflection indexes (h,k,l)
+        sf = sum( f_i * occ_i * dw_i * exp( -i * 2 * pi * hkl.uvw )
+Where f_i is the elemental scattering factor, occ_i is the site occupancy, dw_i
+is the Debye-Waller thermal factor, hkl is the reflection and uvw is the site position.

+The following options for scattering_type are  supported:
+  'xray'  - uses x-ray form factors
+  'neutron' - uses neutron scattering lengths
+  'xray magnetic' - calculates the magnetic (non-resonant) component of the x-ray scattering
+  'neutron magnetic' - calculates the magnetic component of neutron scattering with average polarisation
+  'xray resonant' - calculates magnetic resonant scattering
+  'xray dispersion' - uses x-ray form factors including f'-if'' components
+  'neutron polarised' - calcualtes magnetic component with incident polarised neutrons
+  'xray polarised' - calcualtes magnetic component with incident polarised x-rays

Notes:
- Uses x-ray atomic form factors, calculated from approximated tables in the ITC
-- This may be a little slow for large numbers of reflections, as it is not currently
- possible to use accelerated calculation methods in Jython.
- Debye-Waller factor (atomic displacement) is applied for isotropic ADPs
- Crystal.scale is used to scale the complex structure factor, so the intensity is
 reduced by (Crystal.scale)^2
@@ -617,7 +645,7 @@ No orbital component assumed
magnetic moments assumed to be in the same reference frame as the polarisation
-
xray_nonresonant_magnetic(self, HKL, energy_kev=None, azim_zero=[1, 0, 0], psi=0, polarisation='s-p', disp=False)
Calculate the non-resonant magnetic component of the structure factor
+
xray_nonresonant_magnetic(self, HKL, energy_kev=None, azim_zero=(1, 0, 0), psi=0, polarisation='s-p', disp=False)
Calculate the non-resonant magnetic component of the structure factor
for the given HKL, using x-ray rules and form factor
  Scattering.xray_magnetic([1,0,0])
  Scattering.xray_magnetic([[1,0,0],[2,0,0],[3,0,0])
@@ -628,7 +656,7 @@ No orbital component assumed
magnetic moments assumed to be in the same reference frame as the polarisation
-
xray_resonant(self, HKL, energy_kev=None, polarisation='sp', F0=1, F1=1, F2=1, azim_zero=[1, 0, 0], PSI=[0], disp=False)
Calculate structure factors using resonant scattering factors in the dipolar approximation
+
xray_resonant(self, HKL, energy_kev=None, polarisation='sp', F0=1, F1=1, F2=1, azim_zero=(1, 0, 0), PSI=[0], disp=False)
Calculate structure factors using resonant scattering factors in the dipolar approximation
  I = Scattering.xray_resonant(HKL,energy_kev,polarisation,F0,F1,F2)
Returns an array with the same length as HKL, giving the real intensity at each reflection.
    energy_kev = x-ray energy in keV
@@ -650,7 +678,7 @@  
From Hill+McMorrow Acta Cryst. 1996 A52, 236-244 Equ. (15)
-
xray_resonant_magnetic(self, HKL, energy_kev=None, azim_zero=[1, 0, 0], psi=0, polarisation='s-p', F0=0, F1=1, F2=0, disp=True)
Calculate the resonant magnetic component of the structure factor
+
xray_resonant_magnetic(self, HKL, energy_kev=None, azim_zero=(1, 0, 0), psi=0, polarisation='s-p', F0=0, F1=1, F2=0, disp=True)
Calculate the resonant magnetic component of the structure factor
for the given HKL, using x-ray rules and form factor
  Scattering.xray_magnetic([1,0,0])
  Scattering.xray_magnetic([[1,0,0],[2,0,0],[3,0,0])
@@ -661,7 +689,7 @@ No orbital component assumed
magnetic moments assumed to be in the same reference frame as the polarisation
-
xray_resonant_scattering_factor(self, HKL, energy_kev=None, polarisation='sp', F0=1, F1=1, F2=1, azim_zero=[1, 0, 0], psi=0, disp=False)
Calcualte fxres, the resonant x-ray scattering factor
+
xray_resonant_scattering_factor(self, HKL, energy_kev=None, polarisation='sp', F0=1, F1=1, F2=1, azim_zero=(1, 0, 0), psi=0, disp=False)
Calcualte fxres, the resonant x-ray scattering factor
  fxres = Scattering.xray_resonant_scattering_factor(HKL,energy_kev,polarisation,F0,F1,F2,azim_zero,psi)
energy_kev = x-ray energy in keV
    polarisation = x-ray polarisation: 'ss',{'sp'},'ps','pp'
@@ -726,12 +754,5 @@ Data and other attributes defined here:
ScatteringType = <class 'Dans_Diffraction.classes_scattering.ScatteringTypes.ScatteringType'>
Container for scattering type switcher
-

- - - - - -
 
-Data
       __scattering_types__ = {'neutron': ['neutron', 'n', 'nuclear'], 'neutron magnetic': ['neutron magnetic', 'magnetic neutron', 'magnetic'], 'xray': ['xray', 'x', 'x-ray', 'thomson', 'charge'], 'xray dispersion': ['dispersion', 'xray dispersion'], 'xray magnetic': ['xray magnetic', 'magnetic xray', 'spin xray', 'xray spin'], 'xray resonant': ['xray resonant', 'resonant', 'resonant xray', 'rxs']}
+ \ No newline at end of file diff --git a/docs/Dans_Diffraction.functions_crystallography.html b/docs/Dans_Diffraction.functions_crystallography.html index c66284f..617802a 100644 --- a/docs/Dans_Diffraction.functions_crystallography.html +++ b/docs/Dans_Diffraction.functions_crystallography.html @@ -6,7 +6,7 @@  
Dans_Diffraction.functions_crystallography (version 4.0.1)
 
- 
Dans_Diffraction.functions_crystallography (version 3.8.2)
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\functions_crystallography.py

Module: functions_crystallography.py
@@ -20,8 +20,7 @@     OR
    - from Dans_Diffraction import functions_crystallography as fc
 
-Version 3.8.2
-Last updated: 02/07/23
+Version 4.0.1
 
Version History:
09/07/15 0.1    Version History started.
@@ -52,10 +51,15 @@ 07/05/23 3.8.0  Added electron_scattering_factors and electron wavelength formula
22/05/23 3.8.1  Added wyckoff_label, find_spacegroup
02/07/23 3.8.2  Added wavelength options to several functions, plut DeBroglie wavelength function
+26/09/24 3.9.0  Added complex neutron scattering lengths for isotopes from package periodictable
+06/11/24 4.0.0  Fixed error with triclinic bases, added function_lattice.
+20/11/24 4.0.1  Added alternative neutron scattering length table
 
Acknoledgements:
    April 2020  Thanks to ChunHai Wang for helpful suggestions in readcif!
    May 2023    Thanks to Carmelo Prestipino for adding electron scattering factors
+    Sep 2024    Thanks to thamnos for suggestion to add complex neutron scattering lengths
+    Oct 2024    Thanks to Lee Richter for pointing out the error in triclinic basis definition
 
@author: DGPorter

@@ -66,23 +70,32 @@        
Dans_Diffraction.functions_general
-json
-
numpy
-os
-
re
-sys
-

+Dans_Diffraction.functions_lattice
+json
+numpy
+os
+re
+sys
+

-
 
Functions
       
Bmatrix(UV)
Calculate the Busing and Levy B matrix from a real space UV
+
Bmatrix(basis_vectors)
Calculate the Busing and Levy B matrix from real space basis vectors, with units of 2pi
"choose the x-axis parallel to a*, the y-axis in the plane of a* and b*, and the z-axis perpendicular to that plane"
From: W. R. Busing and H. A. Levy, Acta Cryst. (1967). 22, 457-464
"Angle calculations for 3- and 4-circle X-ray and neutron diffractometers"
-See also: https://docs.mantidproject.org/nightly/concepts/Lattice.html
+See also: https://docs.mantidproject.org/nightly/concepts/Lattice.html

+B = [[b1, b2 * cos(beta3), b3 * cos(beta2)],
+    [0, b2 * sin(beta3), -b3 * sin(beta2) * cos(alpha1)],
+    [0, 0, 1 / a3]]
+return 2pi * B  # equivalent to transpose([a*, b*, c*])

+:param basis_vectors: [3*3] array of basis vectors [a[3], b[3], c[3]]
+:return: [3*3] B matrix * 2 pi
Q2hkl(qvec, UVstar)
Index vectors in an orthonal basis with a reciprocal basis
:param qvec: [nx3] array of coordinates in an orthogonal basis in A-1
:param UV: [3x3] array of unit cell vectors [[a1,a2,a3],[b1,b2,b3],[c1,c2,c3]]
@@ -156,29 +169,51 @@ :param element: str or list of str, name of element. If element string includes a number, this will multiply values
:param energy_kev: float or list energy in keV (None to return original, uninterpolated list)
:return: f1, f2, shape dependent on shapes of element and energy_kev:  float, or [ene] or [ele, ene]
-
attenuation(element_z, energy_keV)
Returns the x-ray mass attenuation, u/p, in cm^2/g
+
attenuation(element_z, energy_kev)
Returns the x-ray mass attenuation, u/p, in cm^2/g
  e.g. A = attenuation(23,np.arange(7,8,0.01)) # Cu
       A = attenuation([23,24,25], 5.6)
       a = attenuation(19,4.5) # K
balance_atom_charge(list_of_elements, occupancy=None)
Determine the default charges and assign remaining charge to
unspecified elements
-:param list_of_elements:
+:param list_of_elements: list of element symbols ['Co', 'Fe', ...]
+:param occupancy: None or list of occupancies, same length as above
:return: [list of charges]
biso2uiso(biso)
Convert B isotropic thermal parameters to U isotropic thermal parameters
:param biso: Biso value or array
:return: Uiso value or array
-
cal2theta(qmag, energy_kev=17.794, wavelength_a=None)
Calculate theta at particular energy in keV from |Q|
- twotheta = cal2theta(Qmag,energy_kev=17.794)
+
cal2theta(qmag, energy_kev=17.794, wavelength_a=None)
Calculate scattering angle at particular energy in keV from magnitude of the wavevector, |Q|
+ twotheta = cal2theta(Qmag, energy_kev=17.794)
+ - equivalent to -
+ twotheta = 2 * arcsin( qmag * wl / 4pi )

+:param qmag: float or array of wavevector magnitudes, in inverse-Angstroms
+:param energy_kev: float photon energy in keV
+:param wavelength_a: float wavelength in Anstrom
+:return two-theta angle in degrees (or array if qmag is array)
calc_vol(UV)
Calculate volume in Angstrom^3 from unit vectors
caldspace(twotheta, energy_kev=17.794, wavelength_a=None)
Calculate d-spacing from two-theta
- dspace = caldspace(tth, energy_kev)
+  dspace = caldspace(tth, energy_kev)
+   - equivalent to -
+  dspace = wl / (2 * sin(theta))

+:param twotheta: float or array of scattering angles, in degrees
+:param energy_kev: float photon energy in keV
+:param wavelength_a: float wavelength in Anstrom
+:return lattice d-spacing in Anstrom
callattice(twotheta, energy_kev=17.794, hkl=(1, 0, 0))
Calculate cubic lattice parameter, a from reflection two-theta
:param twotheta: Bragg angle, deg
:param energy_kev: energy in keV
:param hkl: reflection (cubic only
:return: float, lattice contant
calqmag(twotheta, energy_kev=17.794, wavelength_a=None)
Calculate |Q| at a particular 2-theta (deg) for energy in keV
- magQ = calqmag(twotheta, energy_kev=17.794)
+  magQ = calqmag(twotheta, energy_kev=17.794)
+   - equivalent to -
+  qmag = 4 * pi * sin(theta) / wl

+:param twotheta: float or array of scattering angles, in degrees
+:param energy_kev: float photon energy in keV
+:param wavelength_a: float wavelength in Anstrom
+:return wavevector magnitude in inverse-Angstrom
cif2dict(cifvals)
From a dict of key:value pairs generated from a *.cif file (using readcif),
read standard crystallographic infromation into a crystal dictionary, with keys:
    'filename' - cif filename
@@ -477,19 +512,6 @@   HKL = genHKL([-1,1])
E.G.
  HKL = genHKL([-2,2],[0,3],[1,1])
-
gen_lattice_parameters(lattice_parameters=(), *args, **kwargs)
Generate list of lattice parameters:
- a,b,c,alpha,beta,gamma = gen_lattice_parameters(args)
-args:
-  1 -> a=b=c=1,alpha=beta=gamma=90
-  [1,2,3] -> a=1,b=2,c=3,alpha=beta=gamma=90
-  [1,2,3,120] -> a=1,b=2,c=3,alpha=beta=90,gamma=120
-  [1,2,3,10,20,30] -> a=1,b=2,c=3,alpha=10,beta=20,gamma=30
-  1,2,3,10,20,30 -> a=1,b=2,c=3,alpha=10,beta=20,gamma=30
-  a=1,b=2,c=3,alpha=10,beta=20,gamma=30 -> a=1,b=2,c=3,alpha=10,beta=20,gamma=30
-:param lattice_parameters: float or list
-:param args: floats
-:param kwargs: lattice parameters
-:return: a,b,c,alpha,beta,gamma
gen_sym_axial_vector(sym_ops, x, y, z)
 Transform axial vector by symmetry operations
Usage:
  uvw = gen_symcen_pos(sym_ops,cen_ops,x,y,z)
@@ -590,11 +612,15 @@ :param energy_kev: float energy in keV
:param wavelength_a: float wavelength in Angstroms
:return: [nx1] array of d-spacing in A
-
indx(Q, UV)
Index Q(x,y,z) on on lattice [h,k,l] with unit vectors UV
-Usage:
-  HKL = indx(Q,UV)
-  Q = [[nx3]] array of vectors
-  UV = [[3x3]] matrix of vectors [a,b,c]
+
indx(coords, basis_vectors)
Index cartesian coordinates on a lattice defined by basis vectors
+Usage (reciprocal space):
+    [[h, k, l], ...] = index_lattice([[qx, qy, qz], ...], [a*, b*, c*])
+Usage (direct space):
+    [u, v, w] = index_lattice([x, y, z], [a, b, c])

+:param coords: [nx3] array of coordinates
+:param basis_vectors: [3*3] array of basis vectors [a[3], b[3], c[3]]
+:return: [nx3] array of vectors in units of reciprocal lattice vectors
invert_sym(sym_op)
Invert the sign of the given symmetry operation
Usage:
  new_op = invert_sym(sym_op)
@@ -620,35 +646,19 @@ :param R: [3x3] rotation matrix (see diffractometer_rotation)
:param LAB: [3x3] transformation matrix between diffractometer frame and lab frame
:return: [3xn] array of Q vectors in the lab coordinate system
-
latpar2uv(lattice_parameters=(), *args, **kwargs)
Convert a,b,c,alpha,beta,gamma to UV=[A,B,C]
+
latpar2uv(*lattice_parameters, **kwargs)
Convert a,b,c,alpha,beta,gamma to UV=[A,B,C]
 UV = latpar2uv(a,b,c,alpha=90.,beta=90.,gamma=120.)
 Vector c is defined along [0,0,1]
 Vector a and b are defined by the angles
-
latpar2uv_rot(lattice_parameters=(), *args, **kwargs)
Convert a,b,c,alpha,beta,gamma to UV=[A,B,C]
+
latpar2uv_rot(*lattice_parameters, **kwargs)
Convert a,b,c,alpha,beta,gamma to UV=[A,B,C]
 UV = latpar2uv_rot(a,b,c,alpha=90.,beta=90.,gamma=120.)
 Vector b is defined along [0,1,0]
 Vector a and c are defined by the angles
-
latparBmatrix(a, b=None, c=None, alpha=90.0, beta=90.0, gamma=90.0)
Calculate the Busing and Levy B matrix from a real space UV
-"choose  the x  axis parallel  to a, the  y  axis  in  the  plane  of  a  and  b,  and  the  z  axis
-perpendicular  to  that  plane"
-From: W. R. Busing and H. A. Levy, Acta Cryst. (1967). 22, 457-464
-"Angle calculations for 3- and 4-circle X-ray and neutron diffractometers"
-See also: https://docs.mantidproject.org/nightly/concepts/Lattice.html
-:param a, b, c: float lattice parameters
-:param alpha, beta, gamma: float lattice angles
-:return: [3*3] array
-
latpar_reciprocal(UV)
Return the reciprocal lattice parameters in inverse-angstroms and degrees
-:param UV: [3*3] unit vector [a,b,c]
-:return: a*, b*, c*, alpha*, beta*, gamma*
-
latparvolume(a, b=None, c=None, alpha=90.0, beta=90.0, gamma=90.0)
Calcualte the unit cell volume in A^3
-:param a, b, c: float lattice parameters
-:param alpha, beta, gamma: float lattice angles
-:return: float volume in Angstrom^3
-
lattice_hkl2dspace(hkl, lattice_parameters=(), *args, **kwargs)
Calcualte dspace from lattice parameters
+
lattice_hkl2dspace(hkl, *lattice_parameters, **kwargs)
Calcualte dspace from lattice parameters
:param hkl: [nx3] array of reflections
:param lattice_parameters: a,b,c,alpha,beta,gamma
:return: float, d-spacing in A
-
lattice_hkl2twotheta(hkl, energy_kev=17.794, lattice_parameters=(), *args, **kwargs)
Calcualte dspace from lattice parameters
+
lattice_hkl2twotheta(hkl, *lattice_parameters, energy_kev=17.794, wavelength_a=None, **kwargs)
Calcualte dspace from lattice parameters
:param hkl: [nx3] array of reflections
:param energy_kev: float, radiation energy in keV
:param lattice_parameters: a,b,c,alpha,beta,gamma
@@ -745,11 +755,24 @@   E [meV] ~ 81.82 / lambda^2 [A]
:param wavelength_a: neutron wavelength in Angstroms
:return: energy in meV
-
neutron_scattering_length(element)
Return neutron scattering length, b, in fm
-Uses bound coherent scattering length from NIST
-https://www.ncnr.nist.gov/resources/n-lengths/
- b = neutron_scattering_length('Co')
-:param element: [n*str] list or array of elements
+
neutron_scattering_length(elements, table='neutron data booklet')
Return neutron scattering length, b, in fm

+    b = neutron_scattering_length('Co')

+Now includes complex neutron scattering lengths for isotopes from package periodictable
+    b = neutron_scattering_length('7-Li')

+Lists of elements also allowed
+    [bLi, bCo, bO] = neutron_scattering_length(['7-Li', 'Co', 'O'])

+Default values are extracted from Periodic Table https://github.com/pkienzle/periodictable
+ - Values originally from Neutron Data Booklet, by A-J Dianoux, G. Lander (2003), with additions and corrections upto v1.7.0 (2023)

+Alternative values are also available:
+ - ITC Vol. C, Section 4.4.4., By V. F. Sears Table 4.4.4.1 (Jan 1995)

+:param elements: [n*str] list or array of elements
+:param table: name of data table to use, options are 'neutron data booklet' or 'sears'
:return: [n] array of scattering lengths
neutron_wavelength(energy_mev)
Calcualte the neutron wavelength in Angstroms using DeBroglie's formula
  lambda [A] ~ sqrt( 81.82 / E [meV] )
@@ -819,6 +842,20 @@   data[22]['Element']
:param filedir: location of "Dans Element Properties.txt"
:return: [dict, ...]
+
read_neutron_scattering_lengths(table='neutron data booklet')
Read neutron scattering length of element or isotope
+Returns table of complex bound coherent neutron scattering length, in fm for elements and isotopes

+    Natural average for each element given by 'element', e.g. 'Ti'
+    Isotope value given by 'weight-element', e.g. '46-Ti'

+Default values are extracted from Periodic Table https://github.com/pkienzle/periodictable
+ - Values originally from Neutron Data Booklet, by A-J Dianoux, G. Lander (2003), with additions and corrections upto v1.7.0 (2023)

+Alternative values are also available:
+ - ITC Vol. C, Section 4.4.4., By V. F. Sears Table 4.4.4.1 (Jan 1995)

+:param table: name of data table to use, options are 'neutron data booklet' or 'sears'
+:return: {'isotope': complex, ...}
readcif(filename=None, debug=False)
Open a Crystallographic Information File (*.cif) file and store all entries in a key:value dictionary
 Looped values are stored as lists under a single key entry
 All values are stored as strings
@@ -1020,7 +1057,7 @@  
:param operations: list of str ['x,y,z',]
:return: list of str ['x,y,z']
-
ubmatrix(uv, u)
Return UB matrix
+
ubmatrix(uv, u)
Return UB matrix (units of 2pi)
:param uv: [3*3] unit vector [a,b,c]
:param u: [3*3] orientation matrix in the diffractometer frame
:return: [3*3] array
@@ -1149,7 +1186,10 @@
ATOMFILE = r'C:\Users\grp66007\OneDrive - Diamond Light Sourc...Dans_Diffraction\data\Dans Element Properties.txt'
CIF_REQUIRES = ['_cell_length_a', '_cell_length_b', '_cell_length_c', '_cell_angle_alpha', '_cell_angle_beta', '_cell_angle_gamma', '_atom_site_label', '_atom_site_fract_x', '_atom_site_fract_y', '_atom_site_fract_z']
ELEMENT_LIST = ['Zr', 'Mo', 'Es', 'Eu', 'Fe', 'Fl', 'Fm', 'Fr', 'Ga', 'Gd', 'Ge', 'He', 'Hf', 'Hg', 'Ho', 'Hs', 'In', 'Ir', 'Kr', 'La', ...]
+NSLFILE = r'C:\Users\grp66007\OneDrive - Diamond Light Sourc...ction\data\neutron_isotope_scattering_lengths.dat'
+NSLFILE_SEARS = r'C:\Users\grp66007\OneDrive - Diamond Light Sourc...data\neutron_isotope_scattering_lengths_sears.dat'
PENGFILE = r'C:\Users\grp66007\OneDrive - Diamond Light Sourc...s\Dans_Diffraction\Dans_Diffraction\data\peng.dat'
datadir = r'C:\Users\grp66007\OneDrive - Diamond Light Sourc...onProjects\Dans_Diffraction\Dans_Diffraction\data'
-element_regex = re.compile('Zr|Mo|Es|Eu|Fe|Fl|Fm|Fr|Ga|Gd|Ge|He|...n|Co|Cr|Cs|Cu|Mn|Md|Mt|Rb|Rf|Rh|Rn|Ru|Sb|Sc|Se|S)
+element_regex = re.compile('Zr|Mo|Es|Eu|Fe|Fl|Fm|Fr|Ga|Gd|Ge|He|...n|Co|Cr|Cs|Cu|Mn|Md|Mt|Rb|Rf|Rh|Rn|Ru|Sb|Sc|Se|S)
+regex_sub_element = re.compile('[^a-zA-Z]') \ No newline at end of file diff --git a/docs/Dans_Diffraction.functions_general.html b/docs/Dans_Diffraction.functions_general.html index be43621..022d50e 100644 --- a/docs/Dans_Diffraction.functions_general.html +++ b/docs/Dans_Diffraction.functions_general.html @@ -6,7 +6,7 @@  
Dans_Diffraction.functions_general (version 2.2.3, 06/Feb/2025)
 
- 
Dans_Diffraction.functions_general (version 2.2.2, 15/May/2024)
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\functions_general.py

Module: Generally useful functions "functions_general.py"
@@ -18,8 +18,8 @@ Diamond
2021
 
-Version 2.2.0
-Last updated: 11/03/22
+Version 2.2.3
+Last updated: 06/02/25
 
Version History:
06/01/18 1.0    Program created from DansGeneralProgs.py V2.3
@@ -37,6 +37,7 @@ 15/11/21 2.1.0  Added normal_basis
11/03/22 2.2.0  Added Lorentzian, pVoight, peak_function functions
15/05/24 2.2.2  Added sph2cart, meshgrid_sphere
+06/02/25 2.2.3  refactored norm to remove inspection errors
 
@author: DGPorter

@@ -84,6 +85,11 @@ :param line_start: array, position of the start of the line
:param line_end:  array, position of the end of the line
:param point: array, arbitary position in space
+:return: float

+
distance2plane(line_start, line_end, point)
Calculate distance from a plane (defined by a perpendicular vector) to an arbitary point in space
+:param vector_start: array, position lying on plane and vector start
+:param line_end:  array, position of the end of the vector
+:param point: array, arbitary position in space
:return: float
find_index(A, value)
Return the index of the closest number in array A to value
 
@@ -213,11 +219,11 @@
nice_print(precision=4, linewidth=300)
Sets default printing of arrays to a nicer format
norm(A)
Returns normalised vector A
If A has 2 dimensions, returns an array of normalised vectors
-The returned array will be the same shape as the given array.
+The returned array of vectors will be squeezed to the minimum dimension
 
E.G.
norm([1,1,1]) = [1,1,1]/1.732 = [ 0.57735,  0.57735,  0.57735]
norm(array([[1,1,1],[2,2,2]]) = [ [ 0.57735,  0.57735,  0.57735] , [ 0.57735,  0.57735,  0.57735] ]
+    norm([1,1,1]) = [1,1,1]/1.732 = [ 0.57735,  0.57735,  0.57735]
+    norm(array([[1,1,1],[2,2,2]]) = [ [ 0.57735,  0.57735,  0.57735] , [ 0.57735,  0.57735,  0.57735] ]
normal_basis(vec, normal=(1, 0, 0), azi=0)
Return a vector basis with 3 normal vectors such that:
    [|normal x vec|, |vec x (normal x vec)|, |vec|]
if azi is given, the resulting vectors [0,1] will be rotated about [2]
@@ -261,6 +267,7 @@     centre_y = if 2D, centre along the y-axis (defaults to centre)
    fwhm_y = if 2D, fwhm along the y-axis (defaults to fwhm)
quad(A)
Returns +/-1 depending on quadrant of 3D vector A

i.e.:    A      Returns
    [ 1, 1, 1]    1
    [-1, 1, 1]    1
diff --git a/docs/Dans_Diffraction.functions_lattice.html b/docs/Dans_Diffraction.functions_lattice.html new file mode 100644 index 0000000..6725fa0 --- /dev/null +++ b/docs/Dans_Diffraction.functions_lattice.html @@ -0,0 +1,194 @@ + +Python: module Dans_Diffraction.functions_lattice + + + + + +
 
+ 
Dans_Diffraction.functions_lattice (version 1.0.0)
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\functions_lattice.py
+

Module: functions_lattice.py

+By Dan Porter, PhD
+Diamond
+2024


+Version 1.0
+Last updated: 17/10/24

+Version History:
+17/10/24 1.0.0  Created module extracting lattice functions from functions_crystallography

+Acknoledgements:
+    October 2024    Thanks to Lee Richter for pointing out the error in triclinic angles!

+@author: DGPorter

+

+ + + + + +
 
+Modules
       
numpy
+

+ + + + + +
 
+Functions
       
angles_allowed(alpha=90, beta=90, gamma=90)
Determine if lattice angles are suitable for basis vectors

+https://journals.iucr.org/a/issues/2011/01/00/au5114/index.html
+As reported in International Tables for Crystallography:
+    Donnay & Donnay, 1959 International Tables for X-ray Crystallography, Vol. II.
+    Koch, 2004 International Tables for Crystallography, Vol. C.

+:param alpha: angle in degrees
+:param beta: angle in degrees
+:param gamma: angle in degrees
+:return: bool, True if angles are suitable for creation of basis
+
basis2bandl(basis)
Calculate the Busing and Levy B matrix from a real space UV
+"choose the x-axis parallel to a*, the y-axis in the plane of a* and b*, and the z-axis perpendicular to that plane"
+From: W. R. Busing and H. A. Levy, Acta Cryst. (1967). 22, 457-464
+"Angle calculations for 3- and 4-circle X-ray and neutron diffractometers"
+See also: https://docs.mantidproject.org/nightly/concepts/Lattice.html

+B = [[b1, b2 * cos(beta3), b3 * cos(beta2)],
+    [0, b2 * sin(beta3), -b3 * sin(beta2) * cos(alpha1)],
+    [0, 0, 1 / a3]]
+return 2pi * B  # equivalent to transpose([a*, b*, c*])
+
basis2latpar(basis_vectors)
Convert UV=[a,b,c] to a,b,c,alpha,beta,gamma
+ a,b,c,alpha,beta,gamma = UV2latpar(UV)

+:param basis_vectors: [3*3] basis vectors array [a[3], b[3], c[3]]
+
basis_1(*lattice_parameters, **kwargs)
Generate direct-space basis-vectors [a, b, c] from lattice parameters
+Basis choice equivalent to that of materials project:
+https://github.com/materialsproject/pymatgen/blob/v2024.10.3/src/pymatgen/core/lattice.py#L39-L1702

+    vector c || z-axis
+    vector a rotated by beta about y-axis from +ve x-axis
+    vector b* || y-axis

+Calculate the lattice positions:

+    [[x, y, z]] = dot([[u, v, w]], [vec_a, vec_b, vec_c])

+:param lattice_parameters: float or list in Angstroms & degrees, see gen_lattice_parameters()
+:param kwargs: lattice parameters
+:returns: [3x3] array, as [vec_a, vec_b, vec_c] in Angstroms
+
basis_2(*lattice_parameters, **kwargs)
Generate direct-space basis-vectors [a, b, c] from lattice parameters
+Basis choice equivalent to that of Vesta:
+https://github.com/materialsproject/pymatgen/blob/v2024.10.3/src/pymatgen/core/lattice.py#L39-L1702

+    vector a || x-axis
+    vector b rotated by gamma about z-axis from +ve y-axis
+    vector c* || z-axis

+Calculate the lattice positions:

+    [[x, y, z]] = dot([[u, v, w]], [vec_a, vec_b, vec_c])

+:param lattice_parameters: float or list in Angstroms & degrees, see gen_lattice_parameters()
+:param kwargs: lattice parameters
+:returns: [3x3] array, as [vec_a, vec_b, vec_c] in Angstroms
+
basis_3(*lattice_parameters, **kwargs)
Generate direct-space basis-vectors [a, b, c] from lattice parameters
+Basis choice equivalent to the inverse of the Bmatrix of W. R. Busing and H. A. Levy, Acta Cryst. (1967)
+https://docs.mantidproject.org/nightly/concepts/Lattice.html

+    vector a* || x-axis
+    vector b rotated by alpha about x-axis from +ve z-axis
+    vector c || z-axis

+Calculate the lattice positions:

+    [[x, y, z]] = dot([[u, v, w]], [vec_a, vec_b, vec_c])

+:param lattice_parameters: float or list in Angstroms & degrees, see gen_lattice_parameters()
+:param kwargs: lattice parameters
+:returns: [3x3] array, as [vec_a, vec_b, vec_c] in Angstroms
+
busingandlevy(*lattice_parameters, **kwargs)
Calculate the Busing and Levy B-matrix from lattice parameters
+    "we choose the x-axis parallel to a*, the y-axis in the plane of a* and b*,
+    and the z-axis perpendicular to that plane"
+From: W. R. Busing and H. A. Levy, Acta Cryst. (1967). 22, 457-464
+    "Angle calculations for 3- and 4-circle X-ray and neutron diffractometers"
+See also: https://docs.mantidproject.org/nightly/concepts/Lattice.html

+Creates a matrix to transform (hkl) into a cartesian basis:
+    (qx,qy,qz)' = B.(h,k,l)'       (where ' indicates a column vector)

+The B matrix is related to the reciprocal basis vectors:
+    (astar, bstar, cstar) = 2 * np.pi * B.T
+Where cstar is defined along the z-axis

+:param lattice_parameters: float or list in Angstroms & degrees, see gen_lattice_parameters()
+:param kwargs: lattice parameters
+:returns: [3x3] array B matrix in inverse-Angstroms (no 2pi)
+
choose_basis(name)
Return a basis function based on a name

+Available options:
+    1. 'MaterialsProject': c || z, b* || y
+    2. 'Vesta': a || x, c* || z
+    3. 'BusingandLevy': c || z, a* || x, 'default'

+:param name: str name of basis
+:return: function
+
dspacing(h, k, l, *lattice_parameters, **kwargs)
Calculate the lattice d-spacing for Bragg reflection (h,k,l)

+    d = lambda / 2 * sin(theta) = 2*pi / |h.a* + k.b* + l.c*|

+:param h, k, l: Miller-indices of reflection
+:param lattice_parameters: float or list in Angstroms & degrees, see gen_lattice_parameters()
+:param kwargs: lattice parameters
+:return: float in Angstroms
+
gen_lattice_parameters(*lattice_parameters, **kwargs)
Generate list of lattice parameters:
+ a,b,c,alpha,beta,gamma = gen_lattice_parameters(*args)
+args:
+  1 -> a=b=c=1,alpha=beta=gamma=90
+  [1,2,3] -> a=1,b=2,c=3,alpha=beta=gamma=90
+  [1,2,3,120] -> a=1,b=2,c=3,alpha=beta=90,gamma=120
+  [1,2,3,10,20,30] -> a=1,b=2,c=3,alpha=10,beta=20,gamma=30
+  1,2,3,10,20,30 -> a=1,b=2,c=3,alpha=10,beta=20,gamma=30
+  a=1,b=2,c=3,alpha=10,beta=20,gamma=30 -> a=1,b=2,c=3,alpha=10,beta=20,gamma=30

+:param lattice_parameters: float or list in Angstroms & degrees
+:param kwargs: lattice parameters
+:return: a,b,c,alpha,beta,gamma
+
index_lattice(coords, basis_vectors)
Index cartesian coordinates on a lattice defined by basis vectors
+Usage (reciprocal space):
+    [[h, k, l], ...] = index_lattice([[qx, qy, qz], ...], [a*, b*, c*])
+Usage (direct space):
+    [u, v, w] = index_lattice([x, y, z], [a, b, c])

+:param coords: [nx3] array of coordinates
+:param basis_vectors: [3*3] array of basis vectors [a[3], b[3], c[3]]
+:return: [nx3] array of vectors in units of reciprocal lattice vectors
+
lattice_volume(*lattice_parameters, **kwargs)
Calculate basis volume from lattice parameters

+    volume = vec_a . (vec_b X vec_c)

+:param lattice_parameters: float or list in Angstroms & degrees, see gen_lattice_parameters()
+:param kwargs: lattice parameters
+:returns: float in Angstroms cubed
+
random_basis(symmetry='triclinic', basis_option='default')
Generate a random basis of unit vectors from a real set of lattice parameters
+:param symmetry: string 'cubic', 'tetragona', 'rhobohedral', 'monoclinic-a/b/c', 'triclinic'
+:param basis_option: str name of basis, 'materialsproject', 'vesta', 'busingandlevy'
+:return: [3x3] array, as [vec_a, vec_b, vec_c] in Angstroms
+
random_lattice(symmetry='triclinic')
Return a random set of real lattice parameters
+:param symmetry: string 'cubic', 'tetragona', 'rhobohedral', 'monoclinic-a/b/c', 'triclinic'
+:return: (a, b, c, alpha, beta, gamma) lattice parameters in Angstroms/ degrees
+
reciprocal_basis(basis_vectors)
Return the reciprocal basis vectors
+    [a*, b*, c*] = 2*pi*inv([a, b, c]).T

+:param basis_vectors: [3*3] basis vectors array [a[3], b[3], c[3]]
+:return: [3*3] array of reciprocal vectors [a*[3], b*[3], c*[3]]
+
reciprocal_lattice_parameters(*lattice_parameters, **kwargs)
Return the reciprocal lattice parameters in inverse-angstroms and degrees
+:param lattice_parameters: float or list in Angstroms & degrees, see gen_lattice_parameters()
+:param kwargs: lattice parameters
+:return: a*, b*, c*, alpha*, beta*, gamma*
+
+ \ No newline at end of file diff --git a/docs/Dans_Diffraction.functions_scattering.html b/docs/Dans_Diffraction.functions_scattering.html index a952ee1..bac0d71 100644 --- a/docs/Dans_Diffraction.functions_scattering.html +++ b/docs/Dans_Diffraction.functions_scattering.html @@ -6,7 +6,7 @@  
Dans_Diffraction.functions_scattering (version 1.0)
 
- 
Dans_Diffraction.functions_scattering (version 0.9)
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\functions_scattering.py

Module: functions_scattering.py
@@ -48,12 +48,13 @@ Diamond
2018
 
-Version 0.9
-Last updated: 13/07/21
+Version 1.0
+Last updated: 06/02/25
 
Version History:
11/11/18 0.1    Version History started.
13/07/21 0.9    Functions re-written and tested
+06/02/25 1.0    Removed refrences to unpolarised magnetic scattering due to incorrect averaging
 
@author: DGPorter

@@ -82,7 +83,7 @@ :param kwargs: named arguments to pass to choosen scattering function
:return: float array [n]

autostructurefactor(scattering_type, q, r, *args, **kwargs)
Choose a scattering type can calcuate the structure factor
-:param scattering_type:
+:param scattering_type: str radiation, see "get_scattering_function()"
:param q: array [n,3] reflection positions in A^-1
:param r: array [m,3] atomic positions in A
:param args: additional arguments to pass to choosen scattering function
@@ -120,6 +121,14 @@ :param q: array [n,3] reflection positions in A^-1
:param r: array [m,3] atomic positions in A
:return: complex array [n,m]
+
scattering_factors(scattering_type, atom_type, qmag, enval, use_sears=False, use_wasskirf=False)
Return an array of scattering factors based on the radiation
+:param scattering_type: str radiation, see "get_scattering_function()"
+:param atom_type: [nx1] str array of element symbols
+:param qmag: [mx1] or None, float array of wavevector magnitudes for reflections
+:param enval: [ox1] or None, float array of energies in keV
+:param use_sears: if True, use neutron scattering lengths from ITC Vol. C, By V. F. Sears
+:param use_wasskirf: if True, use x-ray scattering factors from Waasmaier and Kirfel
+:return: [nxmxo] array of scattering factors
scatteringbasis(q, azi_ref_q=(1, 0, 0), psi=0)
Determine the scattering and polarisation vectors of a reflection based on energy, azimuth and polarisation.
:param q: [1*3] reflection vector in a cartesian basis
:param azi_ref_q: [1,3] direction along which the azimuthal zero angle is determind
@@ -160,7 +169,8 @@ :param debyewaller: array [n,m]: thermal vibration factor of each atom and reflection
:param kwargs: additional options[*unused]
:return: complex array [n]
-
sf_magnetic_neutron(q, r, moment, magnetic_formfactor=None, occ=None, debyewaller=None, **kwargs)
Calculate the magnetic structure factor for the given HKL, using neutron magnetic form factor
+
sf_magnetic_neutron(q, r, moment, magnetic_formfactor=None, occ=None, debyewaller=None, **kwargs)
***Not currently used because of incorrect method of averaging polarisations***
+Calculate the magnetic structure factor for the given HKL, using neutron magnetic form factor
Assumes an unpolarised incident beam.
    Reference: G. L. Squires, Introduction to the Theory of Thermal Neutron Scattering (Cambridge University Press, 1997).
:param q: [n,3] array of reflections in cartesian coordinate system in units of inverse-A
@@ -182,7 +192,8 @@ :param debyewaller: [n,m] array of thermal factors for each atom and reflection, or False to omit
:param kwargs: additional options[*unused]
:return sf: [n] complex array of structure factors
-
sf_magnetic_xray(q, r, moment, magnetic_formfactor=None, occ=None, debyewaller=None, **kwargs)
Calculate the non-resonant magnetic component of the structure factor
+
sf_magnetic_xray(q, r, moment, magnetic_formfactor=None, occ=None, debyewaller=None, **kwargs)
***Not currently used because of incorrect method of averaging polarisations***
+Calculate the non-resonant magnetic component of the structure factor
:param q: [n,3] array of hkl reflections
:param r: [m,3] array of atomic positions in r.l.u.
:param moment: [m,3] array of magnetic moment direction in orthogonal basis
@@ -203,22 +214,11 @@ Book: "X-ray Scattering and Absorption by Magnetic Materials" by Loevesy and Collins. Ch 2. Eqn.2.21+1
No orbital component assumed
magnetic moments assumed to be in the same reference frame as the polarisation
-
sf_magnetic_xray_beamline(q, r, moment, energy_kev, magnetic_formfactor=None, occ=None, debyewaller=None, azi_ref_q=(1, 0, 0), psi=0, polarisation='s-p', **kwargs)
Calculate the non-resonant magnetic component of the structure factor
-:param q: [n,3] array of hkl reflections
-:param r: [m,3] array of atomic positions in r.l.u.
-:param moment: [m,3] array of magnetic moment direction in orthogonal basis
-:param energy_kev: float value of incident x-ray energy in keV
-:param magnetic_formfactor: [n,m] array of magnetic form factors for each atom and relection
-:param occ: [m,1] array of atomic occupancies
-:param debyewaller: [n,m] array of thermal factors for each atom and reflection
-:param azi_ref_q: [1,3] azimuthal refence, in cartesian basis (Q)
-:param psi: [p] array of azimthal angles - the rotation out of the scattering plane.
-:param polarisation: str definition of the polarisation can be: ['ss','sp','ps','pp'] with 's'=sigma, 'p'=pi
-:param kwargs: additional options[*unused]
-:return sf: [n, p] complex array of structure factors for different reflections and azimuths
+
sf_magnetic_xray_beamline(q, r, moment, energy_kev, magnetic_formfactor=None, occ=None, debyewaller=None, azi_ref_q=(1, 0, 0), psi=0, polarisation='s-p', **kwargs)
Calculate the non-resonant magnetic component of the structure factor, using standard beamline polarisation
 
    f_non-res_mag = i.r0.(hw/mc^2).fD.[.5.L.A + S.B]
    B = e_o X e_i + (k_o X e_o) * k_o.e_i - (k_i X e_i) * k_i.e_o - (k_o X e_o) X (k_i X e_i)

- ignore orbital moment L
- fD = magnetic form factor
- S = spin moment
@@ -228,52 +228,54 @@ From Hill+McMorrow Acta Cryst. 1996 A52, 236-244 Equ. (2)
Book: "X-ray Scattering and Absorption by Magnetic Materials" by Loevesy and Collins. Ch 2. Eqn.2.21+1
No orbital component assumed
-magnetic moments assumed to be in the same reference frame as the polarisation
-
sf_magnetic_xray_polarised(q, r, moment, incident_polarisation_vector=(1, 0, 0), magnetic_formfactor=None, occ=None, debyewaller=None, **kwargs)
Calculate the non-resonant magnetic component of the structure factor
+magnetic moments assumed to be in the same reference frame as the polarisation

:param q: [n,3] array of hkl reflections
:param r: [m,3] array of atomic positions in r.l.u.
:param moment: [m,3] array of magnetic moment direction in orthogonal basis
-:param incident_polarisation_vector: [1,3] direction of incident polarisation
+:param energy_kev: float value of incident x-ray energy in keV
:param magnetic_formfactor: [n,m] array of magnetic form factors for each atom and relection
:param occ: [m,1] array of atomic occupancies
:param debyewaller: [n,m] array of thermal factors for each atom and reflection
+:param azi_ref_q: [1,3] azimuthal refence, in cartesian basis (Q)
+:param psi: [p] array of azimthal angles - the rotation out of the scattering plane.
+:param polarisation: str definition of the polarisation can be: ['ss','sp','ps','pp'] with 's'=sigma, 'p'=pi
:param kwargs: additional options[*unused]
-:return sf: [n] complex array of structure factors
+:return sf: [n, p] complex array of structure factors for different reflections and azimuths
+
sf_magnetic_xray_polarised(q, r, moment, incident_polarisation_vector=(1, 0, 0), magnetic_formfactor=None, occ=None, debyewaller=None, **kwargs)
Calculate the non-resonant magnetic component of the structure factor
 
    f_non-res_mag = i.r0.(hw/mc^2).fD.[.5.L.A + S.B]
    B = e_o X e_i + (k_o X e_o) * k_o.e_i - (k_i X e_i) * k_i.e_o - (k_o X e_o) X (k_i X e_i)

- ignore orbital moment L
- fD = magnetic form factor
- S = spin moment
- k_i, k_o = wavevector in, out
- e_i, e_o = polarisation in, out

From Hill+McMorrow Acta Cryst. 1996 A52, 236-244 Equ. (2)
Book: "X-ray Scattering and Absorption by Magnetic Materials" by Loevesy and Collins. Ch 2. Eqn.2.21+1
No orbital component assumed
-magnetic moments assumed to be in the same reference frame as the polarisation
-
sf_magnetic_xray_resonant(q, r, moment, energy_kev, occ=None, debyewaller=None, azi_ref_q=(1, 0, 0), psi=0, polarisation='sp', f0=0, f1=1, f2=0, **kwargs)
Calculate the non-resonant magnetic component of the structure factor
+magnetic moments assumed to be in the same reference frame as the polarisation

:param q: [n,3] array of hkl reflections
:param r: [m,3] array of atomic positions in r.l.u.
:param moment: [m,3] array of magnetic moment direction in orthogonal basis
-:param energy_kev: float value of incident x-ray energy in keV
+:param incident_polarisation_vector: [1,3] direction of incident polarisation
+:param magnetic_formfactor: [n,m] array of magnetic form factors for each atom and relection
:param occ: [m,1] array of atomic occupancies
:param debyewaller: [n,m] array of thermal factors for each atom and reflection
-:param azi_ref_q: [1,3] azimuthal refence, in cartesian basis (Q)
-:param psi: [p] array of azimthal angles - the rotation out of the scattering plane.
-:param polarisation: str definition of the polarisation can be: ['ss','sp','ps','pp'] with 's'=sigma, 'p'=pi
-:param f0: float Flm value 0 (charge)
-:param f1: float Flm value 1
-:param f2: float Flm value 2
:param kwargs: additional options[*unused]
-:return sf: [n, p] complex array of structure factors for different reflections and azimuths
+:return sf: [n] complex array of structure factors
+
sf_magnetic_xray_resonant(q, r, moment, energy_kev, occ=None, debyewaller=None, azi_ref_q=(1, 0, 0), psi=0, polarisation='sp', f0=0, f1=1, f2=0, **kwargs)
Calculate the non-resonant magnetic component of the structure factor
 
f_res_mag = [(e'.e)F0 - i(e'xe).Z*F1 + (e'.Z)*(e.Z)*F2]
 
From Hill+McMorrow Acta Cryst. 1996 A52, 236-244 Equ. (2)
Book: "X-ray Scattering and Absorption by Magnetic Materials" by Loevesy and Collins. Ch 2. Eqn.2.21+1
No orbital component assumed
-magnetic moments assumed to be in the same reference frame as the polarisation
-
sf_magnetic_xray_resonant_alternate(q, r, moment, energy_kev, occ=None, debyewaller=None, polarisation='sp', azi_ref_q=(1, 0, 0), psi=0, f0=0, f1=1, f2=0, **kwargs)
Calculate structure factors using resonant scattering factors in the dipolar approximation
+magnetic moments assumed to be in the same reference frame as the polarisation

:param q: [n,3] array of hkl reflections
:param r: [m,3] array of atomic positions in r.l.u.
:param moment: [m,3] array of magnetic moment direction in orthogonal basis
@@ -287,7 +289,8 @@ :param f1: float Flm value 1
:param f2: float Flm value 2
:param kwargs: additional options[*unused]
-:return sf: [n, p] complex array of structure factors for different reflections and azimuths
+:return sf: [n, p] complex array of structure factors for different reflections and azimuths
+
sf_magnetic_xray_resonant_alternate(q, r, moment, energy_kev, occ=None, debyewaller=None, polarisation='sp', azi_ref_q=(1, 0, 0), psi=0, f0=0, f1=1, f2=0, **kwargs)
Calculate structure factors using resonant scattering factors in the dipolar approximation
 
  I = Scattering.xray_resonant(HKL,energy_kev,polarisation,F0,F1,F2)
Returns an array with the same length as HKL, giving the real intensity at each reflection.
@@ -308,7 +311,22 @@         ( s-s  s-p )
        ( p-s  p-p )
 
-From Hill+McMorrow Acta Cryst. 1996 A52, 236-244 Equ. (15)
+From Hill+McMorrow Acta Cryst. 1996 A52, 236-244 Equ. (15)

+:param q: [n,3] array of hkl reflections
+:param r: [m,3] array of atomic positions in r.l.u.
+:param moment: [m,3] array of magnetic moment direction in orthogonal basis
+:param energy_kev: float value of incident x-ray energy in keV
+:param occ: [m,1] array of atomic occupancies
+:param debyewaller: [n,m] array of thermal factors for each atom and reflection
+:param azi_ref_q: [1,3] azimuthal refence, in cartesian basis (Q)
+:param psi: [p] array of azimthal angles - the rotation out of the scattering plane.
+:param polarisation: str definition of the polarisation can be: ['ss','sp','ps','pp'] with 's'=sigma, 'p'=pi
+:param f0: float Flm value 0 (charge)
+:param f1: float Flm value 1
+:param f2: float Flm value 2
+:param kwargs: additional options[*unused]
+:return sf: [n, p] complex array of structure factors for different reflections and azimuths
sf_xray_dispersion(q, r, scattering_factor, occ=None, debyewaller=None, **kwargs)
Calculate the resonant x-ray structure factor
:param q: [n,3] array of hkl reflections
:param r: [m,3] array of atomic positions in r.l.u.
@@ -362,6 +380,6 @@         DEBUG_MODE = False
MAX_QR_ARRAY = 10000000.0
-SCATTERING_TYPES = {'electron': ['electron', 'ele', 'e'], 'neutron': ['neutron', 'n', 'nuclear'], 'neutron magnetic': ['neutron magnetic', 'magnetic neutron', 'magnetic'], 'xray': ['xray', 'x', 'x-ray', 'thomson', 'charge'], 'xray dispersion': ['dispersion', 'xray dispersion'], 'xray fast': ['xray fast', 'xfast'], 'xray magnetic': ['xray magnetic', 'magnetic xray', 'spin xray', 'xray spin'], 'xray resonant': ['xray resonant', 'resonant', 'resonant xray', 'rxs']}
+SCATTERING_TYPES = {'electron': ['electron', 'ele', 'e'], 'neutron': ['neutron', 'n', 'nuclear'], 'neutron magnetic': ['neutron magnetic', 'magnetic neutron', 'magnetic'], 'neutron polarised': ['neutron polarised', 'neutron polarized'], 'xray': ['xray', 'x', 'x-ray', 'thomson', 'charge'], 'xray dispersion': ['dispersion', 'xray dispersion'], 'xray fast': ['xray fast', 'xfast'], 'xray magnetic': ['xray magnetic', 'magnetic xray', 'spin xray', 'xray spin'], 'xray polarised': ['xray polarised', 'xray polarized'], 'xray resonant': ['xray resonant', 'resonant', 'resonant xray', 'rxs']}
TIME_REPORT = True \ No newline at end of file diff --git a/docs/Dans_Diffraction.html b/docs/Dans_Diffraction.html index a9f29ee..550e314 100644 --- a/docs/Dans_Diffraction.html +++ b/docs/Dans_Diffraction.html @@ -6,7 +6,7 @@  
Dans_Diffraction (version 3.3.3, 2025/02/06)
 
- 
Dans_Diffraction (version 3.2.0, 19/05/24)
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\__init__.py

Dans_Diffraction
@@ -27,7 +27,7 @@     ***In Python/ script***
    import Dans_Diffraction as dif
    f = '/location/of/file.cif'
-    xtl = dif.Crystal(f)
+    xtl = dif.Crystal(f)
    
Usage:
    ***From Terminal***
@@ -39,14 +39,14 @@  
By Dan Porter, PhD
Diamond
-2017
+2017-2025
 
-Version 3.2.0
-Last updated: 19/05/24
+Version 3.3.3
+Last updated: 06/02/2025
 
Version History:
02/03/18 1.0    Version History started.
-30/05/18 1.1    Fdmnes added
+30/05/18 1.1    Fdmnes added
08/06/18 1.2    Python3 now fully supported
23/02/19 1.3    Graphical user intrface and magnetic x-ray scattering now implemented
13/07/19 1.4    FDMNES GUI functionality added
@@ -61,7 +61,7 @@ 10/06/20 1.9.1  Added time symmetry to Symmetry class
16/06/20 1.9.2  Made change in simpulate_powder to remove linspace error
29/06/20 1.9.3  Removed import of scipy.convolve2d due to import errrors, new method slower but more accurate
-02/09/20 1.9.4  Added string methods to Crystal classes
+02/09/20 1.9.4  Added string methods to Crystal classes
26/11/20 1.9.5  Various improvements and corrections
04/01/21 1.9.6  Added Scattering.structure_factor function
26/01/21 1.9.7  Added xray dispersion correction functions, plus x-ray interactions calculations
@@ -73,7 +73,7 @@ 15/11/21 2.1.1  Updated Plot.plot_crystal, added additional orientation functions
07/02/22 2.1.2  Corrected error in classes_scattering.powder() of wrong tth values. Thanks Mirko!
14/03/22 2.2.0  Scatter.powder() updated for new inputs and outputs for pVoight and custom peak shapes. Thanks yevgenyr!
-23/07/22 2.2.1  Fixed error in MultiCrystal.Scatter
+23/07/22 2.2.1  Fixed error in MultiCrystal.Scatter
06/01/23 2.2.2  Removed redundent references to np.float
14/01/23 2.2.3  Corrected background error in xtl.Scatter.powder
08/05/23 2.3.0  Merged pull request for non-integer hkl option on SF and electron form factors. Thanks Prestipino!
@@ -86,6 +86,14 @@ 28/03/24 3.1.4  Fixed error with site symmetries having spaces in AtomsGui, added Properties.relative_positions()
10/05/24 3.1.5  Fixed SyntaxWarnings from Unrecognized escape sequences in Python 3.12, various fixes to scattering
15/05/24 3.2.0  Added "save" and "load" methods to structure factor calculation, improved powder for large calculations
+20/05/24 3.2.1  Added pyproject.toml file for installation, including dansdiffraction script
+29/07/24 3.2.2  Fix for issue #19 in multiple_scattering code, other minor improvements
+04/09/24 3.2.3  Updated method of generating charge states in classes_orbtials.py, Thanks Seonghun!
+25/09/24 3.2.4  Fixed error of missing rotation matrices after load_spacegroup. Thanks asteppke!
+26/09/24 3.3.0  Added complex neutron scattering lengths for isotopes from package periodictable. Thanks thamnos!
+06/11/24 3.3.1  Fixed incorrect cell basis for triclinic cells. Added functions_lattice.py and tests. Thanks LeeRichter!
+20/11/24 3.3.2  Added alternate option for neutron scattering lengths
+06/02/25 3.3.3  Added scattering options for polarised neutron and x-ray scattering. Thanks dragonyanglong!
 
Acknoledgements:
    2018        Thanks to Hepesu for help with Python3 support and ideas about breaking up calculations
@@ -105,8 +113,14 @@     July 2023   Thanks to Yves Joly for helpful suggestions on FDMNES wrapper
    Oct 2023    Thanks to asteppke for pointing out scaling issue in diffractometer gui
    Oct 2023    Thanks to Cyril Cayron for pointing out the error with plotting neutron power spectra
+    Jan 2024    Thanks to Carmelo Prestipino for adding search_distance and plot_distance
    May 2024    Thanks to Innbig for spotting some errors in large liquid crystal powder patterns
    May 2024    Thanks to paul-cares pointing out a silly spelling error in the title!
+    Aug 2024    Thanks to Seonghun for pointing out the error with charge states in Hf
+    Aug 2024    Thanks to MaxPelly for spell checks in examples
+    Sep 2024    Thanks to thamnos for suggestion to add complex neutron scattering lengths
+    Oct 2024    Thanks to Lee Richter for pointing out the error in triclinic basis definition
+    Dec 2024    Thanks to dragonyanglong for pointing out the error with magnetic neutron scattering
 
-----------------------------------------------------------------------------
   Copyright 2024 Diamond Light Source Ltd.
@@ -158,26 +172,523 @@ classes_structures
functions_crystallography
functions_general
+functions_lattice
functions_plotting
functions_scattering
-multiple_scattering
-tensor_scattering
+multiple_scattering
+tensor_scattering
tkgui (package)

+ + + + +
 
+Classes
       
+
builtins.object +
+
+
Dans_Diffraction.classes_crystal.Crystal +
Dans_Diffraction.classes_fdmnes.Fdmnes +
Dans_Diffraction.classes_fdmnes.FdmnesAnalysis +
Dans_Diffraction.classes_multicrystal.MultiCrystal +
Dans_Diffraction.classes_structures.Structures +
+
+
+

+ + + + + + + +
 
+class Crystal(builtins.object)
   Crystal(filename=None)

+Reads the structure information from a cif file and generates the full structure.
+Allows the adjustment of the structure through the lattice parameters, symmetry 
+or atomic displacement.
+Can calculate reflection intensities and two-theta values.

+E.G.
+  xtl = Crystal('Diamond.cif')
+  xtl.Cell.lp() >> give the lattice parameters
+  xtl.Atoms.uvw() >> give the symmetric atomic positions
+  xtl.Symmetry.symmetry_operations >> give symmetry operations
+  xtl.Structure.uvw() >> give the full, unsymmetrised structure
+  xtl.Scatter.hkl([1,0,0],8.00) >> prints the intensity and two-theta of this reflection at this energy
+  xtl.Scatter.print_all_reflections(8.00) >> print all allowed reflections, with intensities, at this energy
+  xtl.write_cif('Diamond2.cif') >> write updated structure to file

+To create your own crystal (BCC example):
+  xtl = Crystal()
+  xtl.new_latt([2.866])
+  xtl.new_atoms(u=[0,0.5],
+                v=[0,0.5],
+                w=[0,0.5],
+                type=['Fe','Fe'])
+  xtl.hkl([[1,0,0],[1,1,0],[1,1,1],[2,0,0]])

+Also, see:
+    help(xtl.Cell)
+    help(xtl.Atoms)
+    help(xtl.Symmetry)
+    help(xtl.Scatter)
 
 Methods defined here:
+
__add__(self, other)
+ +
__init__(self, filename=None)
Initialize self.  See help(type(self)) for accurate signature.
+ +
__repr__(self)
Return repr(self).
+ +
__str__(self)
Return str(self).
+ +
add_parent(self, parent, P)
Add parent structure, returning Crystal as superstructure
+    parent = Crystal(cif_parent)
+    xtl = Crystal(cif_superstructure)
+    su = xtl.add_parent(parent, [[1,1,0],[0,2,0],[0,0,1]])
+ +
generate_lattice(self, U=1, V=1, W=0)
Generate a repeated lattice of the crystal structure
+    latt = xtl.generate_lattice(2,0,0)
+:param U: Repeat of the cell along the a axis
+:param V: Repeat of the cell along the b axis
+:param W: Repeat of the cell along the c axis
+:return: Crystal object
+ +
generate_structure(self)
Combines the atomic positions with symmetry operations, returning the full structure as an Atoms class
+:return: None
+ +
generate_superstructure(self, P)
Generate a superstructure of the current cell
+    a' = n1a + n2b + n3c
+    b' = m1a + m2b + m3c
+    c' = o1a + o2b + o3c
+            OR
+    [a',b',c'] = P[a,b,c]
+            Where
+    P = [[n1,n2,n3],
+         [m1,m2,m3],
+         [o1,o2,o3]]
+Returns a superstructure Crystal class:
+    su = xtl.generate_superstructrue([[2,0,0],[0,2,0],[0,0,1]])

+Superstructure Crystal classes have additional attributes:
+    su.P = P as given
+    su.Parent = the parent Crystal Class

+Use >>hasattr(su,'Parent') to check if the current object is a
+superstructure Crystal class
+ +
info(self)
Returns information about the crystal structure
+:return: str
+ +
invert_structure(self)
Convert handedness of structure, transform from left-handed to right handed, or visa-versa
+Equivlent to xtl.transform([[-1,0,0], [0,-1,0], [0,0,-1]])
+:return: Superstructure Crystal class
+ +
new_atoms(self, u=[0], v=[0], w=[0], type=None, label=None, occupancy=None, uiso=None, mxmymz=None)
Replace current atomic positions with new ones and regenerate structure
+:param u: array : atomic positions u
+:param v: array : atomic positions v
+:param w:  array : atomic positions w
+:param type:  array : atomic types
+:param label: array : atomic labels
+:param occupancy: array : atomic occupation
+:param uiso: array : atomic isotropic thermal parameters
+:param mxmymz: array : atomic magnetic vectors [mu,mv,mw]
+:return: None
+ +
new_cell(self, *lattice_parameters, **kwargs)
Replace the lattice parameters
+:param lattice_parameters: [a,b,c,alpha,beta,gamma]
+:return: None
+ +
search_distances(self, min_d=0.65, max_d=3.2, c_ele=None, elems=None, labels=None, simple=True)
Calculated atoms interatomic distances form each label.
+:param c_ele (list,string): only sites with noted elements
+                            if None all site
+:param elems (list,string): only distances with noted elements
+                            if None all site
+:param min_d: minimum distance 
+:param max_d: maximum distance
+:return dictionary:
+ +
start_gui(self)
Start Crystal GUI
+:return: None
+ +
transform(self, P)
Transform the current cell
+    a' = n1a + n2b + n3c
+    b' = m1a + m2b + m3c
+    c' = o1a + o2b + o3c
+            OR
+    [a',b',c'] = P[a,b,c]
+            Where
+    P = [[n1,n2,n3],
+         [m1,m2,m3],
+         [o1,o2,o3]]
+Returns a superstructure Crystal class:
+    su = xtl.transform([[0,1,0],[1,0,0],[0,0,1]])

+Superstructure Crystal classes have additional attributes:
+    su.P = P as given
+    su.Parent = the parent Crystal Class

+Use >>hasattr(su,'Parent') to check if the current object is a
+superstructure Crystal class
+ +
update_cif(self, cifvals=None)
Update self.cif dict with current values
+:param cifvals: cif dict from readcif (None to use self.cif)
+:return: cifvals
+ +
write_cif(self, filename=None, comments=None)
Write crystal structure to CIF (Crystallographic Information File)
+ Only basic information is saved to the file, but enough to open in VESTA etc.
+ If magnetic ions are defined, a magnetic cif (*.mcif) will be produce
+:param filename: name to write too, if None, use writes to self.name (.cif/.mcif)
+:param comments: str comments to add to file header
+:return: None
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+
+Data and other attributes defined here:
+
cif = {}
+ +
filename = ''
+ +
name = 'Crystal'
+ +
scale = 1.0
+ +

+ + + + + + + +
 
+class Fdmnes(builtins.object)
   Fdmnes(xtl=Crystal with 1 atomic positions, 1 symmetries)

+FDMNES class: Create input files for the FDMNES software and run the program inside a python console

+FDMNES (Finite Difference Method for Near Edge Structure) is an abinitio DFT program for
+simulating x-ray absorption spectra and resonant diffraction.
+FDMNES is developed by Yves Joly at CNRS and can be freely downloaded from here:
+  www.fdmnes.neel.cnrs.fr

+In case of publication, please include the following citation:
+  O. Bunau and Y. Joly "Self-consistent aspects of x-ray absorption calculations"
+  J. Phys.: Condens. Matter 21, 345501 (2009)

+This class creates a simple wrapper to automatically generate input files from Dans_Diffraction
+Crystal structures. The output files from the calculation can also be automatically plotted.

+E.G.
+xtl = Crystal('Co.cif')
+fdm = Fdmnes(xtl)
+fdm.setup(folder_name='New_Calculation',
+          comment='Test',
+          absorber='Co',
+          edge='K'
+          azi_ref=[0,0,1],
+          hkl_reflections=[[1,0,0],[0,1,0],[1,1,0]]
+fdm.create_files()
+fdm.write_fdmfile()
+fdm.run_fdmnes()
+###Wait for program completion###
+analysis = fdm.analyse()
+print(analysis)
+analysis.xanes.plot()
+analysis.density.plot()
+for ref in analysis:
+    ref.plot3D()
 
 Methods defined here:
+
__init__(self, xtl=Crystal with 1 atomic positions, 1 symmetries)
Initialize self.  See help(type(self)) for accurate signature.
+ +
__repr__(self)
Return repr(self).
+ +
__str__(self)
Return str(self).
+ +
analyse(self, folder_name=None)
Analyse the completed calculation
+:param folder_name: str name or directory of calculation (None to use current calculation)
+:return: FdmnesAnalysis Object
+ +
azimuthal_reference(self, hkl=(1, 0, 0))
Generate the azimuthal reference
+:param hkl: (1*3) array [h,k,l]
+:return: None
+ +
create_directory(self)
Create a directory in the FDMNES/Sim folder
+:return: None
+ +
create_files(self, param_string=None)
Create FDMNES calculation directory and files
+ - creates new directory
+ - writes the input file to that directory
+:param param_string: str text to add to indata file (None will generate)
+:return: None
+ +
find_fdmnes_exe(self, initial_dir=None, fdmnes_filename='fdmnes_win64.exe', reset=False)
Find fdmnes executable
+ +
generate_input_path(self)
Returns the input file pathname
+ E.G. 'c:\FDMNES\Sim\Fe2O3\FDMNES_Fe2O3.txt'
+:return: filepath
+ +
generate_output_path(self, folder_name=None, overwrite=False)
Creates an automatic output path in the FDMNES/Sim directory
+ If overwrite is False and the directory already exists, a number will be appended to the name
+:param folder_name: str or None, if None xtl.name will be used
+:param overwrite: True/False
+:return: str directory E.G. 'c:\FDMNES\Sim\Fe2O3'
+ +
generate_parameters_string(self)
Create the string of parameters and comments for the input file
+:return: str
+ +
info(self)
Print setup info
+:return: str
+ +
run_fdmnes(self)
Run the fdmnes code, waits until the program completes
+Remember to use self.create_files and self.write_fdmfile first!
+:return: subprocess.call output
+ +
setup(self, exe_path=None, output_path=None, output_name=None, folder_name=None, input_name=None, comment=None, energy_range=None, radius=None, edge=None, absorber=None, green=None, scf=None, quadrupole=None, azi_ref=None, correct_azi=None, hkl_reflections=None)
Set FDMNES Parameters
+:param exe_path: Location of FDMNES executable, e.g. 'c:\FDMNES\fdmnes_win64.exe'
+:param output_path: Specify the output path
+:param folder_name: Specify output folder name (replaces output_path)
+:param output_name: Name of FDMNES output files
+:param input_name: Name of FDMNES input file
+:param comment: A comment written in the input file
+:param energy_range: str energy range in eV relative to Fermi energy
+:param radius: calculation radius
+:param edge: absorptin edge, 'K', 'L3', 'L2'
+:param absorber: absorbing element, 'Co'
+:param green: Green's function (muffin-tin potential)
+:param scf: True/False, Self consistent solution
+:param quadrupole: False/True, E1E2 terms allowed
+:param azi_ref: azimuthal reference, [1,0,0]
+:param correct_azi: if True, correct azimuthal reference for real cell (use in hexagonal systems)
+:param hkl_reflections: list of hkl reflections [[1,0,0],[0,1,0]]
+:return: None
+ +
write_fdmfile(self, file_list=None)
Create fdmfile with list of calculations
+:param file_list: list of parameter file names for fdmfile, or None to only calculate current parameters
+:return: None
+ +
write_runfile(self, param_string=None)
Write FDMNES input data to a file
+:param param_string: str text to add to indata file (None will generate)
+:return: None
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ + + + + + + +
 
+class FdmnesAnalysis(builtins.object)
   FdmnesAnalysis(output_path, output_name='out', calc_name=None)

+Create fdmnes object from *_scan_conv.txt file

+Usage:
+    fdm = FdmnesAnalysis(output_path, output_name)

+    fdm contains all calculated reflections and xanes spectra, as well as spherical tensors
+    Automated plotting of azimuths, spectra and density of states.

+    fdm.xanes.plot()
+    fdm.density.plot()
+    fdm.I100sp.plot3D()
+    fdm.sph_I100sp.plot()
 
 Methods defined here:
+
__add__(self, other)
+ +
__getitem__(self, item)
Return Reflection
+ +
__init__(self, output_path, output_name='out', calc_name=None)
Loads data from an FDMNES calculation, allowing plotting and data cuts
+ E.G.
+ fdm = FdmnesAnalysis('c:\FDMNES\Fe2O3','out')
+ fdm.xanes.plot()
+ plt.show()

+:param output_path: directory of the calculation to be loaded
+:param output_name: base output name for the calculation (default='out')
+ +
__repr__(self)
Return repr(self).
+ +
__str__(self)
Return str(self).
+ +
info(self)
Returns header of calculation output fipe (*_bav.txt)
+:return: str
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+
+Data and other attributes defined here:
+
angle = array([0])
+ +
energy = array([0])
+ +
refkeys = []
+ +
reflections = {}
+ +
reflist = []
+ +
sphkeys = []
+ +

+ + + + + + + +
 
+class MultiCrystal(builtins.object)
   MultiCrystal(crystal_list)

+Multi_Crystal class for combining multiple phases
 
 Methods defined here:
+
__add__(self, other)
+ +
__get__(self, item)
+ +
__init__(self, crystal_list)
Multi-crystal class
+ +
__repr__(self)
Return repr(self).
+ +
__str__(self)
Return str(self).
+ +
find_close_reflections(self, HKL, energy_kev=None, max_twotheta=2, max_angle=10)
Find reflections close to the given one  and return list
+ +
info(self)
Display information about the contained crystals
+ +
orient_6circle(self, phi=0, chi=0, eta=0, mu=0)
Set rotation matrix using 6-circle diffractometer axes
+ +
orient_set_r(self, rotation)
Set rotation matrix in diffractometer frame
+ +
print_all_reflections(self, energy_kev=None, print_symmetric=False, min_intensity=None, max_intensity=None, units=None)
Prints a list of all allowed reflections at this energy
+    energy_kev = energy in keV
+    print_symmetric = False*/True : omits reflections with the same intensity at the same angle
+    min_intensity = None/ 0.01 : omits reflections less than this (remove extinctions)
+    max_intensity = None/ 0.01 : omits reflections greater than this (show extinctions only)
+    units = None/ 'twotheta'/ 'q'/ 'dspace' : choose scattering angle units to display
+ +
remove(self, index=-1)
Remove crystal [index] from crystal list
+ +
set_labframe(self, lab)
Set transformation matrix between diffractometer and lab
+ +
set_labframe_i16(self)
Set lab transformation matrix for beamline I16 at Diamond Light Source
+ +
set_scale(self, index, scale=1.0)
Set scale of crystal[index]
+ +
setup_scatter(self, **kwargs)
Simple way to set scattering parameters, each parameter is internal to xtl (self)

+scattering_type : self._scattering type               :  'xray','neutron','xray magnetic','neutron magnetic','xray resonant'
+energy_kev  : self._energy_kev                    :  radiation energy in keV
+wavelength_a: self._wavelength_a                  :  radiation wavelength in Angstrom
+powder_units: self._powder_units                  :  units to use when displaying/ plotting ['twotheta', 'd',' 'q']
+min_twotheta: self._scattering_min_two_theta      :  minimum detector (two-theta) angle
+max_twotheta: self._scattering_max_two_theta      :  maximum detector (two-theta) angle
+min_theta   : self._scattering_min_theta          :  minimum sample angle = -opening angle
+max_theta   : self._scattering_max_theta          :  maximum sample angle = opening angle
+theta_offset: self._scattering_theta_offset       :  sample offset angle
+specular    : self._scattering_specular_direction : [h,k,l] : reflections normal to sample surface
+parallel    : self._scattering_parallel_direction : [h,k,l] : reflections normal to sample surface
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ + + + + + + +
 
+class Structures(builtins.object)
   Provides a database of cif files
+    S = Structures() # builds database
+    xtl = S.Diamond.build()
+    
+    Use S.list to see the available structures
+    Use S.cif_files to see filenames of structures

+    Iterating over all structures:
+    for xtl in S:
+        print(xtl)
 
 Methods defined here:
+
__getitem__(self, item)
+ +
__init__(self)
Initialize self.  See help(type(self)) for accurate signature.
+ +
__str__(self)
Return str(self).
+ +
info(self)
"Print Available Structures
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ -
 
Functions
       
activate_fdmnes(initial_dir=None, fdmnes_filename='fdmnes_win64.exe')
Call to activate FDMNES functionality
-:param fdmnes_filename: name of the executable to search for
-:param initial_dir: None or str, if directory, look here for file
-:return: None
-
doc_str()
-
module_info()
-
start_gui(xtl=None)
Start GUI window (requires tkinter)
-
version_info()
+
readcif(filename=None, debug=False)
Open a Crystallographic Information File (*.cif) file and store all entries in a key:value dictionary
+ Looped values are stored as lists under a single key entry
+ All values are stored as strings
+E.G.
+  crys=readcif('somefile.cif')
+  crys['_cell_length_a'] = '2.835(2)'

+crys[key] = value
+available keys are give by crys.keys()

+To debug the file with outputted messages, use:
+  cif = readcif(file, debug=True)

+Some useful standard CIF keywords:
+    _cell_length_a
+    _cell_length_b
+    _cell_length_c
+    _cell_angle_alpha
+    _cell_angle_beta
+    _cell_angle_gamma
+    _space_group_symop_operation_xyz
+    _atom_site_label
+    _atom_site_type_symbol
+    _atom_site_occupancy
+    _atom_site_U_iso_or_equiv
+    _atom_site_fract_x
+    _atom_site_fract_y
+    _atom_site_fract_z

@@ -185,5 +696,5 @@ Data -
       structure_list = <Dans_Diffraction.classes_structures.Structures object>
+__all__ = ['fg', 'fp', 'fl', 'fc', 'Crystal', 'MultiCrystal', 'readcif', 'Structures', 'Fdmnes', 'FdmnesAnalysis'] \ No newline at end of file diff --git a/docs/Dans_Diffraction.multiple_scattering.html b/docs/Dans_Diffraction.multiple_scattering.html index 53d4b3a..f42fc7e 100644 --- a/docs/Dans_Diffraction.multiple_scattering.html +++ b/docs/Dans_Diffraction.multiple_scattering.html @@ -6,7 +6,7 @@  
Dans_Diffraction.multiple_scattering (version 1.2)
 
- 
Dans_Diffraction.multiple_scattering (version 1.0)
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\multiple_scattering.py

Multiple Scattering code, By Dr Gareth Nisbet
@@ -19,8 +19,8 @@     mslist = run_calcms(xtl, [0,0,3], [0,1,0], [1,0], [2.83, 2.85], plot=True)
 
Created from python package "calcms"
-Version 1.0
-12/12/2019
+Version 1.2
+21/11/2024
 -------------------------------------------
 Copyright 2014 Diamond Light Source Ltd.123
 
diff --git a/docs/Dans_Diffraction.tkgui.converter.html b/docs/Dans_Diffraction.tkgui.converter.html new file mode 100644 index 0000000..ca80bfc --- /dev/null +++ b/docs/Dans_Diffraction.tkgui.converter.html @@ -0,0 +1,143 @@ + +Python: module Dans_Diffraction.tkgui.converter + + + + + +
 
+ 
Dans_Diffraction.tkgui.converter
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\tkgui\converter.py
+

Unit converter GUI

+

+ + + + + +
 
+Modules
       
Dans_Diffraction.functions_crystallography
+
Dans_Diffraction.functions_general
+
tkinter
+

+ + + + + +
 
+Classes
       
+
builtins.object +
+
+
UnitConverter +
+
+
+

+ + + + + + + +
 
+class UnitConverter(builtins.object)
   Convert various units
 
 Methods defined here:
+
__init__(self)
"Initialise
+ +
but_hkl_switch(self, event=None)
+ +
but_latt_switch(self, event=None)
+ +
fun_dom_size_unit(self, event=None)
+ +
fun_dspace(self, event=None)
+ +
fun_edge(self)
Edge button
+ +
fun_energy(self, event=None)
+ +
fun_energy_unit(self, event=None)
+ +
fun_fwhm_deg(self, event=None)
+ +
fun_fwhm_dom(self, event=None)
+ +
fun_fwhm_q(self, event=None)
+ +
fun_hkl(self, event=None)
+ +
fun_latt(self)
+ +
fun_mass(self, event=None)
+ +
fun_mass_selection(self, event=None)
+ +
fun_mass_unit(self, event=None)
+ +
fun_qmag(self, event=None)
+ +
fun_setlat(self, event=None)
+ +
fun_tth(self, event=None)
+ +
fun_wavelength(self, event=None)
+ +
fun_wavelength_unit(self, event=None)
+ +
get_dom_size(self)
+ +
get_energy_kev(self)
+ +
get_mass_kg(self)
+ +
get_wavelength_a(self)
+ +
set_energy(self, energy_kev)
+ +
set_mass(self, mass_kg)
+ +
set_wavelength(self, wavelength_a)
+ +
update_hkl(self, qmag)
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ + + + + +
 
+Data
       BF = ['Palatino', 14]
+E_UNITS = {'EHz': 4.135675385428032, 'GHz': 4.135675385428031e-09, 'Hz': 4.1356753854280314e-18, 'eV': 0.001, 'keV': 1.0, 'meV': 1e-06}
+FMT = '%.5g'
+HF = ['Courier', 12]
+LF = ['Palatino', 14]
+MASSES = {'Electron': 9.109e-31, 'Neutron': 1.6749e-27, 'X-Ray': 0}
+M_UNITS = {'MeV': 1.7826582120526108e-30, 'kg': 1.0}
+SF = ['Palatino', 14]
+TF = ['Palatino', 12]
+TTF = ('Helvetica', 10, 'bold italic')
+W_UNITS = {'nm': 10.0, 'Å': 1.0}
+bkg = 'snow'
+btn = 'azure'
+btn2 = 'gold'
+btn_active = 'grey'
+btn_txt = 'black'
+ety = 'white'
+ety_txt = 'black'
+opt = 'azure'
+opt_active = 'grey'
+opt_txt = 'black'
+txtcol = 'black'
+ \ No newline at end of file diff --git a/docs/Dans_Diffraction.tkgui.diffractometer.html b/docs/Dans_Diffraction.tkgui.diffractometer.html new file mode 100644 index 0000000..2053df6 --- /dev/null +++ b/docs/Dans_Diffraction.tkgui.diffractometer.html @@ -0,0 +1,309 @@ + +Python: module Dans_Diffraction.tkgui.diffractometer + + + + + +
 
+ 
Dans_Diffraction.tkgui.diffractometer
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\tkgui\diffractometer.py
+

Dans-Diffraction
+Diffractometer Simulator GUI

+Simulate a generic detector situated around the crystal sample.
+The sample and detector orientation are specified like a 6-axis diffractometer.

+The angle conventions are those according to H. You, J. Appl. Cryst. (1999). 32, 614

+On the top left, the reciprocal lattice is shown and any reflections incident on the detector are highlighted.

+On the top right, the detector image is shown and incident reflections are highlighted.

+On the bottom left, the lattice and detector orientation angles are controlled.

+On the bottom right, the incident beam, intensity calculation options and detector size and shaper are specified.

+Additional options can be found in the top menu. Any axis can be scanned to plot
+the sum of the detector at each step

+ Dr Daniel G Porter, dan.porter@diamond.ac.uk
+ www.diamond.ac.uk
+ Diamond Light Source, Chilton, Didcot, Oxon, OX11 0DE, U.K.

+

+ + + + + +
 
+Modules
       
Dans_Diffraction.functions_crystallography
+Dans_Diffraction.functions_general
+
Dans_Diffraction.functions_plotting
+tkinter.messagebox
+
numpy
+tkinter
+

+ + + + + +
 
+Classes
       
+
builtins.object +
+
+
Detector +
DiffractometerGui +
Lattice +
+
+
+

+ + + + + + + +
 
+class Detector(builtins.object)
   Detector(distance=1.0, normal_dir=(0, -1.0, 0), x_size=1.0, z_size=1.0, pixel_size=0.01, labmatrix=array([[1., 0., 0.],
+       [0., 1., 0.],
+       [0., 0., 1.]]))

+Detector class

+ distance: distance to detector in meters
+ normal_dir: (dx, dy, dz) detector normal
+ x_size: detector width along x-axis in meters
+ z_size: detector height along z-axis in meters

+assumes incident vector (0,1,0)
+rotate delta (about z), gamma (about x)
 
 Methods defined here:
+
__init__(self, distance=1.0, normal_dir=(0, -1.0, 0), x_size=1.0, z_size=1.0, pixel_size=0.01, labmatrix=array([[1., 0., 0.], + [0., 1., 0.], + [0., 0., 1.]]))
Initialize self.  See help(type(self)) for accurate signature.
+ +
__repr__(self)
Return repr(self).
+ +
check_vector_incident(self, vectors)
Check a vector is in the direction of the detector
+ +
corners(self)
Returns coordinates of 4 corners
+ +
detector_image(self, iuvw, intensity, peak_width=0.01, background=0)
Generate detector image
+:param iuvw: [nx3] array of relative positions on detector
+:param intensity: [nx1] array of intensity values
+:param peak_width: float or [nx1], peak FWHM, in m
+:param background: float, background level
+:return: xx, yy, mesh, peak_x[m], peak_y[m]
+ +
generate_detector = default_fun(*args, **kwargs)
+ +
height_lim(self)
+ +
incident_position(self, vectors)
Return position of vector incident on detector
+ +
kfkiq(self, wavelength_a)
Return lines traving kf, ki and Q
+ +
kfkiq_corners(self, wavelength_a)
Return lines to corners of kif, ki and Q
+ +
ki(self, wavelength_a)
+ +
peak_width_mm(self, delta_theta)
Calculate peak width on detector in mm
+:param delta_theta: float or array, peak width in degrees
+:return: FWHM in mm
+ +
q_shape(self, wavelength_a)
Return line in reciprocal space tracing the borders of the detector
+ +
reflection_position(self, qxqyqz, wavelength_a)
Return relative position of reflection on detector
+:param qxqyqz: [nx3] array of reciprocal lattice vectors q = h.a* + k.b* + l.c*
+:param wavelength_a: incident beam wavelength in Angstroms
+:return ixyz: [nx3] array of positions on the detector
+:return uvw: [nx3] array of positions on the detector, relative to detector centre, or NaN if not incident
+:return diff: [nx1] array of wavevector difference in A-1, where 0 is the condition for diffraction.
+ +
relative_position(self, vectors)
Return a position coordinate relative to detector centre
+ +
rotate_to(self, delta=0.0, gamma=0.0)
Rotate detector position
+:param delta: float angle in degrees in vertical direction (about diff-z)
+:param gamma: float angle in degrees in horizontal direction (about diff-x)
+:return: None
+ +
set_callbacks(self, generate_detector=None, update_widgets=None, update_plots=None)
+ +
set_detector(self, distance=1.0, normal_dir=(0, -1.0, 0), x_size=1.0, z_size=1.0, pixel_size=0.01)
+ +
set_labframe(self, labmatrix)
+ +
twotheta(self)
Return detector angle in degrees
+ +
update_plots = default_fun(*args, **kwargs)
+ +
update_widgets = default_fun(*args, **kwargs)
+ +
width_lim(self)
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+
+Data and other attributes defined here:
+
normal_dir = array([ 0., -1., 0.])
+ +
position = array([0., 0., 0.])
+ +
x_axis = array([1., 0., 0.])
+ +
z_axis = array([0., 0., 1.])
+ +

+ + + + + + + +
 
+class DiffractometerGui(builtins.object)
   DiffractometerGui(xtl: Dans_Diffraction.classes_crystal.Crystal)

+View and edit the symmetry operations
 
 Methods defined here:
+
__init__(self, xtl: Dans_Diffraction.classes_crystal.Crystal)
"Initialise
+ +
fun_i16(self)
"Add I16 parameters
+ +
fun_supernova(self)
Add SuperNova parameters
+ +
fun_wish(self)
"Add Wish parameters
+ +
menu_new(self)
Create a new instance
+ +
menu_options(self)
Set plot options
+ +
menu_orientation(self)
Set lattice orientation
+ +
update(self, event=None)
Update plot
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ + + + + + + +
 
+class Lattice(builtins.object)
   Lattice(crystal: Dans_Diffraction.classes_crystal.Crystal)

+Reciprocal Lattice
 
 Methods defined here:
+
__init__(self, crystal: Dans_Diffraction.classes_crystal.Crystal)
Initialize self.  See help(type(self)) for accurate signature.
+ +
generate_hkl(self, wavelength_a, max_q=4)
Generate reflection list
+ +
generate_intensities(self, calculate_index=())
Generate list of structure factors
+ +
generate_refs = default_fun(*args, **kwargs)
+ +
get_wavelength = default_fun(*args, **kwargs)
+ +
latt_str(self)
Generate list of reflections
+ +
rotate_to(self, phi=0.0, chi=0.0, eta=0.0, mu=0.0)
+ +
set_callbacks(self, generate_refs=None, update_widgets=None, update_plots=None, get_wavelength=None)
+ +
set_orientation(self, umatrix=None, labmatrix=None)
+ +
update_plots = default_fun(*args, **kwargs)
+ +
update_widgets = default_fun(*args, **kwargs)
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ + + + + +
 
+Functions
       
default_fun(*args, **kwargs)
+
generate_reflections(latt: Dans_Diffraction.tkgui.diffractometer.Lattice, det: Dans_Diffraction.tkgui.diffractometer.Detector, minimum_gaussian_intensity=0.01)
Calulate reflections on detector
+
reflist_str()
Generate string from REFLIST
+
tk_angle_element(name, parent, callback, help_message='', val_range=(-180, 180), initial=0)
Slider element
+
tk_beam(parent, xtl, callback)
radiation tkinter widgets, returns Latt
+
tk_detector(parent, callback)
Create detector options widget
+
tk_help()
Display help
+
tk_hkl(parent, latt: Dans_Diffraction.tkgui.diffractometer.Lattice, tth_axis: tkinter.DoubleVar, th_axis: tkinter.DoubleVar, callback)
reflection frame
+
tk_orientation(parent, latt: Dans_Diffraction.tkgui.diffractometer.Lattice, det: Dans_Diffraction.tkgui.diffractometer.Detector, callback)
Orientation options window
+
tk_plot_options(parent, callback)
Plot options window
+
tk_scan(parent, angle_dict, latt, det)
+
update_3d(array, line_obj)
Update 3D line object
+

+ + + + + +
 
+Data
       BF = ['Palatino', 14]
+DEFAULT_DET_DISTANCE = 1000
+DEFAULT_DET_HEIGHT = 200
+DEFAULT_DET_PIXEL = 0.2
+DEFAULT_DET_WIDTH = 200
+DEFAULT_ENERGY = 8
+DEFAULT_MAXQ = 4
+DEFAULT_PEAKWIDTH = 0.2
+DEFAULT_RESOLUTION = 200
+FIGURE_3D_SIZE = [8, 4]
+FIGURE_DET_SIZE = [7, 4]
+FIGURE_DPI = 80
+HF = ['Courier', 12]
+LF = ['Palatino', 14]
+MSG_CHI = "2nd rotation, right handed rotation about y''-axis."
+MSG_DEL = 'Detector rotation, left handed rotation about diffractometer z-axis'
+MSG_ETA = "3rd rotation, left handed rotation about z'-axis"
+MSG_GAM = 'Detector rotation, right handed rotation about diffractometer x-axis'
+MSG_MU = '4th rotation, right handed rotation about diffractometer x-axis'
+MSG_PHI = "1st rotation, left handed roation about z'''-axis (crystal axis)"
+OPTIONS = {'3d_basis': False, '3d_detector_corners': False, '3d_lattice': True, '3d_ref_arrows': False, 'det_clim': [0.0, 1.0], 'det_cmap': 'viridis', 'det_labels': True, 'det_log': False, 'fig_dpi': 80, 'maxq': 4.0, ...}
+REFLIST = {'color': [], 'detx': array([], dtype=float64), 'dety': array([], dtype=float64), 'fwhm': array([], dtype=float64), 'hkl': array([], shape=(0, 3), dtype=int32), 'hkl_str': [], 'intensity': array([], dtype=float64), 'qxqyqz': array([], shape=(0, 3), dtype=float64), 'scaled': array([], dtype=float64)}
+SF = ['Palatino', 14]
+TABLEAU_COLORS = {'tab:blue': '#1f77b4', 'tab:brown': '#8c564b', 'tab:cyan': '#17becf', 'tab:gray': '#7f7f7f', 'tab:green': '#2ca02c', 'tab:olive': '#bcbd22', 'tab:orange': '#ff7f0e', 'tab:pink': '#e377c2', 'tab:purple': '#9467bd', 'tab:red': '#d62728'}
+TF = ['Palatino', 12]
+TTF = ('Helvetica', 10, 'bold italic')
+bkg = 'snow'
+btn = 'azure'
+btn2 = 'gold'
+btn_active = 'grey'
+btn_txt = 'black'
+col_cycle = <itertools.cycle object>
+ety = 'white'
+ety_txt = 'black'
+opt = 'azure'
+opt_active = 'grey'
+opt_txt = 'black'
+txtcol = 'black'
+ \ No newline at end of file diff --git a/docs/Dans_Diffraction.tkgui.spacegroups.html b/docs/Dans_Diffraction.tkgui.spacegroups.html new file mode 100644 index 0000000..eac39b0 --- /dev/null +++ b/docs/Dans_Diffraction.tkgui.spacegroups.html @@ -0,0 +1,116 @@ + +Python: module Dans_Diffraction.tkgui.spacegroups + + + + + +
 
+ 
Dans_Diffraction.tkgui.spacegroups
index
c:\users\grp66007\onedrive - diamond light source ltd\pythonprojects\dans_diffraction\dans_diffraction\tkgui\spacegroups.py
+

Sacegroup Viewer GUI

+

+ + + + + +
 
+Modules
       
Dans_Diffraction.functions_crystallography
+Dans_Diffraction.functions_general
+
Dans_Diffraction.functions_plotting
+tkinter.messagebox
+
numpy
+matplotlib.pyplot
+
tkinter
+

+ + + + + +
 
+Classes
       
+
builtins.object +
+
+
SpaceGroupGui +
+
+
+

+ + + + + + + +
 
+class SpaceGroupGui(builtins.object)
   SpaceGroupGui(symmetry=None, xtl=None)

+View and edit the symmetry operations
 
 Methods defined here:
+
__init__(self, symmetry=None, xtl=None)
"Initialise
+ +
fun_ch_maggroup(self)
Button Select Magnetic Spacegroup
+ +
fun_ch_spacegroup(self)
Button Select Spacegroup
+ +
fun_ch_subgroup(self)
Button select subgroup
+ +
fun_mousewheel(self, event)
Move scollbar
+ +
fun_move(self, *args)
Move within text frame
+ +
fun_scroll(self, *args)
Move scrollbar
+ +
fun_set(self)
Generate the text box
+ +
fun_spacegroup(self, event=None)
Load spacegroup symmetry
+ +
fun_spacegroup_symbol(self, event=None)
Load spacegroup symmetry
+ +
fun_symhkl(self, event=None)
create symmetric hkl reflections
+ +
fun_symuvw(self, event=None)
create symmetric uvw position
+ +
fun_update(self)
Update button
+ +
fun_wyckoff(self)
Button display Wyckoff sites
+ +
update(self)
Update crystal
+ +
+Data descriptors defined here:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ + + + + +
 
+Data
       BF = ['Palatino', 14]
+HF = ['Courier', 12]
+LF = ['Palatino', 14]
+SF = ['Palatino', 14]
+TF = ['Palatino', 12]
+TTF = ('Helvetica', 10, 'bold italic')
+bkg = 'snow'
+btn = 'azure'
+btn2 = 'gold'
+btn_active = 'grey'
+btn_txt = 'black'
+ety = 'white'
+ety_txt = 'black'
+opt = 'azure'
+opt_active = 'grey'
+opt_txt = 'black'
+txtcol = 'black'
+ \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 247a7a5..2eac110 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,8 @@ dansdiffraction = "Dans_Diffraction:start_gui" [project.gui-scripts] dansdiffraction = "Dans_Diffraction:start_gui" +ddproperties = "Dans_Diffraction:start_properties_gui" +ddfdmnes = "Dans_Diffraction:start_fdmnes_gui" [tool.setuptools.dynamic] version = {attr = "Dans_Diffraction.__version__"} \ No newline at end of file