Skip to content

Commit 1f58f80

Browse files
authored
Merge pull request #31 from DanPorter/supercell_fixes
Supercell scale fix
2 parents 4d3565e + b24d74e commit 1f58f80

File tree

5 files changed

+40
-31
lines changed

5 files changed

+40
-31
lines changed

Dans_Diffraction/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
Diamond
3232
2017-2025
3333
34-
Version 3.3.3
35-
Last updated: 06/02/2025
34+
Version 3.3.4
35+
Last updated: 12/04/2025
3636
3737
Version History:
3838
02/03/18 1.0 Version History started.
@@ -84,6 +84,7 @@
8484
06/11/24 3.3.1 Fixed incorrect cell basis for triclinic cells. Added functions_lattice.py and tests. Thanks LeeRichter!
8585
20/11/24 3.3.2 Added alternate option for neutron scattering lengths
8686
06/02/25 3.3.3 Added scattering options for polarised neutron and x-ray scattering. Thanks dragonyanglong!
87+
12/04/25 3.3.4 Improved superstructure calculations by fixing scale parameter
8788
8889
Acknoledgements:
8990
2018 Thanks to Hepesu for help with Python3 support and ideas about breaking up calculations
@@ -113,7 +114,7 @@
113114
Dec 2024 Thanks to dragonyanglong for pointing out the error with magnetic neutron scattering
114115
115116
-----------------------------------------------------------------------------
116-
Copyright 2024 Diamond Light Source Ltd.
117+
Copyright 2018-2025 Diamond Light Source Ltd.
117118
118119
Licensed under the Apache License, Version 2.0 (the "License");
119120
you may not use this file except in compliance with the License.

