Source code for nxtomomill.app.h52nx

# coding: utf-8

"""
Application to convert a bliss-hdf5 tomography dataset to Nexus - NXtomo (hdf5) format

.. program-output:: nxtomomill h52nx --help

For a complete tutorial you can have a look at: :ref:`Tomoh52nx`

"""

import argparse
import logging

from tqdm import tqdm

from nxtomomill import utils
from nxtomomill.converter import from_h5_to_nx
from nxtomomill.io.config.confighandler import (
    SETTABLE_PARAMETERS_UNITS,
    TomoHDF5ConfigHandler,
)

logging.basicConfig(level=logging.INFO)
_logger = logging.getLogger(__name__)


def _getPossibleInputParams():
    """

    :return: string with param1 (expected unit) ...
    """
    res = []
    for key, value in SETTABLE_PARAMETERS_UNITS.items():
        res.append(f"{key} ({value})")
    return ", ".join(res)


def _ask_for_selecting_detector(det_grps: list[str] | tuple[str]) -> str | None:
    res = input(
        "Several detector found. Only one detector is managed at the "
        "time. Please enter the name of the detector you want to use "
        f"or 'Cancel' to stop translation ({det_grps})"
    )
    if res == "Cancel":
        return None
    elif res in det_grps:
        return res
    else:
        # warning: this is not a debug log !!!
        print("detector name not recognized.")
        return _ask_for_selecting_detector(det_grps)


