def test_get_input_variable(self, var_type): question = "How few are too few coffee cups?" answer = "1" with replace_stdin(io.StringIO(answer)): if isinstance(var_type, int): with pytest.raises(EOFError): _ = _get_input_variable(question, var_type) return 0 else: returns = _get_input_variable(question, var_type) assert returns == var_type(answer)
def file_writer( filename: str, signal, add_scan: Optional[bool] = None, scan_number: int = 1, **kwargs, ): """Write an :class:`~kikuchipy.signals.EBSD` or :class:`~kikuchipy.signals.LazyEBSD` signal to an existing, but not open, or new h5ebsd file. Only writing to kikuchipy's h5ebsd format is supported. Parameters ---------- filename Full path of HDF file. signal : kikuchipy.signals.EBSD or kikuchipy.signals.LazyEBSD Signal instance. add_scan Add signal to an existing, but not open, h5ebsd file. If it does not exist it is created and the signal is written to it. scan_number Scan number in name of HDF dataset when writing to an existing, but not open, h5ebsd file. kwargs Keyword arguments passed to :meth:`h5py:Group.require_dataset`. """ # Set manufacturer and version to use in file from kikuchipy.release import version as ver_signal man_ver_dict = {"manufacturer": "kikuchipy", "version": ver_signal} # Open file in correct mode mode = "w" if os.path.isfile(filename) and add_scan: mode = "r+" try: f = h5py.File(filename, mode=mode) except OSError: raise OSError("Cannot write to an already open file.") if os.path.isfile(filename) and add_scan: check_h5ebsd(f) man_file, ver_file = manufacturer_version(f) if man_ver_dict["manufacturer"].lower() != man_file.lower(): f.close() raise IOError( f"Only writing to kikuchipy's (and not {man_file}'s) h5ebsd " "format is supported." ) man_ver_dict["version"] = ver_file # Get valid scan number scans_file = [f[k] for k in f["/"].keys() if "Scan" in k] scan_nos = [int(i.name.split()[-1]) for i in scans_file] for i in scan_nos: if i == scan_number: q = f"Scan {i} already in file, enter another scan number:\n" scan_number = _get_input_variable(q, int) if scan_number is None: raise IOError("Invalid scan number.") else: # File did not exist dict2h5ebsdgroup(man_ver_dict, f["/"], **kwargs) scan_group = f.create_group("Scan " + str(scan_number)) # Create scan dictionary with EBSD and SEM metadata # Add scan size, image size and detector pixel size to dictionary to write data_shape = [1] * 4 # (ny, nx, sy, sx) data_scales = [1] * 4 # (y, x, dy, dx) nav_extent = [0, 1, 0, 1] # (x0, x1, y0, y1) am = signal.axes_manager nav_axes = am.navigation_axes nav_dim = am.navigation_dimension if nav_dim == 1: nav_axis = nav_axes[0] if nav_axis.name == "y": data_shape[0] = nav_axis.size data_scales[0] = nav_axis.scale nav_extent[2:] = am.navigation_extent else: # nav_axis.name == "x" or something else data_shape[1] = nav_axis.size data_scales[1] = nav_axis.scale nav_extent[:2] = am.navigation_extent elif nav_dim == 2: data_shape[:2] = [i.size for i in nav_axes][::-1] data_scales[:2] = [i.scale for i in nav_axes][::-1] nav_extent = am.navigation_extent data_shape[2:] = am.signal_shape data_scales[2:] = [i.scale for i in am.signal_axes] ny, nx, sy, sx = data_shape scale_ny, scale_nx, scale_sy, _ = data_scales md = signal.metadata.deepcopy() sem_node, ebsd_node = metadata_nodes(["sem", "ebsd"]) md.set_item(ebsd_node + ".pattern_width", sx) md.set_item(ebsd_node + ".pattern_height", sy) md.set_item(ebsd_node + ".n_columns", nx) md.set_item(ebsd_node + ".n_rows", ny) md.set_item(ebsd_node + ".step_x", scale_nx) md.set_item(ebsd_node + ".step_y", scale_ny) md.set_item(ebsd_node + ".detector_pixel_size", scale_sy) # Separate EBSD and SEM metadata det_str, ebsd_str = ebsd_node.split(".")[-2:] # Detector and EBSD nodes md_sem = md.get_item(sem_node).copy().as_dictionary() # SEM node as dict md_det = md_sem.pop(det_str) # Remove/assign detector node from SEM node md_ebsd = md_det.pop(ebsd_str) # Phases if md.get_item("Sample.Phases") is None: md = _update_phase_info(md, _phase_metadata()) # Add default phase md_ebsd["Phases"] = md.Sample.Phases.as_dictionary() for phase in md_ebsd["Phases"].keys(): # Ensure coordinates are arrays atom_coordinates = md_ebsd["Phases"][phase]["atom_coordinates"] for atom in atom_coordinates.keys(): atom_coordinates[atom]["coordinates"] = np.array( atom_coordinates[atom]["coordinates"] ) scan = {"EBSD": {"Header": md_ebsd}, "SEM": {"Header": md_sem}} # Write scan dictionary to HDF groups dict2h5ebsdgroup(scan, scan_group) # Write signal to file man_pats = manufacturer_pattern_names() dset_pattern_name = man_pats["kikuchipy"] overwrite_dataset( scan_group.create_group("EBSD/Data"), signal.data.reshape(nx * ny, sy, sx), dset_pattern_name, signal_axes=(2, 1), **kwargs, ) nx_start, nx_stop, ny_start, ny_stop = nav_extent sample_pos = { "y_sample": np.tile(np.linspace(ny_start, ny_stop, ny), nx), "x_sample": np.tile(np.linspace(nx_start, nx_stop, nx), ny), } dict2h5ebsdgroup(sample_pos, scan_group["EBSD/Data"]) f.close()