def _peaks_from_best_template(single_match_result, library, rank=0): """Takes a TemplateMatchingResults object and return the associated peaks, to be used in combination with map(). Parameters ---------- single_match_result : ndarray An entry in a TemplateMatchingResults. library : DiffractionLibrary Diffraction library containing the phases and rotations. rank : int Get peaks from nth best orientation (default: 0, best vector match) Returns ------- peaks : array Coordinates of peaks in the matching results object in calibrated units. """ best_fit = get_nth_best_solution(single_match_result, "template", rank=rank) phase_names = list(library.keys()) phase_index = int(best_fit[0]) phase = phase_names[phase_index] simulation = library.get_library_entry(phase=phase, angle=tuple(best_fit[1]))["Sim"] peaks = simulation.coordinates[:, :2] # cut z return peaks
def crystal_from_vector_matching(z_matches): """Takes vector matching results for a single navigation position and returns the best matching phase and orientation with correlation and reliability to define a crystallographic map. Parameters ---------- z_matches : numpy.array Template matching results in an array of shape (m,5) sorted by total_error (ascending) within each phase, with entries [phase, R, match_rate, ehkls, total_error] Returns ------- results_array : numpy.array Crystallographic mapping results in an array of shape (3) with entries [phase, np.array((z, x, z)), dict(metrics)] """ if z_matches.shape == (1, ): # pragma: no cover z_matches = z_matches[0] # Create empty array for results. results_array = np.empty(3, dtype="object") # get best matching phase best_match = get_nth_best_solution(z_matches, "vector", key="total_error", descending=False) results_array[0] = best_match.phase_index # get best matching orientation Euler angles results_array[1] = np.rad2deg(mat2euler(best_match.rotation_matrix, "rzxz")) # get vector matching metrics metrics = dict() metrics["match_rate"] = best_match.match_rate metrics["ehkls"] = best_match.error_hkls metrics["total_error"] = best_match.total_error results_array[2] = metrics return results_array
def _refine_best_orientations( single_match_result, vectors, library, accelarating_voltage, camera_length, n_best=5, rank=0, 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 ---------- single_match_result : VectorMatchingResults Pool of solutions from the vector matching algorithm n_best : int Refine the best `n` orientations starting from `rank`. With `n_best=0` (default), all orientations are refined. rank : int The rank of the solution to start from. solution : list np.array containing the initial orientation vectors : DiffractionVectors DiffractionVectors 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. Returns ------- result : OrientationResult Container for the orientation refinement results """ if not isinstance(single_match_result[0], tuple): # pragma: no cover single_match_result = single_match_result[0] n_matches = len(single_match_result) if n_best == 0: n_best = n_matches - rank n_best = min(n_matches, n_best) top_matches = np.empty(n_best, dtype="object") res_rhkls = [] for i in range(rank, rank + n_best): if verbose: # pragma: no cover print(f"# {i}/{n_best} ({n_matches})") solution = get_nth_best_solution(single_match_result, "vector", rank=i) result = _refine_orientation( solution, vectors, library, accelarating_voltage=accelarating_voltage, camera_length=camera_length, index_error_tol=index_error_tol, method=method, vary_angles=vary_angles, vary_center=vary_center, vary_scale=vary_scale, verbose=verbose, ) top_matches[i] = result[0] res_rhkls.append(result[1]) res = np.empty(2, dtype=np.object) res[0] = top_matches res[1] = np.asarray(res_rhkls) return res
def crystal_from_vector_matching(z_matches): """Takes vector matching results for a single navigation position and returns the best matching phase and orientation with correlation and reliability to define a crystallographic map. Parameters ---------- z_matches : numpy.array Template matching results in an array of shape (m,5) sorted by total_error (ascending) within each phase, with entries [phase, R, match_rate, ehkls, total_error] Returns ------- results_array : numpy.array Crystallographic mapping results in an array of shape (3) with entries [phase, np.array((z, x, z)), dict(metrics)] """ if z_matches.shape == (1,): # pragma: no cover z_matches = z_matches[0] # Create empty array for results. results_array = np.empty(3, dtype="object") # get best matching phase best_match = get_nth_best_solution( z_matches, "vector", key="total_error", descending=False ) results_array[0] = best_match.phase_index # get best matching orientation Euler angles results_array[1] = np.rad2deg(mat2euler(best_match.rotation_matrix, "rzxz")) # get vector matching metrics metrics = dict() metrics["match_rate"] = best_match.match_rate metrics["ehkls"] = best_match.error_hkls metrics["total_error"] = best_match.total_error # get second highest correlation phase for phase_reliability (if present) other_phase_matches = [ match for match in z_matches if match.phase_index != best_match.phase_index ] if other_phase_matches: second_best_phase = sorted( other_phase_matches, key=attrgetter("total_error"), reverse=False )[0] metrics["phase_reliability"] = 100 * ( 1 - best_match.total_error / second_best_phase.total_error ) # get second best matching orientation for orientation_reliability same_phase_matches = [ match for match in z_matches if match.phase_index == best_match.phase_index ] second_match = sorted( same_phase_matches, key=attrgetter("total_error"), reverse=False )[1] else: # get second best matching orientation for orientation_reliability second_match = get_nth_best_solution( z_matches, "vector", rank=1, key="total_error", descending=False ) metrics["orientation_reliability"] = 100 * ( 1 - best_match.total_error / (second_match.total_error or 1.0) ) results_array[2] = metrics return results_array