Dans_Diffraction/classes_crystal.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
Diamond
2525
2017
2626
27-
Version 3.3.0
28-
Last updated: 06/02/25
27+
Version 3.3.1
28+
Last updated: 06/04/25
2929
3030
Version History:
3131
27/07/17 1.0 Version History started.
@@ -49,7 +49,8 @@
4949
15/11/21 3.2.2 Added Cell.orientation, updated Cell.UV()
5050
12/01/21 3.2.3 Added Symmetry.axial_vector
5151
22/05/23 3.2.4 Added Symmetry.wyckoff_label(), Symmetry.spacegroup_dict
52-
06/05/25 3.3.0 Symmetry.from_cif now loads operations from find_spacegroup if not already loaded
52+
06/05/24 3.3.0 Symmetry.from_cif now loads operations from find_spacegroup if not already loaded
53+
06/04/25 3.3.1 scale parameter of superlattice improved
5354
5455
@author: DGPorter
5556
"""
@@ -68,7 +69,7 @@
6869
from .classes_multicrystal import MultiCrystal
6970
from .classes_plotting import Plotting, PlottingSuperstructure
7071

71-
__version__ = '3.3.0'
72+
__version__ = '3.3.1'
7273

7374

7475
class Crystal:
@@ -2386,7 +2387,8 @@ def __init__(self, Parent, P):
23862387
self.Parent = Parent
23872388
newUV = Parent.Cell.calculateR(P)
23882389
self.new_cell(fl.basis2latpar(newUV))
2389-
self.scale = Parent.scale * np.prod(self.P)
2390+
parent_cells_in_supercell = fc.calc_vol(P)
2391+
self.scale = Parent.scale * parent_cells_in_supercell
23902392

23912393
# Add exta functions
23922394
self.Plot = PlottingSuperstructure(self)

Dans_Diffraction/classes_plotting.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,12 +1500,12 @@ def parent_generate_intensity_cut(self, x_axis=(1, 0, 0), y_axis=(0, 1, 0), cent
15001500
c_cart = self.xtl.Parent.Cell.calculateQ(centre)
15011501

15021502
# Generate lattice of reciprocal space points
1503-
maxq = np.sqrt(q_max**2 + q_max**2 + np.sum(c_cart**2)) # generate all reflections
1504-
print('Max Q distance: %4.2f A-1'%maxq)
1503+
maxq = np.sqrt(q_max**2 + q_max**2 + np.sum(c_cart**2)) # generate all reflections
1504+
print('Max Q distance: %4.2f A-1' % maxq)
15051505
hmax, kmax, lmax = fc.maxHKL(maxq, self.xtl.Cell.UVstar())
15061506
HKL = fc.genHKL([hmax, -hmax], [kmax, -kmax], [lmax, -lmax])
1507-
HKL = HKL #+ centre # reflection about central reflection
1508-
print('Number of reflections in sphere: %1.0f'%len(HKL))
1507+
HKL = HKL # + centre # reflection about central reflection
1508+
print('Number of reflections in sphere: %1.0f' % len(HKL))
15091509

15101510
# Determine the directions in cartesian space
15111511
x_cart = self.xtl.calculateQ_parent(x_axis)
@@ -1535,10 +1535,12 @@ def parent_generate_intensity_cut(self, x_axis=(1, 0, 0), y_axis=(0, 1, 0), cent
15351535
pHKL = self.xtl.superhkl2parent(HKLinbox)
15361536
pHKL, inten = self.xtl.Parent.Symmetry.symmetric_intensity(pHKL, inten)
15371537
HKL = self.xtl.parenthkl2super(pHKL)
1538+
print('Adding parent symmetry domains, adding %d reflections' % (len(HKL) - len(pHKL)))
15381539
else:
15391540
HKL = HKLinbox
15401541
q = self.xtl.calculateQ_parent(HKL)
15411542

1543+
# remove reflections not in plot
15421544
box_coord = fg.index_coordinates(q - c_cart, CELL)
15431545
incell = np.all(np.abs(box_coord) <= 0.5, axis=1)
15441546
plane_coord = 2 * q_max * box_coord[incell, :]
@@ -1661,21 +1663,26 @@ def simulate_intensity_cut(self, x_axis=(1, 0, 0), y_axis=(0, 1, 0), centre=(0,
16611663
mesh_vec_b = fg.index_coordinates(Q_vec_b, CELL) * 2 * q_max
16621664

16631665
# Vector arrows and lattice point labels
1664-
cen_lab = '(%1.3g,%1.3g,%1.3g)' % (centre[0], centre[1], centre[2])
1665-
vec_a_lab = '(%1.3g,%1.3g,%1.3g)' % (vec_a[0] + centre[0], vec_a[1] + centre[1], vec_a[2] + centre[2])
1666-
vec_b_lab = '(%1.3g,%1.3g,%1.3g)' % (vec_b[0] + centre[0], vec_b[1] + centre[1], vec_b[2] + centre[2])
1666+
supx, supy, supz = 0.0 + np.around(self.xtl.parenthkl2super(centre)[0], 3)
1667+
svax, svay, svaz = 0.0 + np.around(self.xtl.parenthkl2super(vec_a + centre)[0], 3)
1668+
svbx, svby, svbz = 0.0 + np.around(self.xtl.parenthkl2super(vec_b + centre)[0], 3)
1669+
cen_lab = '(%1.3g,%1.3g,%1.3g)$_{p}$' % (centre[0], centre[1], centre[2])
1670+
# cen_lab += '\n(%1.3g,%1.3g,%1.3g)$_{s}$' % (supx, supy, supz)
1671+
vec_a_lab = '(%1.3g,%1.3g,%1.3g)$_{p}$' % (vec_a[0] + centre[0], vec_a[1] + centre[1], vec_a[2] + centre[2])
1672+
vec_a_lab += '\n(%1.3g,%1.3g,%1.3g)$_{s}$' % (svax, svay, svaz)
1673+
vec_b_lab = '(%1.3g,%1.3g,%1.3g)$_{p}$' % (vec_b[0] + centre[0], vec_b[1] + centre[1], vec_b[2] + centre[2])
1674+
vec_b_lab += '\n(%1.3g,%1.3g,%1.3g)$_{s}$' % (svbx, svby, svbz)
16671675

16681676
lattQ = fp.axis_lattice_points(mesh_vec_a, mesh_vec_b, plt.axis())
16691677
fp.plot_lattice_lines(lattQ, mesh_vec_a, mesh_vec_b, lw=0.5, c='grey')
1670-
fp.plot_vector_arrows(mesh_vec_a, mesh_vec_b, vec_a_lab, vec_b_lab)
1678+
fp.plot_vector_arrows(mesh_vec_a, mesh_vec_b, vec_a_lab, vec_b_lab, color='k')
16711679
plt.text(0 - (0.2 * q_max), 0 - (0.1 * q_max), cen_lab, fontname=fp.DEFAULT_FONT, weight='bold', size=18)
16721680

16731681
# Plot labels
16741682
xlab = r'Q || (%1.3g,%1.3g,%1.3g) [$\AA^{-1}$]' % (x_axis[0], x_axis[1], x_axis[2])
16751683
ylab = r'Q || (%1.3g,%1.3g,%1.3g) [$\AA^{-1}$]' % (y_axis[0], y_axis[1], y_axis[2])
1676-
supercentre = self.xtl.parenthkl2super(centre)[0]
16771684
ttl = '%s\n(%1.3g,%1.3g,%1.3g)$_{p}$ = (%1.3g,%1.3g,%1.3g)$_{s}$' \
1678-
% (self.xtl.name, centre[0], centre[1], centre[2], supercentre[0], supercentre[1], supercentre[2])
1685+
% (self.xtl.name, centre[0], centre[1], centre[2], supx, supy, supz)
16791686
fp.labels(ttl, xlab, ylab)
16801687

16811688

Dans_Diffraction/functions_crystallography.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
PENGFILE = os.path.join(datadir, 'peng.dat')
7373
NSLFILE = os.path.join(datadir, 'neutron_isotope_scattering_lengths.dat')
7474
NSLFILE_SEARS = os.path.join(datadir, 'neutron_isotope_scattering_lengths_sears.dat')
75+
ASFFILE = os.path.join(datadir, 'atomic_scattering_factors.npy')
7576

7677
# List of Elements in order sorted by length of name
7778
ELEMENT_LIST = [
@@ -1236,8 +1237,7 @@ def atomic_scattering_factor(element, energy_kev=None):
12361237
:param energy_kev: float or list energy in keV (None to return original, uninterpolated list)
12371238
:return: f1, f2, shape dependent on shapes of element and energy_kev: float, or [ene] or [ele, ene]
12381239
"""
1239-
asf_file = os.path.join(datadir, 'atomic_scattering_factors.npy')
1240-
asf = np.load(asf_file, allow_pickle=True)
1240+
asf = np.load(ASFFILE, allow_pickle=True)
12411241
asf = asf.item()
12421242

