def objfunc(params, k_xy, lattice_recip, wavelength, camera_length): cx = params["center_x"].value cy = params["center_y"].value ai = params["ai"].value aj = params["aj"].value ak = params["ak"].value scale = params["scale"].value rotmat = euler2mat(ai, aj, ak) k_xy = k_xy + np.array((cx, cy)) * scale cart = detector_to_fourier(k_xy, wavelength, camera_length) intermediate = cart.dot(rotmat.T) # Must use the transpose here hklss = lattice_recip.fractional(intermediate) * scale rhklss = np.rint(hklss) ehklss = np.abs(hklss - rhklss) return ehklss
def _refine_orientation( solution, k_xy, structure_library, accelarating_voltage, camera_length, index_error_tol=0.2, method="leastsq", vary_angles=True, vary_center=False, vary_scale=False, verbose=False, ): """ Refine a single orientation agains the given cartesian vector coordinates. Parameters ---------- solution : OrientationResult Namedtuple containing the starting orientation k_xy : DiffractionVectors DiffractionVectors (x,y pixel format) to be indexed. structure_library : :obj:`diffsims:StructureLibrary` Object Dictionary of structures and associated orientations for which electron diffraction is to be simulated. index_error_tol : float Max allowed error in peak indexation for classifying it as indexed, calculated as :math:`|hkl_calculated - round(hkl_calculated)|`. method : str Minimization algorithm to use, choose from: 'leastsq', 'nelder', 'powell', 'cobyla', 'least-squares'. See `lmfit` documentation (https://lmfit.github.io/lmfit-py/fitting.html) for more information. vary_angles : bool, Free the euler angles (rotation matrix) during the refinement. vary_center : bool Free the center of the diffraction pattern (beam center) during the refinement. vary_scale : bool Free the scale (i.e. pixel size) of the diffraction vectors during refinement. verbose : bool Be more verbose Returns ------- result : OrientationResult Container for the orientation refinement results """ # prepare reciprocal_lattice structure = structure_library.structures[solution.phase_index] lattice_recip = structure.lattice.reciprocal() def objfunc(params, k_xy, lattice_recip, wavelength, camera_length): cx = params["center_x"].value cy = params["center_y"].value ai = params["ai"].value aj = params["aj"].value ak = params["ak"].value scale = params["scale"].value rotmat = euler2mat(ai, aj, ak) k_xy = k_xy + np.array((cx, cy)) * scale cart = detector_to_fourier(k_xy, wavelength, camera_length) intermediate = cart.dot(rotmat.T) # Must use the transpose here hklss = lattice_recip.fractional(intermediate) * scale rhklss = np.rint(hklss) ehklss = np.abs(hklss - rhklss) return ehklss ai, aj, ak = mat2euler(solution.rotation_matrix) params = lmfit.Parameters() params.add("center_x", value=solution.center_x, vary=vary_center) params.add("center_y", value=solution.center_y, vary=vary_center) params.add("ai", value=ai, vary=vary_angles) params.add("aj", value=aj, vary=vary_angles) params.add("ak", value=ak, vary=vary_angles) params.add("scale", value=solution.scale, vary=vary_scale, min=0.8, max=1.2) wavelength = get_electron_wavelength(accelarating_voltage) camera_length = camera_length * 1e10 args = k_xy, lattice_recip, wavelength, camera_length res = lmfit.minimize(objfunc, params, args=args, method=method) if verbose: # pragma: no cover lmfit.report_fit(res) p = res.params ai, aj, ak = p["ai"].value, p["aj"].value, p["ak"].value scale = p["scale"].value center_x = params["center_x"].value center_y = params["center_y"].value rotation_matrix = euler2mat(ai, aj, ak) k_xy = k_xy + np.array((center_x, center_y)) * scale cart = detector_to_fourier(k_xy, wavelength=wavelength, camera_length=camera_length) intermediate = cart.dot(rotation_matrix.T) # Must use the transpose here hklss = lattice_recip.fractional(intermediate) rhklss = np.rint(hklss) error_hkls = res.residual.reshape(-1, 3) error_mean = np.mean(error_hkls) valid_peak_mask = np.max(error_hkls, axis=-1) < index_error_tol valid_peak_count = np.count_nonzero(valid_peak_mask, axis=-1) num_peaks = len(k_xy) match_rate = (valid_peak_count * (1 / num_peaks)) if num_peaks else 0 orientation = OrientationResult( phase_index=solution.phase_index, rotation_matrix=rotation_matrix, match_rate=match_rate, error_hkls=error_hkls, total_error=error_mean, scale=scale, center_x=center_x, center_y=center_y, ) res = np.empty(2, dtype=np.object) res[0] = orientation res[1] = rhklss return res
def test_detector_to_fourier(wavelength, camera_length, detector_coords, k_expected): k = detector_to_fourier(detector_coords, wavelength, camera_length) np.testing.assert_allclose(k, k_expected)