Example #1
0
def _get_metadata(omd: dict) -> dict:
    """Return metadata dictionary from original metadata dictionary.

    Parameters
    ----------
    omd
        Dictionary with original metadata.

    Returns
    -------
    md
        Dictionary with metadata.
    """
    md = ebsd_metadata()
    sem_node, ebsd_node = metadata_nodes(["sem", "ebsd"])
    md.set_item(f"{ebsd_node}.manufacturer", "EMsoft")
    mapping = {
        f"{ebsd_node}.version": ["EMheader", "EBSD", "Version"],
        f"{ebsd_node}.binning": ["NMLparameters", "EBSDNameList", "binning"],
        f"{ebsd_node}.elevation_angle":
        ["NMLparameters", "EBSDNameList", "thetac"],
        f"{ebsd_node}.exposure_time":
        ["NMLparameters", "EBSDNameList", "dwelltime"],
        f"{ebsd_node}.xpc": ["NMLparameters", "EBSDNameList", "xpc"],
        f"{ebsd_node}.ypc": ["NMLparameters", "EBSDNameList", "ypc"],
        f"{ebsd_node}.zpc": ["NMLparameters", "EBSDNameList", "L"],
        f"{sem_node}.beam_energy":
        ["NMLparameters", "EBSDNameList", "energymax"],
    }
    _set_metadata_from_mapping(omd, md, mapping)
    return md.as_dictionary()
Example #2
0
    def test_init(self):

        # Signal shape
        array0 = np.zeros(shape=(10, 10, 10, 10))
        s0 = EBSD(array0)
        assert array0.shape == s0.axes_manager.shape

        # Cannot initialise signal with one signal dimension
        with pytest.raises(ValueError):
            _ = EBSD(np.zeros(10))

        # Shape of one-image signal
        array1 = np.zeros(shape=(10, 10))
        s1 = EBSD(array1)
        assert array1.shape == s1.axes_manager.shape

        # SEM metadata
        kp_md = ebsd_metadata()
        sem_node = metadata_nodes("sem")
        assert_dictionary(
            kp_md.get_item(sem_node), s1.metadata.get_item(sem_node)
        )

        # Phases metadata
        assert s1.metadata.has_item("Sample.Phases")
Example #3
0
def h5ebsdheader2dicts(
    scan_group: h5py.Group,
    manufacturer: str,
    version: str,
    lazy: bool = False
) -> Tuple[DictionaryTreeBrowser, DictionaryTreeBrowser,
           DictionaryTreeBrowser]:
    """Return three dictionaries in HyperSpy's
    :class:`hyperspy.misc.utils.DictionaryTreeBrowser` format, one
    with the h5ebsd scan header parameters as kikuchipy metadata,
    another with all datasets in the header as original metadata, and
    the last with info about scan size, image size and detector pixel
    size.

    Parameters
    ----------
    scan_group : h5py:Group
        HDF group of scan data and header.
    manufacturer
        Manufacturer of file. Options are
        "kikuchipy"/"EDAX"/"Bruker Nano"
    version
        Version of manufacturer software used to create file.
    lazy
        Read dataset lazily.

    Returns
    -------
    md
        kikuchipy ``metadata`` elements available in file.
    omd
        All metadata available in file.
    scan_size
        Scan, image, step and detector pixel size available in file.
    """
    md = ebsd_metadata()
    title = (scan_group.file.filename.split("/")[-1].split(".")[0] + " " +
             scan_group.name[1:].split("/")[0])
    if len(title) > 20:
        title = "{:.20}...".format(title)
    md.set_item("General.title", title)

    if "edax" in manufacturer.lower():
        md, omd, scan_size = edaxheader2dicts(scan_group, md)
    elif "bruker" in manufacturer.lower():
        md, omd, scan_size = brukerheader2dicts(scan_group, md)
    else:  # kikuchipy
        md, omd, scan_size = kikuchipyheader2dicts(scan_group, md)

    ebsd_node = metadata_nodes("ebsd")
    md.set_item(ebsd_node + ".manufacturer", manufacturer)
    md.set_item(ebsd_node + ".version", version)

    return md, omd, scan_size
