Skip to content

Commit b59e945

Browse files
committed
Fixes for #33
functions_scattering.py - changed method of structure factor calculation in 'magnetic neutron' and 'magnetic xray' to give unpolarised structure factor functions_crystallography.py - Changed input of magnetic_form_factor to *elements. - add new magnetic form factor functions: - magnetic_ff_symbol - magnetic_ff_coefs - print_magnetic_ff_coefs - last_df_orbital - magnetic_ff_g_factor - magnetic_ff_j2j0_ratio classes_crystal.py - Add method scattering_factor_coefficients to Atoms. classes_properties.py - Add scattering factors method to Properties classes_scattering.py - add atom scattering factor methods - add use_waaskirf and use_sears to setup_scatter test_data_tables.py - added test cases for magnetic form factors test_structure_factors.py - added test cases for magnetic scattering All tests pass.
1 parent 843cab1 commit b59e945

12 files changed

+469
-127
lines changed

Dans_Diffraction/classes_crystal.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,10 @@ def mass_fraction(self):
15881588

15891589
return weights / total_weight
15901590

1591+
def scattering_factor_coefficients(self, table='itc'):
1592+
"""Return scattering factor coefficients for the elements"""
1593+
return fc.scattering_factor_coefficients(*self.type, table=table)
1594+
15911595
def info(self, idx=None, type=None):
15921596
"""
15931597
Prints properties of all atoms

Dans_Diffraction/classes_properties.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
from . import functions_general as fg
3333
from . import functions_crystallography as fc
34+
from . import functions_scattering as fs
3435
from .classes_orbitals import CrystalOrbitals
3536

3637
__version__ = '2.0'
@@ -119,7 +120,30 @@ def magnetic_form_factor(self, hkl):
119120
:return: [nxm] array of scattering factors for each atom and reflection
120121
"""
121122
qmag = self.xtl.Cell.Qmag(hkl)
122-
return fc.magnetic_form_factor(self.xtl.Structure.type, qmag)
123+
return fc.magnetic_form_factor(*self.xtl.Structure.type, qmag=qmag)
124+
125+
def scattering_factors(self, scattering_type, hkl, energy_kev=None,
126+
use_sears=False, use_wasskirf=False):
127+
"""
128+
Return an array of scattering factors based on the radiation
129+
:param scattering_type: str radiation, see "get_scattering_function()"
130+
:param hkl: [mx1] or None, float array of wavevector magnitudes for reflections
131+
:param energy_kev: [ox1] or None, float array of energies in keV
132+
:param use_sears: if True, use neutron scattering lengths from ITC Vol. C, By V. F. Sears
133+
:param use_wasskirf: if True, use x-ray scattering factors from Waasmaier and Kirfel
134+
:return: [nxmxo] array of scattering factors
135+
"""
136+
qmag = self.xtl.Cell.Qmag(hkl)
137+
# Scattering factors
138+
ff = fs.scattering_factors(
139+
scattering_type=scattering_type,
140+
atom_type=self.xtl.Structure.type,
141+
qmag=qmag,
142+
enval=energy_kev,
143+
use_sears=use_sears,
144+
use_wasskirf=use_wasskirf,
145+
)
146+
return np.squeeze(ff)
123147

