Imaging refactor part 2 - Atoms: add_atoms(), refine_atoms(), plot(kind='atoms') and tests#236
Imaging refactor part 2 - Atoms: add_atoms(), refine_atoms(), plot(kind='atoms') and tests#236darshan-mali wants to merge 4 commits into
Conversation
| relative to the lattice origin r0 and basis vectors (u, v), and are used to tile the | ||
| image with candidate atom centers at all visible integer translations. | ||
| numbers : array-like of int, shape (S,), optional | ||
| Identifier per site (e.g., species or label). If None, uses 1..S. Used only for plotting |
There was a problem hiding this comment.
If None, it appears to use 0, 1, ..., S-1
| # VALIDATION: Check that lattice vectors have been defined | ||
| if not hasattr(self, "_lat") or self._lat is None: | ||
| raise ValueError( | ||
| "Lattice vectors have not been fitted. Please call define_lattice() first." |
There was a problem hiding this comment.
define_lattice() --> define_lattice_vectors()
| r_px = float(intensity_radius) if intensity_radius is not None else _auto_radius_px() | ||
|
|
||
| # Annulus radii for background contrast measurement (in pixels) | ||
| rin, rout = (1.5 * r_px, 3.0 * r_px) if annulus_radii is None else annulus_radii |
There was a problem hiding this comment.
Is this what we want? It seems like this ring will include neighboring atoms... This could cause issues for atom position refinement.
| from scipy.ndimage import distance_transform_edt | ||
|
|
||
| DT = distance_transform_edt(m) | ||
| except Exception: |
There was a problem hiding this comment.
not sure why the distance_transform_edt would fail, but if it does, perhaps add an output message for this? otherwise this is a silent failure
| # Compute mean intensity in the detection disk for all candidates | ||
| int_center = np.empty(xy.shape[0], dtype=float) | ||
| for i in range(xy.shape[0]): | ||
| int_center[i] = mean_disk(x[i], y[i]) |
There was a problem hiding this comment.
we compute mean intensity for all atoms, even though we have a validity mask (we could generate keep right before this) that should rule some out at this point. It probably doesn't cost too much in the way of time, but it is worth making this change.
| estimate is invalid or non-positive, a robust fallback is used. | ||
| max_nfev : int, default 200 | ||
| Maximum number of function evaluations for the non-linear least-squares solver. | ||
| max_move_px : float, optional |
There was a problem hiding this comment.
max_move_px ends up not being the actual maximum movement, it is just the maximum movement in the x and y directions - both moving by max_move_px is not forbidden.
There was a problem hiding this comment.
Additional comment on this - I think that the maximum movement should not be greater than the window that the fit is over. The default is to make it equal, which seems okay, but user can set it greater; do we want to forbid that?
| max(pmax - pmin, amp0 * 4.0), | ||
| max(2.0 * r_fit, 1.0), | ||
| pmax + (pmax - pmin), | ||
| ] |
There was a problem hiding this comment.
these values seem arbitrary - why 0.25 for sigma min? why amp0*4 for amplitude max? I don't really have a better idea but just want to be thoughtful about these hard-coded values.
| ) | ||
|
|
||
| assert result is simple_lattice | ||
|
|
There was a problem hiding this comment.
these tests seem okay, and pass, but there is no test that validates the found positions of the atoms after refinement. That would be a good test.
What does this PR do?
Part 2 of Imaging refactor
Enables the Lattice class to store atoms and their data. This includes
add_atoms()function that checks if an atom is present at a given position and stores the atomic positions in both pixel and unit cell coordinatesrefine_atoms()function to refine the atomic positionsplot()now includeskind='atoms'Relevant references
Part 1 can be found at : #198
This PR involves the use of the
Vectordatastructure.A tutorial for the same can be found at: https://github.com/electronmicroscopy/quantem-tutorials/blob/main/tutorials/core/vector.ipynb
API and logic
After defining the lattice vectors, atoms can be added to$0 \leq u,v < 1$ .
Latticevia theadd_atoms()method.The
add_atoms()takes in the fractional/unit cell coordinates of all atoms in one unit cellThese are tiled across all unit cells and checked against the background to determine if an atom is present.
The
refine_atoms()functions optimizes for the position of the atom via 2D Gaussian fitting.The pixel and unit cell coordinates of the atoms are stored in
Lattice.atomswhich is aVectordatastructure, alongwith other fitting information.Both
add_atoms()andrefine_atoms()set thedefault_plot='atoms'inLattice.plot().Files changed
Updated files
src/quantem/imaging/lattice.py: Theadd_atoms()andrefine_atoms()functions were added.src/quantem/imaging/lattice_visualization.py: Functionality forplot(kind='atoms')was added along with necessary helperstests/imaging/test_lattice.py: Basic pytests foradd_atoms()andrefine_atoms()based on expected user behaviourExamples
A testing notebook with examples can be found here:
Lattice_refactor_2_atoms.ipynb
(Note: Some plotting calls have been commented out to reduce file size. Please uncomment them before running)
Example code block:
Example output:

PR Checklist
Reviewer checklist