def test_rotate_tsl2bruker(self, r_tsl2bruker): s_tilt = 70 d_tilt = 10 r_tsl_matrix = detector2sample(sample_tilt=s_tilt, detector_tilt=d_tilt) r_tsl = Rotation.from_matrix(r_tsl_matrix) r_bruker_matrix = detector2sample( sample_tilt=s_tilt, detector_tilt=d_tilt, convention="bruker" ) r_bruker = Rotation.from_matrix(r_bruker_matrix) assert np.allclose((~r_tsl2bruker * r_tsl).data, r_bruker.data)
def test_passing_results_from_get_patterns(self): s = nickel_ebsd_small() print(s) s.remove_static_background() s.remove_dynamic_background() mp = nickel_ebsd_master_pattern_small(projection="lambert") r = Rotation([ [0.9522, -0.0151, -0.2883, 0.1001], # Left grain [0.9534, 0.0465, -0.2187, -0.2026], # Right grain [0.8876, -0.2312, 0.3364, -0.2131], # 50th best match ]) detector = EBSDDetector( shape=s.axes_manager.signal_shape[::-1], pc=[0.421, 0.7794, 0.5049], convention="tsl", sample_tilt=70, ) sim = mp.get_patterns(rotations=r, detector=detector, energy=20) xmap = s.match_patterns(sim, keep_n=1) scores = xmap.scores.reshape(xmap.size, ) sim_idx = xmap.simulation_indices.reshape(xmap.size, ) assert np.allclose( scores, [0.197, 0.188, 0.207, 0.198, 0.186, 0.225, 0.191, 0.191, 0.206], atol=1e-3, ) assert np.allclose(sim_idx, [0, 1, 1, 0, 1, 1, 0, 1, 1])
def test_get_item( self, nickel_ebsd_simulation_generator, nav_idx, desired_shape, desired_pc, desired_rotation, ): """Desired PC and rotation values from __getitem__().""" simgen = nickel_ebsd_simulation_generator simgen.navigation_shape = (5, 5) simgen.detector.pc[nav_idx] = desired_pc r = Rotation.from_euler(desired_rotation) simgen.rotations[nav_idx] = r simgen2 = simgen[nav_idx] assert simgen2.navigation_shape == desired_shape assert np.allclose(simgen2.detector.pc, desired_pc) assert np.allclose(simgen2.rotations.data, r.data) new_pc = [ 0.5, ] * 3 simgen2.detector.pc[0] = new_pc assert not np.allclose(simgen[nav_idx].detector.pc, simgen2.detector.pc)
def to_crystal_map(self): """ Exports an indexation result with multiple results per navigation position to crystal map with one result per pixel Returns ------- orix.CrystalMap """ _s = self.data.map(_get_best_match,inplace=False) """ Gets properties """ phase_id = _s.isig[0].data.flatten() alpha = _s.isig[1].data.flatten() beta = _s.isig[2].data.flatten() gamma = _s.isig[3].data.flatten() score = _s.isig[4].data.flatten() """ Gets navigation placements """ xy = np.indices(_s.data.shape[:2]) x = xy[1].flatten() y = xy[0].flatten() """ Tidies up so we can put these things into CrystalMap """ euler = np.vstack((alpha,beta,gamma)).T rotations = Rotation.from_euler(euler,convention="bunge", direction="crystal2lab") properties = {"score":score} return CrystalMap( rotations=rotations, phase_id=phase_id, x=x, y=y, prop=properties)
def test_detector_azimuthal(self): """Test that setting an azimuthal angle of a detector results in different patterns. """ det1 = self.detector # Looking from the detector toward the sample, the left part of # the detector is closer to the sample than the right part det2 = det1.deepcopy() det2.azimuthal = 10 # Looking from the detector toward the sample, the right part of # the detector is closer to the sample than the left part det3 = det1.deepcopy() det3.azimuthal = -10 mp = nickel_ebsd_master_pattern_small(projection="lambert") r = Rotation.identity() kwargs = dict(rotations=r, energy=20, compute=True, dtype_out=np.uint8) sim1 = mp.get_patterns(detector=det1, **kwargs) sim2 = mp.get_patterns(detector=det2, **kwargs) sim3 = mp.get_patterns(detector=det3, **kwargs) assert not np.allclose(sim1.data, sim2.data) assert np.allclose(sim2.data.mean(), 43.56, atol=1e-2) assert np.allclose(sim3.data.mean(), 43.39, atol=1e-2)
def test_get_patterns_navigation_shape_raises(self): mp = nickel_ebsd_master_pattern_small(projection="lambert") r = Rotation(np.random.uniform(low=0, high=1, size=(1, 2, 3, 4))) detector = kp.detectors.EBSDDetector(shape=(60, 60)) with pytest.raises(ValueError, match="`rotations` can only have one or two "): _ = mp.get_patterns(rotations=r, detector=detector, energy=20)
def rotate(self, axis=None, angle=0): """Convenience function for rotating this vector. Shapes of 'axis' and 'angle' must be compatible with shape of this vector for broadcasting. Parameters ---------- axis : Vector3d or array_like, optional The axis of rotation. Defaults to the z-vector. angle : array_like, optional The angle of rotation, in radians. Returns ------- Vector3d A new vector with entries rotated. Examples -------- >>> from math import pi >>> v = Vector3d((0, 1, 0)) >>> axis = Vector3d((0, 0, 1)) >>> angles = [0, pi/4, pi/2, 3*pi/4, pi] >>> v.rotate(axis=axis, angle=angles) """ # Import here to avoid circular import from orix.quaternion import Rotation from orix.vector.neo_euler import AxAngle axis = Vector3d.zvector() if axis is None else axis angle = 0 if angle is None else angle q = Rotation.from_neo_euler(AxAngle.from_axes_angles(axis, angle)) return q * self
def test_get_orientation_similarity_map(self): s = nickel_ebsd_small() s_dict1 = EBSD(s.data.reshape(-1, 60, 60)) s_dict2 = EBSD(s.data.reshape(-1, 60, 60)) n_patterns = s_dict1.axes_manager.navigation_size s_dict1._xmap = CrystalMap(Rotation(np.zeros((n_patterns, 4)))) s_dict2._xmap = CrystalMap(Rotation(np.zeros((n_patterns, 4)))) s_dict1.xmap.phases[0].name = "a" s_dict2.xmap.phases[0].name = "b" sd = StaticPatternMatching([s_dict1, s_dict2]) res = sd(s, keep_n=1, get_orientation_similarity_map=True) xmap1, _ = res assert np.allclose(xmap1.scores, 1) assert np.all(["osm" in xmap.prop for xmap in res])
def test_orientation_similarity_map(self): xmap = CrystalMap( rotations=Rotation(np.zeros((100, 4))), prop={"simulation_indices": np.tile(np.arange(5), (100, 1))}, x=np.tile(np.arange(10), 10), y=np.tile(np.arange(10), 10), ) assert np.allclose(orientation_similarity_map(xmap), np.ones((10, 10)))
def test_merging_refined_maps(self): ny, nx = (3, 3) nav_size = ny * nx r = Rotation.from_euler(np.ones((nav_size, 3))) x = np.tile(np.arange(ny), nx) y = np.repeat(np.arange(nx), ny) # Simulation indices n_sim_indices = 10 sim_indices1 = np.random.randint(low=0, high=1000, size=n_sim_indices * nav_size).reshape( (nav_size, n_sim_indices)) sim_indices2 = np.random.randint(low=0, high=1000, size=n_sim_indices * nav_size).reshape( (nav_size, n_sim_indices)) # Scores scores1 = np.ones(nav_size) scores1[0] = 3 scores2 = 2 * np.ones(nav_size) xmap1 = CrystalMap( rotations=r, phase_id=np.ones(nav_size) * 0, phase_list=PhaseList(Phase(name="a")), x=x, y=y, prop={ "simulation_indices": sim_indices1, "scores": scores1 }, ) xmap2 = CrystalMap( rotations=r, phase_id=np.ones(nav_size), phase_list=PhaseList(Phase(name="b")), x=x, y=y, prop={ "simulation_indices": sim_indices2, "scores": scores2 }, ) xmap_merged = merge_crystal_maps(crystal_maps=[xmap1, xmap2]) assert "simulation_indices" not in xmap_merged.prop.keys() assert "merged_simulation_indices" not in xmap_merged.prop.keys() with pytest.raises(ValueError, match="Cannot merge maps with more"): _ = merge_crystal_maps( crystal_maps=[xmap1, xmap2], simulation_indices_prop="simulation_indices", )
def test_get_patterns_dtype(self): r = Rotation.identity() mp = nickel_ebsd_master_pattern_small(projection="lambert") dtype_out = np.dtype("float64") pattern = mp.get_patterns(rotations=r, detector=self.detector, energy=20, dtype_out=dtype_out) assert pattern.data.dtype == dtype_out
def test_n_best_too_great(self): xmap = CrystalMap( rotations=Rotation(np.zeros((100, 4))), prop={"simulation_indices": np.ones((100, 5))}, x=np.tile(np.arange(10), 10), y=np.tile(np.arange(10), 10), ) with pytest.raises(ValueError, match="n_best 6 cannot be greater than"): orientation_similarity_map(xmap, n_best=6)
def compute_refine_orientation_projection_center_results( results: list, detector, xmap: CrystalMap, master_pattern, ): """Compute the results from :meth:`~kikuchipy.signals.EBSD.refine_orientation_projection_center` and return the :class:`~orix.crystal_map.CrystalMap` and :class:`~kikuchipy.detectors.EBSDDetector`. Parameters ---------- results Results returned from `refine_orientation_projection_center()`, which is a list of :class:`~dask.delayed.Delayed`. detector : ~kikuchipy.detectors.EBSDDetector Detector passed to `refine_orientation_projection_center()` to obtain `results`. xmap Crystal map passed to `refine_orientation_projection_center()` to obtain `results`. master_pattern : ~kikuchipy.signals.EBSDMasterPattern Master pattern passed to `refine_orientation_projection_center()` to obtain `results`. Returns ------- xmap_refined : :class:`~orix.crystal_map.CrystalMap` Crystal map with refined orientations and scores. new_detector : :class:`~kikuchipy.detectors.EBSDDetector` EBSD detector with refined projection center parameters. """ n_patterns = len(results) nav_shape = xmap.shape with ProgressBar(): print( f"Refining {n_patterns} orientation(s) and projection center(s):", file=sys.stdout, ) computed_results = dask.compute(*results) computed_results = np.array(computed_results) # (n, score, phi1, Phi, phi2, PCx, PCy, PCz) xmap_refined = CrystalMap( rotations=Rotation.from_euler(computed_results[:, 1:4]), phase_id=np.zeros(n_patterns), x=xmap.x, y=xmap.y, phase_list=PhaseList(phases=master_pattern.phase), prop=dict(scores=computed_results[:, 0]), scan_unit=xmap.scan_unit, ) new_detector = detector.deepcopy() new_detector.pc = computed_results[:, 4:].reshape(nav_shape + (3, )) return xmap_refined, new_detector
def test_signal_varying_dimensions(self, dummy_signal, slices, desired_xmap_shape): s = dummy_signal.inav[slices] sig_shape = dummy_signal.axes_manager.signal_shape s_dict1 = EBSD(dummy_signal.data.reshape((-1, ) + sig_shape)) n_sim = s_dict1.axes_manager.navigation_size s_dict1._xmap = CrystalMap(Rotation(np.zeros((n_sim, 4)))) sd = StaticPatternMatching(s_dict1) res = sd(s) assert res.shape == desired_xmap_shape
def to_crystal_map(self): """Obtain a crystallographic map specifying the best matching phase and orientation at each probe position with corresponding metrics. Raises ------- ValueError("Currently under development") """ raise ValueError("Currently under development") _s = self.map( crystal_from_vector_matching, inplace=False) """ Gets phase, the easy bit """ phase_id = _s.isig[0].data.flatten() """ Deals with the properties, hard coded as of v0.13 """ # need to invert an array of dicts into a dict of arrays def _map_to_get_property(prop): return d[prop] # assume same properties at every point of the signal key_list = [] for key in _s.inav[0,0].isig[2]: key_list.append(key) properties = {} for key in key_list: _key_signal = _s.isig[2].map(_map_to_get_property,prop=key,inplace=False) properties[key] = _key_signal """ Deal with the rotations """ def _map_for_alpha_beta_gamma(ix): return z[ix] alpha = _s.isig[1].map(_map_for_alpha_beta_gamma,ix=0,inplace=False) beta = _s.isig[1].map(_map_for_alpha_beta_gamma,ix=1,inplace=False) gamma = _s.isig[1].map(_map_for_alpha_beta_gamma,ix=2,inplace=False) euler = np.vstack((alpha,beta,gamma)).T rotations = Rotation.from_euler(euler,convention="bunge", direction="crystal2lab") """ Gets navigation placements """ xy = np.indices(_s.data.shape[:2]) x = xy[1].flatten() y = xy[0].flatten() return CrystalMap( rotations=rotations, phase_id=phase_id, x=x, y=y, prop=properties)
def test_from_n_best(self): sim_idx_prop = "simulated_indices" xmap = CrystalMap( rotations=Rotation(np.zeros((100, 4))), prop={sim_idx_prop: np.ones((100, 5))}, x=np.tile(np.arange(10), 10), y=np.tile(np.arange(10), 10), ) osm = orientation_similarity_map(xmap, simulation_indices_prop=sim_idx_prop, from_n_best=2) assert osm.shape == (10, 10, 4)
def test_keep_n(self, n_rot_in, n_rot_out, keep_n): s = nickel_ebsd_small() s_dict = EBSD(np.random.random((n_rot_in, 60, 60)).astype(np.float32)) s_dict._xmap = CrystalMap(Rotation(np.zeros((n_rot_in, 4)))) sd = StaticPatternMatching(s_dict) xmap = sd(s) assert xmap.rotations_per_point == n_rot_out xmap2 = sd(s, keep_n=keep_n) assert xmap2.rotations_per_point == keep_n
def test_n_slices_input(self, dummy_signal): sig_shape = dummy_signal.axes_manager.signal_shape n_px = np.prod(sig_shape) n_sim = 13500 + 1 rand_data = (np.random.randint( 0, 255, n_sim * n_px).reshape((n_sim, ) + sig_shape).astype(np.uint8)) s_dict1 = EBSD(rand_data) s_dict1._xmap = CrystalMap(Rotation(np.zeros((n_sim, 4)))) sd = StaticPatternMatching(s_dict1) with replace_stdin(io.StringIO("y")): res = sd(dummy_signal, n_slices=1) assert isinstance(res, CrystalMap) with replace_stdin(io.StringIO("n")): res = sd(dummy_signal, n_slices=1) assert res is None
def test_simulated_patterns_xmap_detector(self): mp = nickel_ebsd_master_pattern_small(projection="lambert") r = Rotation.from_euler([[0, 0, 0], [0, np.pi / 2, 0]]) detector = EBSDDetector( shape=(60, 60), pc=[0.5, 0.5, 0.5], sample_tilt=70, convention="tsl", ) s = mp.get_patterns(rotations=r, detector=detector, energy=20) assert np.allclose(s.xmap.rotations.to_euler(), r.to_euler()) assert s.xmap.phases.names == [mp.phase.name] assert s.xmap.phases[0].point_group.name == mp.phase.point_group.name assert s.detector.shape == detector.shape assert np.allclose(s.detector.pc, detector.pc) assert s.detector.sample_tilt == detector.sample_tilt
async def preview_dictionary(req: DictionaryIndexingIn): if req.ebsd_info.uid not in kp_signals: raise HTTPException(status_code=404, detail="Patterns not found") s = kp_signals[req.ebsd_info.uid] detector = kp.detectors.EBSDDetector( shape=s.axes_manager.signal_shape[::-1], pc=req.detector.pc, sample_tilt=req.detector.sample_tilt, convention=req.detector.pc_convention, tilt=req.detector.camera_tilt, ) res = PreviewDictionary(patterns=[]) if req.preview_angles: euler = np.array(req.preview_angles) else: euler = np.array([0.0, 0.0, 0.0]) for mp_req in req.masterpatterns: mp = kp.load( mp_req.filepath, projection=mp_req.projection, hemisphere="both", energy=mp_req.energy, ) sim = mp.get_patterns( rotations=Rotation.from_euler(np.deg2rad(euler)), detector=detector, energy=mp_req.energy, compute=True, ) svg_string = io.StringIO() plt.figure() plt.imshow(sim.data[0], cmap="gray") plt.title( f"{mp.phase.name.capitalize()}\n($\phi_1, \Phi, \phi_2)$ = {np.array_str(euler, precision=1)}" ) plt.axis("off") plt.savefig(svg_string, format="svg", bbox_inches="tight", transparent=True) svg_string.seek(0) res.patterns.append(svg_string.getvalue()) return res
def test_get_patterns_chunk(self): r = Rotation.from_euler(((0, 0, 0), (1, 1, 1), (2, 2, 2))) dc = _get_direction_cosines(self.detector) mpn = np.empty((1001, 1001)) mps = mpn npx = 1001 npy = npx out = _get_patterns_chunk( rotations_array=r.data, dc=dc, master_north=mpn, master_south=mps, npx=npx, npy=npy, scale=(npx - 1) / 2, rescale=False, ) assert out.shape == r.shape + dc.shape
def compute_refine_orientation_results(results: list, xmap: CrystalMap, master_pattern): """Compute the results from :meth:`~kikuchipy.signals.EBSD.refine_orientation` and return the :class:`~orix.crystal_map.CrystalMap`. Parameters ---------- results Results returned from `refine_orientation()`, which is a list of :class:`~dask.delayed.Delayed`. xmap Crystal map passed to `refine_orientation()` to obtain `results`. master_pattern : ~kikuchipy.signals.EBSDMasterPattern Master pattern passed to `refine_orientation()` to obtain `results`. Returns ------- refined_xmap : :class:`~orix.crystal_map.CrystalMap` Crystal map with refined orientations and scores. """ n_patterns = len(results) with ProgressBar(): print(f"Refining {n_patterns} orientation(s):", file=sys.stdout) computed_results = dask.compute(*results) # (n, score, phi1, Phi, phi2) computed_results = np.array(computed_results) xmap_refined = CrystalMap( rotations=Rotation.from_euler(computed_results[:, 1:]), phase_id=np.zeros(n_patterns), x=xmap.x, y=xmap.y, phase_list=PhaseList(phases=master_pattern.phase), prop=dict(scores=computed_results[:, 0]), scan_unit=xmap.scan_unit, ) return xmap_refined
def test_project_patterns_from_master_pattern(self): """Make sure the Numba function is covered.""" r = Rotation.from_euler(((0, 0, 0), (1, 1, 1), (2, 2, 2))) dc = _get_direction_cosines_for_single_pc_from_detector(self.detector) npx = npy = 101 mpn = mps = np.zeros((npy, npx)) patterns = _project_patterns_from_master_pattern.py_func( rotations=r.data, direction_cosines=dc, master_north=mpn, master_south=mps, npx=npx, npy=npy, scale=float((npx - 1) / 2), dtype_out=mpn.dtype, rescale=False, # Aren't used out_min=1, out_max=2, ) assert patterns.shape == r.shape + dc.shape[:-1]
def test_return_merged_crystal_map(self, return_merged_xmap, desired_n_xmaps_out): s = nickel_ebsd_small() s_dict1 = EBSD(s.data.reshape(-1, 60, 60)) s_dict2 = s_dict1.deepcopy() n_patterns = s_dict1.axes_manager.navigation_size s_dict1._xmap = CrystalMap(Rotation(np.zeros((n_patterns, 4)))) s_dict2._xmap = s_dict1.xmap.deepcopy() s_dict1.xmap.phases[0].name = "a" s_dict2.xmap.phases[0].name = "b" sd = StaticPatternMatching([s_dict1, s_dict2]) res1 = sd(s, return_merged_crystal_map=return_merged_xmap) assert len(res1) == desired_n_xmaps_out sd.dictionaries.pop(-1) res2 = sd(s, return_merged_crystal_map=True) assert isinstance(res2, CrystalMap) res3 = sd(s) assert isinstance(res3, CrystalMap)
def test_get_patterns(self): # Ni Test EMSOFT_EBSD_FILE = os.path.join( DIR_PATH, "../../data/emsoft_ebsd/EBSD_TEST_Ni.h5") emsoft_key = load(EMSOFT_EBSD_FILE) emsoft_key = emsoft_key.data[0] angles = np.array((120, 45, 60)) r = Rotation.from_euler(np.radians(angles)) kp_mp = nickel_ebsd_master_pattern_small(projection="lambert", hemisphere="both") kp_pattern = kp_mp.get_patterns(rotations=r, detector=self.detector, energy=20, dtype_out=np.uint8) kp_pat = kp_pattern.data[0].compute() ncc1 = ncc(kp_pat, emsoft_key) ndp1 = ndp(kp_pat, emsoft_key) assert ncc1 >= 0.935 assert ndp1 >= 0.935 detector_shape = self.detector.shape r2 = Rotation.from_euler(((0, 0, 0), (1, 1, 1), (2, 2, 2))) mp_a = EBSDMasterPattern(np.zeros((2, 10, 11, 11))) print(mp_a.axes_manager) mp_a.axes_manager[0].name = "hemisphere" mp_a.axes_manager[1].name = "energy" mp_a.projection = "lambert" mp_a.phase = Phase("Ni", 225) out_a = mp_a.get_patterns(r2, self.detector, 5) assert isinstance(out_a, LazyEBSD) desired_data_shape = (3, ) + detector_shape[::-1] assert out_a.axes_manager.shape == desired_data_shape mp_b = EBSDMasterPattern(np.zeros((10, 11, 11))) mp_b.axes_manager[0].name = "energy" mp_b.projection = "lambert" mp_b.phase = Phase("Ni", 225) out_b = mp_b.get_patterns(r2, self.detector, 5) assert isinstance(out_b, LazyEBSD) assert out_b.axes_manager.shape == desired_data_shape mp_c = EBSDMasterPattern(np.zeros((11, 11))) mp_c.projection = "lambert" mp_c.phase = Phase("Ni", 225) out_c = mp_c.get_patterns(r2, self.detector, 5) out_c_2 = mp_c.get_patterns(r2, self.detector, 5, compute=True) assert isinstance(out_c, LazyEBSD) assert isinstance(out_c_2, EBSD) assert out_c.axes_manager.shape == desired_data_shape mp_c2 = EBSDMasterPattern(np.zeros((11, 11))) mp_c2.projection = "lambert" mp_c2.phase = Phase("!Ni", 220) with pytest.raises(AttributeError): mp_c2.get_patterns(r2, self.detector, 5) mp_d = EBSDMasterPattern(np.zeros((2, 11, 11))) with pytest.raises(NotImplementedError): mp_d.get_patterns(r2, self.detector, 5) mp_e = EBSDMasterPattern(np.zeros((10, 11, 11))) mp_e.axes_manager[0].name = "energy" mp_e.projection = "lambert" mp_e.phase = Phase("!Ni", 220) with pytest.raises(AttributeError): mp_e.get_patterns(r2, self.detector, 5) # More than one Projection center is currently not supported so # it should fail d2 = EBSDDetector( shape=(10, 10), px_size=50, pc=((0, 0, 15000), (0, 0, 15000)), convention="emsoft4", tilt=0, sample_tilt=70, ) with pytest.raises(NotImplementedError): mp_c.get_patterns(r2, d2, 5)
def _get_patterns_chunk( rotations_array: np.ndarray, dc: Vector3d, master_north: np.ndarray, master_south: np.ndarray, npx: int, npy: int, scale: Union[int, float], rescale: bool, dtype_out: Optional[type] = np.float32, ) -> np.ndarray: """Get the EBSD patterns on the detector for each rotation in the chunk. Each pattern is found by a bi-quadratic interpolation of the master pattern as described in EMsoft. Parameters ---------- rotations_array Array of rotations of shape (..., 4) for a given chunk in quaternions. dc Direction cosines unit vector between detector and sample. master_north Northern hemisphere of the master pattern. master_south Southern hemisphere of the master pattern. npx Number of pixels in the x-direction on the master pattern. npy Number of pixels in the y-direction on the master pattern. scale Factor to scale up from square Lambert projection to the master pattern. rescale Whether to call rescale_intensities() or not. dtype_out Data type of the returned patterns, by default np.float32. Returns ------- numpy.ndarray 3D or 4D array with simulated patterns. """ rotations = Rotation(rotations_array) rotations_shape = rotations_array.shape[:-1] simulated = np.empty(shape=rotations_shape + dc.shape, dtype=dtype_out) for i in np.ndindex(rotations_shape): rotated_dc = rotations[i] * dc ( nii, nij, niip, nijp, di, dj, dim, djm, ) = _get_lambert_interpolation_parameters( rotated_direction_cosines=rotated_dc, npx=npx, npy=npy, scale=scale, ) pattern = np.where( rotated_dc.z >= 0, ( master_north[nii, nij] * dim * djm + master_north[niip, nij] * di * djm + master_north[nii, nijp] * dim * dj + master_north[niip, nijp] * di * dj ), ( master_south[nii, nij] * dim * djm + master_south[niip, nij] * di * djm + master_south[nii, nijp] * dim * dj + master_south[niip, nijp] * di * dj ), ) if rescale: pattern = rescale_intensity(pattern, dtype_out=dtype_out) simulated[i] = pattern return simulated
def file_reader( filename: str, scan_size: Union[None, int, Tuple[int, ...]] = None, lazy: bool = False, **kwargs, ) -> List[dict]: """Read dynamically simulated electron backscatter diffraction patterns from EMsoft's format produced by their EMEBSD.f90 program. Parameters ---------- filename Full file path of the HDF file. scan_size Scan size in number of patterns in width and height. lazy Open the data lazily without actually reading the data from disk until requested. Allows opening datasets larger than available memory. Default is False. kwargs : Keyword arguments passed to h5py.File. Returns ------- signal_dict_list: list of dicts Data, axes, metadata and original metadata. """ mode = kwargs.pop("mode", "r") f = File(filename, mode=mode, **kwargs) _check_file_format(f) # Read original metadata omd = hdf5group2dict(f["/"], data_dset_names=["EBSDPatterns"], recursive=True) # Set metadata and original metadata dictionaries md = _get_metadata(omd) md.update({ "Signal": { "signal_type": "EBSD", "record_by": "image" }, "General": { "title": f.filename.split("/")[-1].split(".")[0], "original_filename": f.filename.split("/")[-1], }, }) scan = {"metadata": md, "original_metadata": omd} # Read patterns dataset = f["EMData/EBSD/EBSDPatterns"] if lazy: chunks = "auto" if dataset.chunks is None else dataset.chunks patterns = da.from_array(dataset, chunks=chunks) else: patterns = np.asanyarray(dataset) # Reshape data if desired sy = omd["NMLparameters"]["EBSDNameList"]["numsy"] sx = omd["NMLparameters"]["EBSDNameList"]["numsx"] if scan_size is not None: if isinstance(scan_size, int): new_shape = (scan_size, sy, sx) else: new_shape = scan_size + (sy, sx) patterns = patterns.reshape(new_shape) scan["data"] = patterns # Set navigation and signal axes pixel_size = omd["NMLparameters"]["EBSDNameList"]["delta"] ndim = patterns.ndim units = ["px", "um", "um"] names = ["x", "dy", "dx"] scales = np.array([1, pixel_size, pixel_size]) if ndim == 4: units = ["px"] + units names = ["y"] + names scales = np.append([1], scales) scan["axes"] = [{ "size": patterns.shape[i], "index_in_array": i, "name": names[i], "scale": scales[i], "offset": 0, "units": units[i], } for i in range(patterns.ndim)] # Get crystal map phase = _crystaldata2phase(hdf5group2dict(f["CrystalData"])) xtal_fname = f["EMData/EBSD/xtalname"][()][0].decode().split("/")[-1] phase.name, _ = os.path.splitext(xtal_fname) scan["xmap"] = CrystalMap( rotations=Rotation.from_euler(f["EMData/EBSD/EulerAngles"][()]), phase_list=PhaseList(phase), ) if not lazy: f.close() return [scan]
def test_results_dict_to_crystal_map(test_library_phases_multi, test_lib_gen): """Test getting a :class:`orix.crystal_map.CrystalMap` from returns from :func:`index_dataset_with_template_rotation`. """ # Map and signal shapes nav_shape = (2, 3) sig_shape = (80, 80) test_set = np.zeros(nav_shape + sig_shape) # Diffraction conditions diff_lib = test_lib_gen.get_diffraction_library( test_library_phases_multi, calibration=0.015, reciprocal_radius=1.18, half_shape=tuple(np.array(sig_shape) // 2), with_direct_beam=False, ) # Simulate multi-phase results phase_id = np.zeros(nav_shape, dtype=int) phase_id[:, [0, 2]] = 1 phase_names = list(diff_lib.keys()) # Simulate patterns sim_kwargs = dict(size=sig_shape[0], sigma=4) for idx in np.ndindex(*nav_shape): i = phase_id[idx] j = int(idx[1] / 2) test_pattern = diff_lib[phase_names[i]]["simulations"][j].\ get_diffraction_pattern(**sim_kwargs) test_set[idx] = test_pattern # Perform template matching n_best = 3 results, phase_dict = index_dataset_with_template_rotation( Signal2D(test_set), diff_lib, phases=phase_names, n_best=n_best, ) # Extract various results once phase_id = results["phase_index"].reshape((-1, n_best)) ori = np.deg2rad(results["orientation"].reshape((-1, n_best, 3))) # Property names in `results` prop_names = ["correlation", "mirrored_template", "template_index"] # Only get the bast match when multiple phases match best to some # patterns xmap = results_dict_to_crystal_map(results, phase_dict, diffraction_library=diff_lib) assert np.allclose(xmap.phase_id, phase_id[:, 0]) assert xmap.rotations_per_point == 1 assert xmap.phases.names == phase_names assert (xmap.phases.structures[0].lattice.abcABG() == test_library_phases_multi.structures[0].lattice.abcABG()) # Raise warning when a property is not present as expected del results[prop_names[0]] with pytest.warns(UserWarning, match=f"Property '{prop_names[0]}' was expected"): xmap2 = results_dict_to_crystal_map(results, phase_dict, diffraction_library=diff_lib) assert list(xmap2.prop.keys()) == prop_names[1:] # Raise error when trying to access a best match which isn't # available with pytest.raises(ValueError, match="`index` cannot be higher than 2"): _ = results_dict_to_crystal_map(results, phase_dict, index=3) # Get second best match i = 1 xmap3 = results_dict_to_crystal_map(results, phase_dict, index=i) assert xmap3.rotations_per_point == 1 assert np.allclose(xmap3.phase_id, phase_id[:, i]) assert np.allclose(xmap3.rotations.data, Rotation.from_euler(ori[:, i]).data) assert np.allclose(xmap3.prop[prop_names[1]], results[prop_names[1]][:, :, i].flatten()) # Make map single-phase and get all matches per point results["phase_index"][..., 0] = 0 xmap4 = results_dict_to_crystal_map(results, phase_dict) assert np.all(xmap4.phase_id == 0) assert xmap4.phases.names[0] == phase_names[0] assert xmap4.rotations_per_point == 3 # Get only best match even though map is single-phase i = 0 xmap5 = results_dict_to_crystal_map(results, phase_dict, index=i) assert xmap5.rotations_per_point == 1 assert np.allclose(xmap5.rotations.data, Rotation.from_euler(ori[:, i]).data) assert np.allclose(xmap5.prop[prop_names[1]], results[prop_names[1]][:, :, i].flatten())
def test_get_patterns_navigation_shape(self, nav_shape): mp = nickel_ebsd_master_pattern_small(projection="lambert") r = Rotation(np.random.uniform(low=0, high=1, size=nav_shape + (4, ))) detector = EBSDDetector(shape=(60, 60)) sim = mp.get_patterns(rotations=r, detector=detector, energy=20) assert sim.axes_manager.navigation_shape[::-1] == nav_shape
def test_get_patterns(self): emsoft_key = load(EMSOFT_EBSD_FILE) emsoft_key = emsoft_key.data[0] r = Rotation.from_euler(np.radians([120, 45, 60])) mp1 = nickel_ebsd_master_pattern_small(projection="lambert", hemisphere="both") kp_pattern = mp1.get_patterns(rotations=r, detector=self.detector, energy=20, dtype_out=emsoft_key.dtype) kp_pat = kp_pattern.data[0].compute() assert kp_pat.dtype == emsoft_key.dtype ncc = NormalizedCrossCorrelationMetric(1, 1) ncc1 = ncc(kp_pat, emsoft_key) assert ncc1 >= 0.935 ndp = NormalizedDotProductMetric(1, 1) ndp1 = ndp(kp_pat, emsoft_key) assert ndp1 >= 0.935 detector_shape = self.detector.shape r2 = Rotation.from_euler(((0, 0, 0), (1, 1, 1), (2, 2, 2))) mp2 = kp.signals.EBSDMasterPattern(np.zeros((2, 10, 11, 11))) mp2.axes_manager[0].name = "hemisphere" mp2.axes_manager[1].name = "energy" mp2.projection = "lambert" mp2.phase = Phase("Ni", 225) out2 = mp2.get_patterns(r2, self.detector, 5) assert isinstance(out2, kp.signals.LazyEBSD) desired_data_shape = (3, ) + detector_shape[::-1] assert out2.axes_manager.shape == desired_data_shape mp3 = kp.signals.EBSDMasterPattern(np.zeros((10, 11, 11))) mp3.axes_manager[0].name = "energy" mp3.projection = "lambert" mp3.phase = Phase("Ni", 225) out3 = mp3.get_patterns(r2, self.detector, 5) assert isinstance(out3, kp.signals.LazyEBSD) assert out3.axes_manager.shape == desired_data_shape mp4 = kp.signals.EBSDMasterPattern(np.zeros((11, 11))) mp4.projection = "lambert" mp4.phase = Phase("Ni", 225) out41 = mp4.get_patterns(r2, self.detector, 5) out42 = mp4.get_patterns(r2, self.detector, 5, compute=True) assert isinstance(out41, kp.signals.LazyEBSD) assert isinstance(out42, kp.signals.EBSD) assert out41.axes_manager.shape == desired_data_shape mp5 = kp.signals.EBSDMasterPattern(np.zeros((11, 11))) mp5.projection = "lambert" mp5.phase = Phase("!Ni", 220) with pytest.raises(AttributeError): _ = mp5.get_patterns(r2, self.detector, 5) mp6 = kp.signals.EBSDMasterPattern(np.zeros((2, 11, 11))) with pytest.raises(AttributeError, match="Master pattern `phase` attribute"): _ = mp6.get_patterns(r2, self.detector, 5) mp7 = kp.signals.EBSDMasterPattern(np.zeros((10, 11, 11))) mp7.axes_manager[0].name = "energy" mp7.projection = "lambert" mp7.phase = Phase("!Ni", 220) with pytest.raises(AttributeError, match="For point groups without inversion"): _ = mp7.get_patterns(r2, self.detector, 5) # More than one PC is currently not supported so should fail d2 = kp.detectors.EBSDDetector( shape=(10, 10), px_size=50, pc=((0, 0, 15000), (0, 0, 15000)), convention="emsoft4", sample_tilt=70, ) with pytest.raises(NotImplementedError): _ = mp4.get_patterns(r2, d2, 5)