124148
def xray_edges(self):
125149
"""

Dans_Diffraction/classes_scattering.py

Lines changed: 106 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ def __str__(self):
183183
return out
184184

185185
def setup_scatter(self, scattering_type=None, energy_kev=None, energy_mev=None, wavelength_a=None,
186+
use_sears=None, use_waaskirf=None,
186187
powder_units=None, powder_pixels=None, powder_lorentz=None, powder_overlap=None,
187188
int_hkl=None, specular=None, parallel=None, theta_offset=None,
188189
min_theta=None, max_theta=None, min_twotheta=None, max_twotheta=None,
@@ -233,6 +234,12 @@ def setup_scatter(self, scattering_type=None, energy_kev=None, energy_mev=None,
233234
else:
234235
self._energy_kev = fc.wave2energy(wavelength_a)
235236

237+
if use_sears is not None:
238+
self._use_sears_scattering_lengths = use_sears
239+
240+
if use_waaskirf is not None:
241+
self._use_waaskirf_scattering_factor = use_waaskirf
242+
236243
if powder_units is not None:
237244
self._powder_units = powder_units
238245

@@ -514,7 +521,7 @@ def structure_factor(self, hkl=None, scattering_type=None, int_hkl=None, **kwarg
514521

515522
# Get magnetic form factors
516523
if self._use_magnetic_form_factor:
517-
mf = fc.magnetic_form_factor(atom_type, qmag)
524+
mf = fc.magnetic_form_factor(*atom_type, qmag=qmag)
518525
else:
519526
mf = None
520527

@@ -1069,7 +1076,7 @@ def magnetic_neutron(self, HKL):
10691076

10701077
# Get magnetic form factors
10711078
if self._use_magnetic_form_factor:
1072-
ff = fc.magnetic_form_factor(atom_type, Qmag)
1079+
ff = fc.magnetic_form_factor(*atom_type, qmag=Qmag)
10731080
else:
10741081
ff = np.ones([len(HKL), Nat])
10751082

@@ -1135,7 +1142,7 @@ def xray_magnetic(self, HKL):
11351142

11361143
# Get magnetic form factors
11371144
if self._use_magnetic_form_factor:
1138-
ff = fc.magnetic_form_factor(atom_type, Qmag)
1145+
ff = fc.magnetic_form_factor(*atom_type, qmag=Qmag)
11391146
else:
11401147
ff = np.ones([len(HKL), Nat])
11411148

@@ -1359,7 +1366,7 @@ def xray_nonresonant_magnetic(self, HKL, energy_kev=None, azim_zero=(1, 0, 0), p
13591366

13601367
# Get magnetic form factors
13611368
if self._use_magnetic_form_factor:
1362-
ff = fc.magnetic_form_factor(atom_type, Qmag)
1369+
ff = fc.magnetic_form_factor(*atom_type, qmag=Qmag)
13631370
else:
13641371
ff = np.ones([len(HKL), len(uvw)])
13651372

@@ -1628,6 +1635,24 @@ def scatteringbasis(self, hkl, azim_zero=(1, 0, 0), psi=0):
16281635
Jhat_psi = fg.norm(np.cross(Qhat, Ihat_psi))
16291636
return np.vstack([Ihat_psi, Jhat_psi, Qhat])
16301637

1638+
def scattering_factors(self, hkl, energy_kev=None):
1639+
"""Return the scattering factors[n, m] for each reflection, hkl[n,3] and each atom [m]"""
1640+
1641+
if energy_kev is None:
1642+
energy_kev = self._energy_kev
1643+
1644+
qmag = self.xtl.Cell.Qmag(hkl)
1645+
# Scattering factors
1646+
ff = fs.scattering_factors(
1647+
scattering_type=self._scattering_type,
1648+
atom_type=self.xtl.Structure.type,
1649+
qmag=qmag,
1650+
enval=energy_kev,
1651+
use_sears=self._use_sears_scattering_lengths,
1652+
use_wasskirf=self._use_waaskirf_scattering_factor,
1653+
)
1654+
return ff
1655+
16311656
def print_scattering_coordinates(self, hkl, azim_zero=(1, 0, 0), psi=0):
16321657
"""
16331658
Transform magnetic vector into components within the scattering plane
@@ -1675,7 +1700,56 @@ def print_intensity(self, HKL):
16751700
vals=(HKL[n][0],HKL[n][1],HKL[n][2],IN[n],IX[n],INM[n],IXM[n],IXRss[n],IXRsp[n],IXRps[n],IXRpp[n])
16761701
outstr += fmt % vals
16771702
return outstr
1678-
1703+
1704+
def print_atom_scattering_factors(self, hkl, energy_kev=None):
1705+
"""show scattering factors for each atom for each reflection"""
1706+
qmag = self.xtl.Cell.Qmag(hkl)
1707+
ff = self.scattering_factors(hkl, energy_kev)
1708+
hkl = np.asarray(hkl, dtype=float).reshape([-1, 3])
1709+
1710+
out = f"{self._scattering_type}\n"
1711+
for n, (h, k, l) in enumerate(hkl):
1712+
out += f"({h:.3g}, {k:.3g}, {l:.3g}) |Q| = {qmag[n]:.4g} A-1\n"
1713+
for m, ele in enumerate(self.xtl.Structure.type):
1714+
out += f" {ele:5}: {ff[n, m]: 12.5f}\n"
1715+
return out
1716+
1717+
def print_scattering_factor_coefficients(self):
1718+
"""generate string of scattering factor coefficients for each atom"""
1719+
scattering_type = fs.get_scattering_type(self._scattering_type)
1720+
1721+
if 'neutron' in scattering_type:
1722+
if self._use_sears_scattering_lengths:
1723+
table = 'sears'
1724+
else:
1725+
table = 'ndb'
1726+
elif 'electron' in scattering_type:
1727+
table = 'peng'
1728+
elif 'xray' in scattering_type:
1729+
if self._use_waaskirf_scattering_factor:
1730+
table = 'waaskirf'
1731+
else:
1732+
table = 'itc'
1733+
else:
1734+
raise Exception(f"Unknown scattering type: {scattering_type}")
1735+
1736+
coefs = fc.scattering_factor_coefficients(*self.xtl.Structure.type, table=table)
1737+
if not np.any(coefs[:, -1]):
1738+
coefs = coefs[:, :-1] # trim final column if all zeros
1739+
n_doubles = coefs.shape[1] // 2
1740+
n_singles = coefs.shape[1] % 2
1741+
1742+
structrue = self.xtl.Structure
1743+
structure_list = zip(structrue.label, structrue.type, structrue.u, structrue.v, structrue.w)
1744+
out = f"{scattering_type}\n"
1745+
for n, (label, el, u, v, w) in enumerate(structure_list):
1746+
out += f"{n:3} {label:6} {el:5}: {u:8.3g}, {v:8.3g}, {w:8.3g} : "
1747+
out += ', '.join(f"a{d} = {coefs[n, 2*d]:.3f}, A{d} = {coefs[n, 2*d+1]:.3f}" for d in range(n_doubles))
1748+
out += (', ' * int(n_doubles > 0)) + (f"b = {coefs[n, -1]:.3f}" * n_singles)
1749+
out += '\n'
1750+
return out
1751+
1752+
16791753
def old_intensity(self, HKL, scattering_type=None):
16801754
"""
16811755
Calculate the squared structure factor for the given HKL
@@ -2303,48 +2377,50 @@ def print_atomic_contributions(self, HKL):
23032377
"""
23042378
Prints the atomic contributions to the structure factor
23052379
"""
2306-
2307-
HKL = np.asarray(np.rint(HKL),dtype=float).reshape([-1,3])
2380+
2381+
HKL = np.asarray(np.rint(HKL), dtype=float).reshape([-1, 3])
23082382
Nref = len(HKL)
2309-
2383+
23102384
# Calculate the full intensity
23112385
I = self.intensity(HKL)
2312-
2386+
23132387
# Calculate the structure factors of the symmetric atomic sites
23142388
base_label = self.xtl.Atoms.label
2315-
uvw,type,label,occ,uiso,mxmymz = self.xtl.Structure.get()
2316-
2389+
uvw, atom_type, label, occ, uiso, mxmymz = self.xtl.Structure.get()
2390+
23172391
Qmag = self.xtl.Cell.Qmag(HKL)
2318-
2392+
23192393
# Get atomic form factors
2320-
ff = fc.xray_scattering_factor(type,Qmag)
2321-
2394+
# ff = fc.xray_scattering_factor(atom_type, Qmag)
2395+
ff = self.scattering_factors(HKL)
2396+
23222397
# Get Debye-Waller factor
2323-
dw = fc.debyewaller(uiso,Qmag)
2324-
2398+
dw = fc.debyewaller(uiso, Qmag)
2399+
23252400
# Calculate dot product
2326-
dot_KR = np.dot(HKL,uvw.T)
2327-
2401+
dot_KR = np.dot(HKL, uvw.T)
2402+
23282403
# Calculate structure factor
2329-
SF = ff*dw*occ*np.exp(1j*2*np.pi*dot_KR)
2330-
2404+
SF = ff * dw * occ * np.exp(1j * 2 * np.pi * dot_KR)
2405+
23312406
# Sum structure factors of each base label in atoms
2332-
SFbase = np.zeros([len(HKL),len(base_label)],dtype=np.complex128)
2407+
SFbase = np.zeros([len(HKL), len(base_label) + 1], dtype=complex)
23332408
for n in range(len(base_label)):
23342409
label_idx = label == base_label[n]
2335-
SFbase[:,n] = np.sum(SF[:,label_idx],axis=1)
2336-
2410+
SFbase[:, n] = np.sum(SF[:, label_idx], axis=1)
2411+
SFbase[:, -1] = SFbase.sum(axis=1) # add the sum
2412+
23372413
# Get the real part of the structure factor
2338-
#SFtot = np.sqrt(np.real(SF * np.conj(SF)))
2414+
# SFtot = np.sqrt(np.real(SF * np.conj(SF)))
23392415
SFrel = np.real(SFbase)
23402416
SFimg = np.imag(SFbase)
2341-
2417+
23422418
# Generate the results
23432419
outstr = ''
2344-
outstr+= '( h, k, l) Intensity' + ' '.join(['%12s '%x for x in base_label])+'\n'
2420+
outstr += '( h, k, l) Intensity ' + ' '.join(['%12s ' % x for x in base_label]) + ' Total SF\n'
23452421
for n in range(Nref):
2346-
ss = ' '.join(['%6.1f + i%-6.1f' % (x,y) for x,y in zip(SFrel[n],SFimg[n])])
2347-
outstr+= '(%2.0f,%2.0f,%2.0f) %9.2f %s\n' % (HKL[n,0],HKL[n,1],HKL[n,2],I[n],ss)
2422+
ss = ' '.join(['%6.1f + i%-6.1f' % (x, y) for x, y in zip(SFrel[n], SFimg[n])])
2423+
outstr += '(%2.0f,%2.0f,%2.0f) %9.2f %s\n' % (HKL[n, 0], HKL[n, 1], HKL[n, 2], I[n], ss)
23482424
return outstr
23492425

23502426
def print_symmetry_contributions(self, HKL):
@@ -2367,7 +2443,8 @@ def print_symmetry_contributions(self, HKL):
23672443
# Calculate the structure factors
23682444
uvw, type, label, occ, uiso, mxmymz = self.xtl.Structure.get()
23692445
Qmag = self.xtl.Cell.Qmag(HKL)
2370-
ff = fc.xray_scattering_factor(type, Qmag)
2446+
# ff = fc.xray_scattering_factor(type, Qmag)
2447+
ff = self.scattering_factors(HKL)
23712448
dw = fc.debyewaller(uiso, Qmag)
23722449
dot_KR = np.dot(HKL, uvw.T)
23732450
phase = np.exp(1j * 2 * np.pi * dot_KR)

0 commit comments

Comments
 (0)