Skip to content
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

Simulations with Phase do not take symmetry into account #234

Open
viljarjf opened this issue Jan 23, 2025 · 0 comments
Open

Simulations with Phase do not take symmetry into account #234

viljarjf opened this issue Jan 23, 2025 · 0 comments

Comments

@viljarjf
Copy link

viljarjf commented Jan 23, 2025

Describe the bug
The new simulations with a Phase does not (necessarily) take symmetry into account when calculating intensities. Only the explicitly included atoms in the underlying structure are part of the structure factor calculations.

To Reproduce
Steps to reproduce the behavior:

from numpy import allclose
from matplotlib import pyplot as plt
from diffpy.structure import Structure, Atom, Lattice
from orix.crystal_map import Phase
from orix.quaternion import Rotation
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)

P1 = Phase(structure=s, space_group=1)
Fd3m = Phase(structure=s, space_group=227)

# Rotate slightly off-zone to see extinct reflections
rot = Rotation.from_euler((0, 0, 1), degrees=True)

gen = SimulationGenerator()
P1_sim = gen.calculate_diffraction2d(P1, rotation=rot)
Fd3m_sim = gen.calculate_diffraction2d(Fd3m, rotation=rot)

# Use ReciprocalLatticeVector.sanitize_phase
Fd3m_sim.coordinates.sanitise_phase()
Fd3m_expanded = Fd3m_sim.coordinates.phase
Fd3m_sim_expanded = gen.calculate_diffraction2d(Fd3m_expanded, rotation=rot)

# Intensities should be different due to the added symmetry, 
# even when the symmetrically equivalent atoms are missing from the structure
assert not allclose(P1_sim.coordinates.intensity, Fd3m_sim_expanded.coordinates.intensity) # Passes
# assert not allclose(P1_sim.coordinates.intensity, Fd3m_sim.coordinates.intensity) # Fails

# Plot patterns
plt.figure()
plt.subplot(1, 3, 1)
plt.title("P1")
P1_sim.plot(ax=plt.gca())

plt.subplot(1, 3, 2)
plt.title("Fd3m default")
Fd3m_sim.plot(ax=plt.gca())

plt.subplot(1, 3, 3)
plt.title("Fd3m expanded")
Fd3m_sim_expanded.plot(ax=plt.gca())

Image

Currently, intensities are calculated as follows:

  1. Find intersecting vectors for a given reflection
  2. Calculate the structure factor of each intersected reflection
  3. Square the structure factor, and scale it according to the excitation error

I suggest instead to calculate the structure factors with ReciprocalLatticeVector.calculate_structure_factor(), after calling ReciprocalLatticeVector.sanitize_phase(). This reduces code duplication, and lets us avoid a lot of re-computing. The loop over rotations then only needs to find the excitation error, and scale the squared structure factor using that.

Expected behavior
Expand the unit cell to ensure structure factors are calculated correctly, and then scale using the excitation error

viljarjf added a commit to viljarjf/diffsims that referenced this issue Jan 23, 2025
@viljarjf viljarjf mentioned this issue Jan 27, 2025
13 tasks
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

No branches or pull requests

1 participant