Skip to content

Add option to have spot centers off pixel centers #235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 2, 2025

Conversation

viljarjf
Copy link
Contributor

Description of the change

Previously, Simulation2d.get_diffraction_pattern rounded coordinates down to nearest pixel in the output pattern, before adding a gaussian blur.
This PR implements a more manual gaussian blurring, evaluating the gaussian without assuming integer spot coordinates instead of using convolution.
This gives more accurate spot positions, which is important when using these patterns in external analysis tools.
It is slower, but using numba made it only around 20% slower (as opposed to 800% slower without).

Progress of the PR

Minimal example of the bug fix or new feature

# Setup
from diffpy.structure import Structure, Atom, Lattice
from orix.crystal_map import Phase
from diffsims.generators.simulation_generator import SimulationGenerator

l = Lattice(10, 10, 10, 90, 90, 90)
a = [Atom("Au", (0, 0, 0))]
s = Structure(a, l)

p = Phase(structure=s, space_group=1)

gen = SimulationGenerator()
sim = gen.calculate_diffraction2d(p)

Performance analysis:

%%timeit
sim.get_diffraction_pattern(shape=(100,100), sigma=1, fast=True)

205 µs ± 4.61 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

%%timeit
sim.get_diffraction_pattern(shape=(100,100), sigma=1, fast=False)

250 µs ± 2.8 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

New is around 25% slower.

Qualitative difference in resulting plots:

from matplotlib import pyplot as plt
plt.figure()
plt.subplot(1, 2, 1)
kwargs = dict(
    shape=(10, 10), 
    sigma=1, 
    normalize=False,
    fast_clip_threshold=0.1,
    calibration=0.001, # Very small calibration = only direct beam
)
fast = sim.get_diffraction_pattern(fast=True, **kwargs)
plt.imshow(fast, vmax=20)
plt.subplot(1, 2, 2)
slow = sim.get_diffraction_pattern(fast=False, **kwargs)
plt.imshow(slow, vmax=20)

image

In the example above, since the shape is 10x10, the center is not at a pixel coordinate, but at (4.5, 4.5). This is rounded to (5, 5) in the fast (current) mode.

Note that there is a bug where the direct beam is added twice to the simulations. For the fast mode, this is fine, as the intensity of each spot is set rather than summed (before blurring). For the new, however, the direct beam is twice as intense as it should. This is fixed in #232.

For reviewers

  • The PR title is short, concise, and will make sense 1 year later.
  • New functions are imported in corresponding __init__.py.
  • New features, API changes, and deprecations are mentioned in the
    unreleased section in CHANGELOG.rst.
  • Contributor(s) are listed correctly in credits in diffsims/release_info.py and
    in .zenodo.json.

@viljarjf viljarjf mentioned this pull request Jan 27, 2025
13 tasks
@CSSFrancis CSSFrancis self-requested a review June 2, 2025 01:53
@CSSFrancis CSSFrancis force-pushed the accurate-diffraction-spot-positions branch from 6be366c to 91ee08d Compare June 2, 2025 01:55
@CSSFrancis CSSFrancis force-pushed the accurate-diffraction-spot-positions branch from 4e57397 to eb8a04d Compare June 2, 2025 18:27
@CSSFrancis CSSFrancis requested a review from Copilot June 2, 2025 20:27
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds subpixel-precise Gaussian blurring in Simulation2D.get_diffraction_pattern to allow spot centers off integer pixel centers by replacing the convolution-based blur with a manual evaluation.
Key changes:

  • Introduce get_pattern_from_pixel_coordinates_and_intensities for both integer and float coordinates
  • Update Simulation2D.get_diffraction_pattern signature and logic to handle fast, normalize, and clip_threshold
  • Add tests for fast vs slow modes and for the new detector function

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
diffsims/utils/fourier_transform.py Mark fallback FFT planning functions with # pragma: no cover
diffsims/simulations/simulation2d.py Extend get_diffraction_pattern signature, remove old convolution path
diffsims/pattern/detector_functions.py Add get_pattern_from_pixel_coordinates_and_intensities and helper
diffsims/tests/simulations/test_simulations2d.py Add test_get_diffraction_pattern_fast_vs_slow
diffsims/tests/patterns/test_detector_functions.py Add tests for subpixel pattern generator

@CSSFrancis CSSFrancis merged commit 293f75d into pyxem:main Jun 2, 2025
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants