def test_fast_abs(shape, n): x = _random_array(shape, n) y = np.empty(shape, dtype=x.dtype) z = fast_abs(x, y) np.testing.assert_allclose(abs(x), fast_abs(x), 1e-5) np.testing.assert_allclose(abs(x), y, 1e-5) assert y is z
def get_diffraction_image(coordinates, species, probe, x, wavelength, precession, GPU=True, pointwise=False, **kwargs): """ Return kinematically simulated diffraction pattern Parameters ---------- coordinates : `numpy.ndarray` [`float`], (n_atoms, 3) List of atomic coordinates species : `numpy.ndarray` [`int`], (n_atoms,) List of atomic numbers probe : `diffsims.ProbeFunction` Function representing 3D shape of beam x : `list` [`numpy.ndarray` [`float`] ], of shapes [(nx,), (ny,), (nz,)] Mesh on which to compute the volume density wavelength : `float` Wavelength of electron beam precession : a pair (`float`, `int`) The float dictates the angle of precession and the int how many points are used to discretise the integration. dtype : (`str`, `str`) tuple of floating/complex datatypes to cast outputs to ZERO : `float` > 0, optional Rounding error permitted in computation of atomic density. This value is the smallest value rounded to 0. GPU : `bool`, optional Flag whether to use GPU or CPU discretisation. Default (if available) is True pointwise : `bool`, optional Optional parameter whether atomic intensities are computed point-wise at the centre of a voxel or an integral over the voxel. default=False Returns ------- DP : `numpy.ndarray` [`dtype[0]`], (nx, ny, nz) The two-dimensional diffraction pattern evaluated on the reciprocal grid corresponding to the first two vectors of `x`. """ FTYPE = kwargs["dtype"][0] kwargs["GPU"] = GPU kwargs["pointwise"] = pointwise x = [X.astype(FTYPE, copy=False) for X in x] y = to_recip(x) if wavelength == 0: p = probe(x).mean(-1) vol = get_discretisation(coordinates, species, x[:2], **kwargs)[..., 0] ft = get_DFT(x[:-1], y[:-1])[0] else: p = probe(x) vol = get_discretisation(coordinates, species, x, **kwargs) ft = get_DFT(x, y)[0] if precession[0] == 0: arr = ft(vol * p) arr = fast_abs(arr, arr).real**2 if wavelength == 0: return normalise(arr) else: return normalise(grid2sphere(arr, y, None, 2 * pi / wavelength)) R = [ precess_mat(precession[0], i * 360 / precession[1]) for i in range(precession[1]) ] if wavelength == 0: return normalise( sum( get_diffraction_image(coordinates.dot(r), species, probe, x, wavelength, (0, 1), **kwargs) for r in R)) fftshift_phase(vol) # removes need for fftshift after fft buf = empty(vol.shape, dtype=FTYPE) ft, buf = plan_fft(buf, overwrite=True, planner=1) DP = None for r in R: probe(to_mesh(x, r.T, dtype=FTYPE), out=buf, scale=vol) # buf = bess*vol # Do convolution newFT = ft() newFT = fast_abs(newFT, buf).real newFT *= newFT # newFT = abs(newFT) ** 2 newFT = grid2sphere(newFT.real, y, list(r), 2 * pi / wavelength) if DP is None: DP = newFT else: DP += newFT return normalise(DP.astype(FTYPE, copy=False))