12431243
element = np.asarray(element, dtype=str).reshape(-1)
@@ -1295,8 +1295,7 @@ def xray_dispersion_corrections(elements, energy_kev=None):
12951295
:param energy_kev: float or list energy in keV (None to return original, uninterpolated list)
12961296
:return: f', f" with shape (len(energy), len(elements))
12971297
"""
1298-
asf_file = os.path.join(datadir, 'atomic_scattering_factors.npy')
1299-
asf = np.load(asf_file, allow_pickle=True)
1298+
asf = np.load(ASFFILE, allow_pickle=True)
13001299
asf = asf.item()
13011300

13021301
energy_kev = np.asarray(energy_kev, dtype=float).reshape(-1)
@@ -3446,7 +3445,7 @@ def group_intensities(q_values, intensity, min_overlap=0.01):
34463445
def calc_vol(UV):
34473446
"""Calculate volume in Angstrom^3 from unit vectors"""
34483447
a, b, c = UV
3449-
return np.dot(a, np.cross(b, c))
3448+
return np.abs(np.dot(a, np.cross(b, c)))
34503449

34513450

34523451
def cif2table(cif):

Examples/example_supercell.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
Build a supercell from multiple unit cells and simulate the diffraction pattern
44
"""
55

6-
import sys,os
6+
import sys, os
77
import numpy as np
8-
import matplotlib.pyplot as plt # Plotting
8+
import matplotlib.pyplot as plt # Plotting
99
cf = os.path.dirname(__file__)
10-
sys.path.insert(0,os.path.join(cf,'..'))
10+
sys.path.insert(0, os.path.join(cf, '..'))
1111
import Dans_Diffraction as dif
1212

1313

@@ -17,14 +17,14 @@
1717

1818
#P = [[2,-1,0],[1,3,0],[0,0,1]] # 1/7th Supercell
1919
#P = [[-1,3,0],[4,3,0],[0,0,1]] # Square Supercell
20-
P = [[3,0,0],[4,5,0],[0,0,1]] # Stripe Supercell
20+
P = [[3, 0, 0], [4, 5, 0], [0, 0, 1]] # Stripe Supercell
2121
#P = [[1,3,0],[3,-1,0],[0,0,1]]
2222
#P = [[2,0,0],[0,2,0],[0,0,1]] # Double supercell
2323
#sup = xtl.generate_superstructure(P)
2424

2525
# Set discrete occupancies for average structure
26-
xtl.Atoms.occupancy[2]=0
27-
xtl.Atoms.occupancy[3]=1
26+
xtl.Atoms.occupancy[2] = 0
27+
xtl.Atoms.occupancy[3] = 1
2828
xtl.generate_structure()
2929

3030
# Generate the superstructure, repeating the parent/average structure to fill the supercell
@@ -34,8 +34,8 @@
3434
# Stripe Cell
3535
# Na1 6,7 16,17 26,27 36,37 46,47 56,57 66,67 76,77 86,87 96,97 106,107 116,117 126,127 136,137 146,147
3636
# Na2 8,9 18,19 28,29 38,39 48,49 58,59 68,69 78,79 88,89 98,99 108,109 118,119 128,129 138,139 148,149
37-
sup.Structure.occupancy[[6 ,16,26,77,87,107]] = 1 # Na1
38-
sup.Structure.occupancy[[8 ,18,38,28,48,58, 139, 119, 149, 109, 89,79]] = 0 # Na2
37+
sup.Structure.occupancy[[6, 16, 26, 77, 87, 107]] = 1 # Na1
38+
sup.Structure.occupancy[[8, 18, 38, 28, 48, 58, 139, 119, 149, 109, 89, 79]] = 0 # Na2
3939

4040
# Plot the Na layers showing the ordering
4141
sup.Plot.plot_layers(layers=[0.25, 0.75], layer_width=0.01, show_labels=True)

0 commit comments

Comments
 (0)