Example #4
0
    def test_set_metadata_from_mapping(self):
        """Updating DictionaryTreeBrowser with values from a dictionary
        via a mapping.
        """
        sem_node, ebsd_node = metadata_nodes(["sem", "ebsd"])
        md = ebsd_metadata()

        old_val1, new_val1 = (-1, 20)
        old_val2, new_val2 = (-1, 2)
        omd = {"V": new_val1, "xpc": {"xpc2": {"xpc3": new_val2}}}
        key1 = f"{sem_node}.beam_energy"
        key2 = f"{ebsd_node}.xpc"
        assert md.get_item(key1) == old_val1
        assert md.get_item(key2) == old_val2

        mapping = {key1: "V", key2: ["xpc", "xpc2", "xpc3"]}
        _set_metadata_from_mapping(omd, md, mapping)
        assert md.get_item(key1) == new_val1
        assert md.get_item(key2) == new_val2

        with pytest.warns(UserWarning, match="Could not read"):
            _ = _set_metadata_from_mapping(omd, md, {"a": "b"})
Example #5
0
def file_reader(
    filename: str,
    mmap_mode: Optional[str] = None,
    scan_size: Union[None, int, Tuple[int, ...]] = None,
    pattern_size: Optional[Tuple[int, ...]] = None,
    setting_file: Optional[str] = None,
    lazy: bool = False,
) -> List[Dict]:
    """Read electron backscatter patterns from a NORDIF data file.

    Parameters
    ----------
    filename
        File path to NORDIF data file.
    mmap_mode
    scan_size
        Scan size in number of patterns in width and height.
    pattern_size
        Pattern size in detector pixels in width and height.
    setting_file
        File path to NORDIF setting file (default is `Setting.txt` in
        same directory as ``filename``).
    lazy
        Open the data lazily without actually reading the data from disk
        until required. Allows opening arbitrary sized datasets. Default
        is False.

    Returns
    -------
    scan : list of dicts
        Data, axes, metadata and original metadata.
    """
    if mmap_mode is None:
        mmap_mode = "r" if lazy else "c"

    scan = {}

    # Make sure we open in correct mode
    if "+" in mmap_mode or (
        "write" in mmap_mode and "copyonwrite" != mmap_mode
    ):
        if lazy:
            raise ValueError("Lazy loading does not support in-place writing")
        f = open(filename, mode="r+b")
    else:
        f = open(filename, mode="rb")

    # Get metadata from setting file
    sem_node, ebsd_node = metadata_nodes(["sem", "ebsd"])
    folder, fname = os.path.split(filename)
    if setting_file is None:
        setting_file = os.path.join(folder, "Setting.txt")
    setting_file_exists = os.path.isfile(setting_file)
    if setting_file_exists:
        md, omd, scan_size_file = get_settings_from_file(setting_file)
        if not scan_size:
            scan_size = (scan_size_file.nx, scan_size_file.ny)
        if not pattern_size:
            pattern_size = (scan_size_file.sx, scan_size_file.sy)
    else:
        if scan_size is None and pattern_size is None:
            raise ValueError(
                "No setting file found and no scan_size or pattern_size "
                "detected in input arguments. These must be set if no setting "
                "file is provided."
            )
        md = ebsd_metadata()
        omd = DictionaryTreeBrowser()

    # Read static background image into metadata
    static_bg_file = os.path.join(folder, "Background acquisition pattern.bmp")
    try:
        md.set_item(ebsd_node + ".static_background", imread(static_bg_file))
    except FileNotFoundError:
        warnings.warn(
            f"Could not read static background pattern '{static_bg_file}', "
            "however it can be added using set_experimental_parameters()."
        )

    # Set required and other parameters in metadata
    md.set_item("General.original_filename", filename)
    md.set_item(
        "General.title", os.path.splitext(os.path.split(filename)[1])[0]
    )
    md.set_item("Signal.signal_type", "EBSD")
    md.set_item("Signal.record_by", "image")
    scan["metadata"] = md.as_dictionary()
    scan["original_metadata"] = omd.as_dictionary()

    # Set scan size and image size
    if isinstance(scan_size, int):
        nx = scan_size
        ny = 1
    else:
        nx, ny = scan_size
    sx, sy = pattern_size

    # Read data from file
    data_size = ny * nx * sy * sx
    if not lazy:
        f.seek(0)
        data = np.fromfile(f, dtype="uint8", count=data_size)
    else:
        data = np.memmap(f, mode=mmap_mode, dtype="uint8")

    try:
        data = data.reshape((ny, nx, sy, sx), order="C").squeeze()
    except ValueError:
        warnings.warn(
            "Pattern size and scan size larger than file size! Will attempt to "
            "load by zero padding incomplete frames."
        )
        # Data is stored image by image
        pw = [(0, ny * nx * sy * sx - data.size)]
        data = np.pad(data, pw, mode="constant")
        data = data.reshape((ny, nx, sy, sx))
    scan["data"] = data

    units = ["um"] * 4
    names = ["y", "x", "dy", "dx"]
    scales = np.ones(4)

    # Calibrate scan dimension
    try:
        scales[:2] = scales[:2] * scan_size_file.step_x
    except (TypeError, UnboundLocalError):
        warnings.warn(
            "Could not calibrate scan dimensions, this can be done using "
            "set_scan_calibration()"
        )

    # Create axis objects for each axis
    axes = [
        {
            "size": data.shape[i],
            "index_in_array": i,
            "name": names[i],
            "scale": scales[i],
            "offset": 0.0,
            "units": units[i],
        }
        for i in range(data.ndim)
    ]
    scan["axes"] = axes

    f.close()

    return [
        scan,
    ]
