def test_energy(): energy = Accelerator(energy=300e3) assert energy.energy == 300e3 assert np.isclose(energy.wavelength, energy2wavelength(300e3)) energy.energy = 200e3 assert np.isclose(energy.wavelength, energy2wavelength(200e3))
def point_resolution(Cs: float, energy: float): """ Calculate the point resolution. Parameters ---------- Cs: float Spherical aberration [Å]. energy: float Electron energy [eV]. Returns ------- float The point resolution. """ return (energy2wavelength(energy)**3 * np.abs(Cs) / 6)**(1 / 4)
def scherzer_defocus(Cs, energy): """ Calculate the Scherzer defocus. Parameters ---------- Cs: float Spherical aberration [Å]. energy: float Electron energy [eV]. Returns ------- float The Scherzer defocus. """ return np.sign(Cs) * np.sqrt( 3 / 2 * np.abs(Cs) * energy2wavelength(energy))
def wavelength(self) -> float: """ Relativistic wavelength [Å]. """ self.check_is_defined() return energy2wavelength(self.energy)
def _evaluate_potential(self): from sympy.physics.wigner import wigner_3j self.grid.check_is_defined() self.accelerator.check_is_defined() potential = np.zeros(self.gpts, dtype=np.complex64) kx, ky = spatial_frequencies(self.gpts, self.sampling) kz = self.momentum_transfer kt, phi = polar_coordinates(kx, ky) k = np.sqrt(kt**2 + kz**2) theta = np.pi - np.arctan(kt / kz) radial_grid = np.arange(0, np.max(k) * 1.05, 1 / max(self.extent)) l, ml = self._bound_state lprime, mlprime = self._continuum_state for lprimeprime in range(max(l - lprime, 0), np.abs(l + lprime) + 1): prefactor1 = (np.sqrt(4 * np.pi) * ((-1.j)**lprimeprime) * np.sqrt( (2 * lprime + 1) * (2 * lprimeprime + 1) * (2 * l + 1))) jk = None for mlprimeprime in range(-lprimeprime, lprimeprime + 1): if ml - mlprime - mlprimeprime != 0: # Wigner3j selection rule continue # Evaluate Eq. (14) from Dwyer Ultramicroscopy 104 (2005) 141-151 prefactor2 = ( (-1.0)**(mlprime + mlprimeprime) * float(wigner_3j(lprime, lprimeprime, l, 0, 0, 0)) * float( wigner_3j(lprime, lprimeprime, l, -mlprime, -mlprimeprime, ml))) if np.abs(prefactor2) < 1e-12: continue if jk is None: jk = interp1d( radial_grid, self.overlap_integral(radial_grid, lprimeprime))(k) Ylm = sph_harm(mlprimeprime, lprimeprime, phi, theta) potential += prefactor1 * prefactor2 * jk * Ylm potential *= np.prod(self.gpts) / np.prod(self.extent) # Multiply by orbital filling # if orbital_filling_factor: potential *= np.sqrt(4 * l + 2) # Apply constants: # sqrt(Rdyberg) to convert to 1/sqrt(eV) units # 1 / (2 pi**2 a0 kn) as as per paper # Relativistic mass correction to go from a0 to relativistically corrected a0* # divide by q**2 kn = 1 / energy2wavelength(self.energy + self.energy_loss) potential *= relativistic_mass_correction(self.energy) / ( 2 * units.Bohr * np.pi**2 * np.sqrt(units.Rydberg) * kn * k**2) return potential
def momentum_transfer(self): k0 = 1 / energy2wavelength(self.energy) kn = 1 / energy2wavelength(self.energy + self.energy_loss) return k0 - kn
def point_resolution(Cs, energy): return (energy2wavelength(energy)**3 * np.abs(Cs) / 6)**(1 / 4)
def scherzer_defocus(Cs, energy): return np.sign(Cs) * np.sqrt( 3 / 2 * np.abs(Cs) * energy2wavelength(energy))
def test_energy2wavelength(): assert np.isclose(energy2wavelength(300e3), 0.01968748889772767)