[docs]def main(argv): """ """ parser = argparse.ArgumentParser( description="convert data acquired as " "hdf5 from bliss to nexus " "`NXtomo` classes. For `zseries` it will create one entry per `z`" ) parser.add_argument( "input_file", help="master file of the " "acquisition", default=None, nargs="?" ) parser.add_argument( "output_file", help="output .nx or .h5 file", default=None, nargs="?" ) parser.add_argument( "--file-extension", "--file_extension", default=None, help="extension of the output file. Valid values are " "" + "/".join([item.value for item in utils.FileExtension]), ) parser.add_argument( "--single-file", help="merge all scan sequence to the same output file. " "By default create one file per sequence and " "group all sequence in the output file", dest="single_file", action="store_true", default=None, # default is None and not False for the ConfigHandler so it can knows when set by the user or not ) parser.add_argument( "--with-master-file", help="Creates a master file linking all .nx files", dest="no_master_file", action="store_false", default=None, ) parser.add_argument( "--overwrite", help="Do not ask for user permission to overwrite output files", action="store_true", default=None, # default is None and not False for the ConfigHandler so it can knows when set by the user or not ) parser.add_argument( "--debug", help="Set logs to debug mode", action="store_true", default=None, # default is None and not False for the ConfigHandler so it can knows when set by the user or not ) parser.add_argument( "--entries", help="Specify (root) entries to be converted. By default it will try " "to convert all existing entries.", default=None, ) parser.add_argument( "--sub-entries-to-ignore", "--ignore-sub-entries", help="Specify (none-root) sub entries to ignore.", default=None, ) parser.add_argument( "--raises-error", help="Raise errors if some data are not met instead of providing some" " default values", action="store_true", default=None, # default is None and not False for the ConfigHandler so it can knows when set by the user or not ) parser.add_argument( "--field-of-view", help="Force the output to be `Half` or `Full` acquisition. Otherwise " "parse raw data to find this information.", default=None, ) parser.add_argument( "--no-input", "--no-input-for-missing-information", help="The user won't be ask for any inputs", dest="request_input", action="store_false", default=None, # default is None and not False for the ConfigHandler so it can knows when set by the user or not ) parser.add_argument( "--data-copy", "--copy-data", help="Force data duplication of frames. This will permit to have an " "'all-embed' file. Otherwise the detector/data dataset will haves " "links to other files.", action="store_true", dest="default_data_copy", default=None, # default is None and not False for the ConfigHandler so it can knows when set by the user or not ) parser.add_argument( "--sample_x_keys", "--sample-x-keys", default=None, help="x translation key in bliss HDF5 file", ) parser.add_argument( "--sample_y_keys", "--sample-y-keys", default=None, help="y translation key in bliss HDF5 file", ) parser.add_argument( "--translation_z_keys", "--translation-z-keys", default=None, help="z translation key in bliss HDF5 file", ) parser.add_argument( "--sample-detector-distance-keys", "--sample-detector-distance-paths", "--distance-paths", default=None, help="sample detector distance paths", ) parser.add_argument( "--valid_camera_names", "--valid-camera-names", default=None, help="Valid NXDetector dataset name to be considered. Otherwise will" "try to deduce them from NX_class attibute (value should be" "NXdetector) or from instrument group child structure.", ) parser.add_argument( "--rotation_angle_keys", "--rotation-angle-keys", "--rot-angle-keys", "--rot_angle_keys", default=None, help="Valid dataset name for rotation angle", ) parser.add_argument( "--exposure_time_keys", "--exposure-time-keys", "--acq_expo_time_keys", "--acq-expo-time-keys", default=None, help="Valid dataset name for acquisition exposure time", ) parser.add_argument( "--sample-x-pixel-size_keys", "--sample_x_pixel_size_keys", default=None, help="X pixel size key to read", ) parser.add_argument( "--sample-y-pixel-size_keys", "--sample_y_pixel_size_keys", default=None, help="Y pixel size key to read", ) # scan titles parser.add_argument( "--init_titles", "--init-titles", default=None, help="Titles corresponding to init scans", ) parser.add_argument( "--zseries-init-titles", "--zseries_init_titles", "--z_series_init_titles", "--z-series_init_titles", "--init_zserie_titles", "--init-zserie-titles", default=None, help="Titles corresponding to zserie init scans", ) parser.add_argument( "--multitomo-init-titles", "--multitomo_init_titles", "--multi-tomo-init-titles", "--multi_tomo_init_titles", "--init-multi-tomo-titles", "--init-pcotomo-titles", default=None, help="Titles corresponding to multi-tomo init scans", ) parser.add_argument( "--back-and-forth-init-titles", "--back_and_forth_init_titles", "--init-back-and-forth-titles", "--init_back_and_forth_titles", default=None, help="Titles corresponding to back-and-forth init scans", ) parser.add_argument( "--dark-titles", "--dark_titles", default=None, help="Titles corresponding to dark scans", ) parser.add_argument( "--flat-titles", "--flat_titles", "--ref_titles", "--ref-titles", default=None, help="Titles corresponding to ref scans", dest="flat_titles", ) parser.add_argument( "--projection_titles", "--proj_titles", "--proj-titles", default=None, help="Titles corresponding to projection scans", ) parser.add_argument( "--alignment-titles", "--alignment_titles", "--align_titles", "--align-titles", default=None, help="Titles corresponding to alignment scans", ) parser.add_argument( "--set-params", default=None, nargs="*", help="Allow manual definition of some parameters. " "Valid parameters (and expected input unit) " f"are: {_getPossibleInputParams()}. Should be added at the end of the command line because " "will try to cover all text set after this option.", ) # config file parser.add_argument( "--config-file", "--config", "--configuration", "--configuration-file", default=None, help="file containing the full configuration to convert from h5 " "bliss to nexus", ) options = parser.parse_args(argv[1:]) if options.request_input: callback_det_sel = _ask_for_selecting_detector else: callback_det_sel = None try: configuration_handler = TomoHDF5ConfigHandler(options) except Exception: _logger.error("Fail to initiate the configuration.", exc_info=True) return else: for title in configuration_handler.configuration.init_titles: assert title != "" logging.getLogger("nxtomomill").setLevel( configuration_handler.configuration.log_level ) from_h5_to_nx( configuration=configuration_handler.configuration, progress=tqdm(desc="h52nx", delay=1, bar_format="{l_bar}{bar}"), input_callback=None, detector_sel_callback=callback_det_sel, )