Example #6
0
def get_settings_from_file(
    filename: str,
) -> Tuple[DictionaryTreeBrowser, DictionaryTreeBrowser, DictionaryTreeBrowser]:
    """Return metadata with parameters from NORDIF setting file.

    Parameters
    ----------
    filename
        File path of NORDIF setting file.

    Returns
    -------
    md
        Metadata complying with HyperSpy's metadata structure.
    omd
        Metadata that does not fit into HyperSpy's metadata structure.
    scan_size
        Information on image size, scan size and scan steps.
    """
    f = open(filename, "r", encoding="latin-1")  # Avoid byte strings
    content = f.read().splitlines()

    # Get line numbers of setting blocks
    blocks = {
        "[NORDIF]": -1,
        "[Microscope]": -1,
        "[EBSD detector]": -1,
        "[Detector angles]": -1,
        "[Acquisition settings]": -1,
        "[Area]": -1,
        "[Specimen]": -1,
    }
    for i, line in enumerate(content):
        for block in blocks:
            if block in line:
                blocks[block] = i
    l_nordif = blocks["[NORDIF]"]
    l_mic = blocks["[Microscope]"]
    l_det = blocks["[EBSD detector]"]
    l_ang = blocks["[Detector angles]"]
    l_acq = blocks["[Acquisition settings]"]
    l_area = blocks["[Area]"]
    l_specimen = blocks["[Specimen]"]

    # Create metadata and original metadata structures
    md = ebsd_metadata()
    sem_node, ebsd_node = metadata_nodes(["sem", "ebsd"])
    omd = DictionaryTreeBrowser()
    omd.set_item("nordif_header", content)

    # Get metadata values from settings file using regular expressions
    azimuth_angle = get_string(content, "Azimuthal\t(.*)\t", l_ang + 4, f)
    md.set_item(ebsd_node + ".azimuth_angle", float(azimuth_angle))
    beam_energy = get_string(
        content, "Accelerating voltage\t(.*)\tkV", l_mic + 5, f
    )
    md.set_item(sem_node + ".beam_energy", float(beam_energy))
    detector = get_string(content, "Model\t(.*)\t", l_det + 1, f)
    detector = re.sub("[^a-zA-Z0-9]", repl="", string=detector)
    md.set_item(ebsd_node + ".detector", "NORDIF " + detector)
    elevation_angle = get_string(content, "Elevation\t(.*)\t", l_ang + 5, f)
    md.set_item(ebsd_node + ".elevation_angle", float(elevation_angle))
    exposure_time = get_string(content, "Exposure time\t(.*)\t", l_acq + 3, f)
    md.set_item(ebsd_node + ".exposure_time", float(exposure_time) / 1e6)
    frame_rate = get_string(content, "Frame rate\t(.*)\tfps", l_acq + 1, f)
    md.set_item(ebsd_node + ".frame_rate", int(frame_rate))
    gain = get_string(content, "Gain\t(.*)\t", l_acq + 4, f)
    md.set_item(ebsd_node + ".gain", float(gain))
    magnification = get_string(content, "Magnification\t(.*)\t#", l_mic + 3, f)
    md.set_item(sem_node + ".magnification", int(magnification))
    mic_manufacturer = get_string(content, "Manufacturer\t(.*)\t", l_mic + 1, f)
    mic_model = get_string(content, "Model\t(.*)\t", l_mic + 2, f)
    md.set_item(sem_node + ".microscope", mic_manufacturer + " " + mic_model)
    sample_tilt = get_string(content, "Tilt angle\t(.*)\t", l_mic + 7, f)
    md.set_item(ebsd_node + ".sample_tilt", float(sample_tilt))
    scan_time = get_string(content, "Scan time\t(.*)\t", l_area + 7, f)
    scan_time = time.strptime(scan_time, "%H:%M:%S")
    scan_time = datetime.timedelta(
        hours=scan_time.tm_hour,
        minutes=scan_time.tm_min,
        seconds=scan_time.tm_sec,
    ).total_seconds()
    md.set_item(ebsd_node + ".scan_time", int(scan_time))
    version = get_string(content, "Software version\t(.*)\t", l_nordif + 1, f)
    md.set_item(ebsd_node + ".version", version)
    working_distance = get_string(
        content, "Working distance\t(.*)\tmm", l_mic + 6, f
    )
    md.set_item(sem_node + ".working_distance", float(working_distance))
    md.set_item(ebsd_node + ".grid_type", "square")
    md.set_item(ebsd_node + ".manufacturer", "NORDIF")
    specimen = get_string(content, "Name\t(.*)\t", l_specimen + 1, f)
    pmd = _phase_metadata()
    pmd["material_name"] = specimen
    md.set_item("Sample.Phases.1", pmd)

    # Get scan size values
    scan_size = DictionaryTreeBrowser()
    num_samp = get_string(content, "Number of samples\t(.*)\t#", l_area + 6, f)
    ny, nx = [int(i) for i in num_samp.split("x")]
    scan_size.set_item("nx", int(nx))
    scan_size.set_item("ny", int(ny))
    pattern_size = get_string(content, "Resolution\t(.*)\tpx", l_acq + 2, f)
    sx, sy = [int(i) for i in pattern_size.split("x")]
    scan_size.set_item("sx", int(sx))
    scan_size.set_item("sy", int(sy))
    step_size = get_string(content, "Step size\t(.*)\t", l_area + 5, f)
    scan_size.set_item("step_x", float(step_size))
    scan_size.set_item("step_y", float(step_size))

    return md, omd, scan_size
Example #7
0
 def test_ebsd_metadata(self):
     sem_node, ebsd_node = metadata_nodes(["sem", "ebsd"])
     md = ebsd_metadata()
     assert md.get_item(sem_node + ".microscope") == ""
     assert md.get_item(ebsd_node + ".xpc") == -1.0