Skip to content

Commit 347f7d4

Browse files
authored
Merge pull request #238 from CSSFrancis/bugfix_simulation
Bugfix: Small Bugfix for polar flatten simulation
2 parents c356a2f + 9833f45 commit 347f7d4

File tree

7 files changed

+106
-83
lines changed

7 files changed

+106
-83
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ jobs:
4646
- os: ubuntu-latest
4747
python-version: 3.9
4848
OLDEST_SUPPORTED_VERSION: true
49-
DEPENDENCIES: diffpy.structure==3.0.2 matplotlib==3.5 numpy==1.17.3 orix==0.12.1 scipy==1.8 tqdm==4.61.2
49+
DEPENDENCIES: diffpy.structure==3.0.2 matplotlib==3.7 numpy==1.24 orix==0.12.1 scipy==1.10 tqdm==4.61.2
5050
LABEL: -oldest
5151
steps:
5252
- uses: actions/checkout@v4

diffsims/generators/simulation_generator.py

Lines changed: 19 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from orix.crystal_map import Phase
2828

2929
from diffsims.crystallography._diffracting_vector import DiffractingVector
30+
from diffsims.crystallography import ReciprocalLatticeVector
3031
from diffsims.utils.shape_factor_models import (
3132
linear,
3233
atanc,
@@ -280,65 +281,37 @@ def calculate_diffraction1d(
280281
debye_waller_factors
281282
Maps element names to their temperature-dependent Debye-Waller factors.
282283
"""
283-
latt = phase.structure.lattice
284+
rpl = ReciprocalLatticeVector.from_min_dspacing(phase)
285+
rpl = rpl.unique(use_symmetry=True)
284286

285-
# Obtain crystallographic reciprocal lattice points within range
286-
recip_latt = latt.reciprocal()
287-
spot_indices, _, spot_distances = get_points_in_sphere(
288-
recip_latt, reciprocal_radius
289-
)
290-
291-
##spot_indicies is a numpy.array of the hkls allowed in the recip radius
292-
g_indices, multiplicities, g_hkls = get_intensities_params(
293-
recip_latt, reciprocal_radius
294-
)
295-
296-
i_hkl = get_kinematical_intensities(
287+
intensities = get_kinematical_intensities(
297288
phase.structure,
298-
g_indices,
299-
np.asarray(g_hkls),
300-
prefactor=multiplicities,
289+
rpl.hkl,
290+
rpl.gspacing,
291+
prefactor=rpl.multiplicity,
301292
scattering_params=self.scattering_params,
302293
debye_waller_factors=debye_waller_factors,
303294
)
304-
305-
if is_lattice_hexagonal(latt):
306-
# Use Miller-Bravais indices for hexagonal lattices.
307-
g_indices = np.array(
308-
[
309-
g_indices[:, 0],
310-
g_indices[:, 1],
311-
g_indices[:, 0] - g_indices[:, 1],
312-
g_indices[:, 2],
313-
]
314-
).T
315-
316-
hkls_labels = ["".join([str(int(x)) for x in xs]) for xs in g_indices]
317-
318-
peaks = []
319-
for l, i, g in zip(hkls_labels, i_hkl, g_hkls):
320-
peaks.append((l, [i, g]))
295+
if rpl.has_hexagonal_lattice:
296+
hkl = rpl.hkil
297+
else:
298+
hkl = rpl.hkl
299+
g_vectors = rpl.gspacing
321300

322301
# Scale intensities so that the max intensity is 100.
323302

324-
max_intensity = max([v[1][0] for v in peaks])
325-
reciporical_spacing = []
326-
intensities = []
327-
hkls = []
328-
for p in peaks:
329-
label, v = p # (label, [intensity,g])
330-
if v[0] / max_intensity * 100 > minimum_intensity and (label != "000"):
331-
reciporical_spacing.append(v[1])
332-
intensities.append(v[0])
333-
hkls.append(label)
334-
303+
max_intensity = np.max(intensities)
335304
intensities = np.asarray(intensities) / max(intensities) * 100
305+
mask = intensities > minimum_intensity
306+
intensities = intensities[mask]
307+
g_vectors = g_vectors[mask]
308+
hkl = hkl[mask]
336309

337310
return Simulation1D(
338311
phase=phase,
339-
reciprocal_spacing=reciporical_spacing,
312+
reciprocal_spacing=g_vectors,
340313
intensities=intensities,
341-
hkl=hkls,
314+
hkl=hkl,
342315
reciprocal_radius=reciprocal_radius,
343316
wavelength=self.wavelength,
344317
)

diffsims/simulations/simulation1d.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,45 @@ def __repr__(self):
7272
def theta(self):
7373
return np.arctan2(np.array(self.reciprocal_spacing), 1 / self.wavelength)
7474

75-
def plot(self, ax=None, annotate_peaks=False, fontsize=12, with_labels=True):
76-
"""Plots the 1D diffraction pattern,"""
75+
def plot(
76+
self,
77+
ax=None,
78+
annotate_peaks=False,
79+
fontsize=12,
80+
with_labels=True,
81+
rotation=90,
82+
va="bottom",
83+
ha="center",
84+
**kwargs,
85+
):
86+
"""Plots the 1D diffraction pattern,
87+
88+
Parameters
89+
----------
90+
ax : matplotlib.axes.Axes, optional
91+
The axes to plot on. If None, a new figure and axes are created.
92+
annotate_peaks : bool, optional
93+
Whether to annotate the peaks with their hkl indices. Default is False.
94+
95+
"""
7796
if ax is None:
7897
fig, ax = plt.subplots(1, 1)
7998
for g, i, hkls in zip(self.reciprocal_spacing, self.intensities, self.hkl):
8099
label = hkls
81100
ax.plot([g, g], [0, i], color="k", linewidth=3, label=label)
82101
if annotate_peaks:
83-
ax.annotate(label, xy=[g, i], xytext=[g, i], fontsize=fontsize)
102+
label = "[" + "".join([str(int(np.round(x))) for x in label]) + "]"
103+
104+
ax.annotate(
105+
label,
106+
xy=[g, i],
107+
xytext=[g, i + 4],
108+
fontsize=fontsize,
109+
rotation=rotation,
110+
va=va,
111+
ha=ha,
112+
**kwargs,
113+
)
84114

85115
if with_labels:
86116
ax.set_xlabel("A ($^{-1}$)")

diffsims/simulations/simulation2d.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -327,14 +327,25 @@ def polar_flatten_simulations(self, radial_axes=None, azimuthal_axes=None):
327327
intensities_templates = np.zeros((len(flattened_vectors), max_num_spots))
328328
for i, v in enumerate(flattened_vectors):
329329
r, t = v.to_flat_polar()
330+
inten = v.intensity
330331
if radial_axes is not None and azimuthal_axes is not None:
331-
r = get_closest(radial_axes, r)
332-
t = get_closest(azimuthal_axes, t)
333-
r = r[r < len(radial_axes)]
334-
t = t[t < len(azimuthal_axes)]
335-
r_templates[i, : len(r)] = r
336-
theta_templates[i, : len(t)] = t
337-
intensities_templates[i, : len(v.intensity)] = v.intensity
332+
r = get_closest(
333+
radial_axes, r
334+
) # convert from real to pixel coordinates
335+
t = get_closest(
336+
azimuthal_axes, t
337+
) # convert from real to pixel coordinates
338+
mask = (r < len(radial_axes) - 1) & (
339+
t < len(azimuthal_axes) - 1
340+
) # combined mask for out-of-bounds indices
341+
r = r[mask] # apply combined mask
342+
t = t[mask] # apply combined mask
343+
inten = inten[mask] # apply combined mask
344+
r_templates[i, : len(r)] = (
345+
r # set the r coordinates (len r and t should be the same)
346+
)
347+
theta_templates[i, : len(r)] = t # set the theta coordinates
348+
intensities_templates[i, : len(inten)] = inten
338349
if radial_axes is not None and azimuthal_axes is not None:
339350
r_templates = np.array(r_templates, dtype=int)
340351
theta_templates = np.array(theta_templates, dtype=int)

diffsims/tests/generators/test_simulation_generator.py

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import numpy as np
2020
import pytest
2121
from pathlib import Path
22+
import re
2223

2324
import diffpy.structure
2425
from orix.crystal_map import Phase
@@ -239,7 +240,6 @@ def test_simulate_1d(self, is_hex):
239240
assert len(sim.intensities) == len(sim.reciprocal_spacing)
240241
assert len(sim.intensities) == len(sim.hkl)
241242
for h in sim.hkl:
242-
h = h.replace("-", "")
243243
if is_hex:
244244
assert len(h) == 4
245245
else:
@@ -360,10 +360,9 @@ def test_calculate_diffraction2d_progressbar_single_phase(capsys):
360360
sims = gen.calculate_diffraction2d(phase, rots, show_progressbar=True)
361361

362362
captured = capsys.readouterr()
363-
expected = "test phase: 100%|██████████| 10/10" # also some more, but that is compute-time dependent
364-
# ignore possible flushing
365-
captured = captured.err.split("\r")[-1]
366-
assert captured[: len(expected)] == expected
363+
# Accept any number of "█" characters
364+
expected = "test phase: 100\%\|█+\| 10\/10"
365+
assert re.findall(expected, captured.err)
367366

368367

369368
def test_calculate_diffraction2d_progressbar_multi_phase(capsys):
@@ -389,15 +388,8 @@ def test_calculate_diffraction2d_progressbar_multi_phase(capsys):
389388
)
390389

391390
captured = capsys.readouterr()
392-
expected1 = "A: 100%|██████████| 10/10 "
393-
expected2 = "B: 100%|██████████| 10/10 "
394-
# Find the correct output in the stream, i.e. final line containing the name of the phase
395-
captured1 = ""
396-
captured2 = ""
397-
for line in captured.err.split("\r"):
398-
if "A" in line:
399-
captured1 = line
400-
if "B" in line:
401-
captured2 = line
402-
assert captured1[: len(expected1)] == expected1
403-
assert captured2[: len(expected2)] == expected2
391+
# Accept any number of "█" characters
392+
expected1 = "A: 100\%\|█+\| 10\/10 "
393+
expected2 = "B: 100\%\|█+\| 10\/10 "
394+
assert re.findall(expected1, captured.err)
395+
assert re.findall(expected2, captured.err)

diffsims/tests/simulations/test_simulations1d.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class TestSingleSimulation:
3030
def simulation1d(self):
3131
al_phase = make_phase()
3232
al_phase.name = "Al"
33-
hkls = np.array(["100", "110", "111"])
33+
hkls = np.array([[1, 0, 0], [1, 1, 0], [1, 1, 1]])
3434
magnitudes = np.array([1, 2, 3])
3535
inten = np.array([1, 2, 3])
3636
recip = 4.0

diffsims/tests/simulations/test_simulations2d.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,20 @@ class TestSingleSimulation:
4646
def single_simulation(self, al_phase):
4747
gen = SimulationGenerator(accelerating_voltage=200)
4848
rot = Rotation.from_axes_angles([1, 0, 0], 45, degrees=True)
49-
coords = DiffractingVector(phase=al_phase, xyz=[[1, 0, 0]])
49+
coords = DiffractingVector(
50+
phase=al_phase,
51+
xyz=[
52+
[1, 0, 0],
53+
[2, 0, 0],
54+
[3, 3, 0],
55+
[-4, 0, 0],
56+
[-5, 0, 0],
57+
[-6, 0, 0],
58+
[-7, 0, 0],
59+
[-8, 0, 0],
60+
],
61+
intensity=[1, 2, 3, 4, 5, 6, 7, 8],
62+
)
5063
sim = Simulation2D(
5164
phases=al_phase, simulation_generator=gen, coordinates=coords, rotations=rot
5265
)
@@ -91,12 +104,12 @@ def test_polar_flatten(self, single_simulation):
91104
theta_templates,
92105
intensities_templates,
93106
) = single_simulation.polar_flatten_simulations()
94-
assert r_templates.shape == (1, 1)
95-
assert theta_templates.shape == (1, 1)
96-
assert intensities_templates.shape == (1, 1)
107+
assert r_templates.shape == (1, 8)
108+
assert theta_templates.shape == (1, 8)
109+
assert intensities_templates.shape == (1, 8)
97110

98111
def test_polar_flatten_axes(self, single_simulation):
99-
radial_axes = np.linspace(0, 1, 10)
112+
radial_axes = np.linspace(0, 7, 5)
100113
theta_axes = np.linspace(0, 2 * np.pi, 10)
101114
(
102115
r_templates,
@@ -105,9 +118,13 @@ def test_polar_flatten_axes(self, single_simulation):
105118
) = single_simulation.polar_flatten_simulations(
106119
radial_axes=radial_axes, azimuthal_axes=theta_axes
107120
)
108-
assert r_templates.shape == (1, 1)
109-
assert theta_templates.shape == (1, 1)
110-
assert intensities_templates.shape == (1, 1)
121+
assert r_templates.shape == (1, 8)
122+
assert theta_templates.shape == (1, 8)
123+
assert intensities_templates.shape == (1, 8)
124+
# The last 2 elements should be zero
125+
np.testing.assert_array_equal(r_templates[:, 6:], 0)
126+
np.testing.assert_array_equal(theta_templates[:, 6:], 0)
127+
np.testing.assert_array_equal(intensities_templates[:, 6:], 0)
111128

112129
def test_deepcopy(self, single_simulation):
113130
copied = single_simulation.deepcopy()

0 commit comments

Comments
 (0)