Skip to content

Improving/bugfixing how we simulate precession #159

@pc494

Description

@pc494

I think our current precession simulations could be improved a little. Currently we use "max_excitation_error" to eliminate spots from our precessed simulations, but this isn't quiet accurate as it doesn't account for the size of the g vector sensibly.

Case 1 (no approximation):
This finds the average excitation error, but a spot can have an average excitation error greater than max_excitation_error and we would still expect to see it in a pattern as long as somewhere on the circuit it had a sufficiently small excitation error. This is a bug (I think).

Case 2 (approximation):
These spots are eliminated before we even consider that there is precession going on.

Proposed solution:

Working from Equation 10 of [1] which provides the intensity of a spot as a function of:

g-vector (we have this)
precession angle (we have this)
the unprecessed excitation error, which is exactly what we have
the extinction distance (we can use max_excitation_error as a proxy)

(and is currently used in "lorenztian precession)

What Figure 3 (same manuscript) shows is that changing max_excitation_error doesn't change the width of the camel plot significantly. This is likely because we are in the regime (below equation 11) where we have full integration of our spots. We could create two cases (basically by hand) and use them as the eliminations. They would be:

~ numerical_factor * g * phi (precesison regime)
~ The 98th percentile (or similar) of the phi = 0 lorenztian

I would take this opportunity to remove the "manual integration" as I'm not sure this is a particularly good option.

[1] - Specifics of the data processing of precession electron diffraction tomography data and their implementation in the program PETS2.0 - Lukáš Palatinus et al.

Code

As it currently is.

# Identify points intersecting the Ewald sphere within maximum
        # excitation error and store the magnitude of their excitation error.
        r_sphere = 1 / wavelength
        r_spot = np.sqrt(np.sum(np.square(cartesian_coordinates[:, :2]), axis=1))
        z_spot = cartesian_coordinates[:, 2]

        if self.precession_angle > 0 and not self.approximate_precession:
            # We find the average excitation error - this step can be
            # quite expensive
            excitation_error = _average_excitation_error_precession(
                z_spot,
                r_spot,
                wavelength,
                self.precession_angle,
            )
        else:
            z_sphere = -np.sqrt(r_sphere ** 2 - r_spot ** 2) + r_sphere
            excitation_error = z_sphere - z_spot
        # Mask parameters corresponding to excited reflections.
        intersection = np.abs(excitation_error) < max_excitation_error
        intersection_coordinates = cartesian_coordinates[intersection]
        excitation_error = excitation_error[intersection]

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature, request, or improvement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions