nxtomomill 2.2.0.dev1__tar.gz → 2.2.0.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nxtomomill-2.2.0.dev1/nxtomomill.egg-info → nxtomomill-2.2.0.dev2}/PKG-INFO +1 -1
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/h52nx.py +35 -1
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/baseacquisition.py +122 -102
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/standardacquisition.py +17 -1
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/tests/test_acquisition.py +75 -6
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/utils/_context.py +1 -0
- nxtomomill-2.2.0.dev2/nxtomomill/converter/hdf5/acquisition/utils/_keys.py +29 -0
- nxtomomill-2.2.0.dev2/nxtomomill/converter/hdf5/tests/test_err_handling.py +48 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/tests/test_h52nx_utils.py +9 -5
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/tests/test_hdf5converter.py +132 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/dx2nx.py +9 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/edf2nx/general_section.py +6 -3
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/edf2nx/unit_section.py +3 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/_context.py +2 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/general_section.py +5 -1
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/keys_section.py +3 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/tests/test_edf2nx_model.py +12 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/tests/test_h52nx_model.py +15 -2
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2/nxtomomill.egg-info}/PKG-INFO +1 -1
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill.egg-info/SOURCES.txt +1 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill.egg-info/top_level.txt +0 -2
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/pyproject.toml +1 -1
- nxtomomill-2.2.0.dev1/nxtomomill/converter/hdf5/acquisition/utils/_keys.py +0 -10
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/LICENSE +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/README.md +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/doc/conf.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/__main__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/blissfluo2nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/blissfluoconfig.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/dxfile2nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/edf2nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/edf2nx_check.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/edfconfig.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/fluo2nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/fluoconfig.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/fscan2nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/h5config.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/nxcopy.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/patch_nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/split_nxfile.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/tests/test_bliss_fluo2nx_app.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/tests/test_dxfile2nx_app.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/tests/test_edf2nx_app.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/tests/test_edf_config_app.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/tests/test_fluo2nx_app.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/tests/test_h52nx_app.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/tests/test_h5_config_app.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/tests/test_nx_copy.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/tests/test_patch_nx_app.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/tests/test_split_nxfile_app.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/z_concatenate_scans.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/app/zstages2nxs.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/baseconverter.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/dxfile/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/dxfile/dxfileconverter.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/dxfile/tests/test_dxfile.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/edf/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/edf/checks.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/edf/edfconverter.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/edf/tests/test_checks.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/edf/tests/test_edf2nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/edf/tests/test_edf2nx_check.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/fluo/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/fluo/blissfluoscan.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/fluo/fluoconverter.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/fluo/fluoscan.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/fluo/tests/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/fluo/tests/test_fluoscan2D.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/fluo/tests/test_fluoscan3D.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/fscan/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/fscan/fscanconverter.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/_bliss_activeconfig.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/backandforth.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/blisstomoconfig.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/multitomo.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/pcotomoacquisition.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/tests/bliss_tomo_datasets.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/tests/test_acquisition_utils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/tests/test_back_and_forth.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/tests/test_bliss_tomo_config.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/tests/test_holotomo.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/tests/test_legacy.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/tests/test_multitomo_zseries.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/tests/test_multitomoacquisition.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/utils/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/utils/_scan_type_finder.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/utils/bliss_scan_type.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/utils/detector.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/utils/machine_current.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/utils/series.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/utils/timestamps.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisition/zseriesacquisition.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/acquisitionConstructor.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/hdf5converter.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/post_processing/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/post_processing/dark_flat_copy.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/tests/test_frame_flip.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/utils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/version.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/config/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/config/configbase.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/config/confighandler.py +1 -1
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/config/dxconfig.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/config/edfconfig.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/config/fluoconfig.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/config/hdf5config.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/config/tests/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/config/tests/test_confighandler.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/tests/test_frame_group.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/io/tests/utils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/base/ConfigBase.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/base/FrmFlatToNestedBase.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/base/NestedModelBase.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/base/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/base/general_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/base/instrument_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/base/source_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/blissfluo2nx/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/blissfluo2nx/blissfluo2nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/blissfluo2nx/general_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/edf2nx/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/edf2nx/dark_and_flat_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/edf2nx/detector_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/edf2nx/edf2nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/edf2nx/keys_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/edf2nx/sample_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/fluo2nx/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/fluo2nx/fluo2nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/fluo2nx/general_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/FrameGroup.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/_acquisitionstep.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/entries_and_title_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/extra_params_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/frame_type_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/h52nx.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/h52nx/multitomo_section.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/tests/test_context.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/tests/test_fluo2nx_model.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/tests/test_io_utils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/models/utils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/settings.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/test.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/tests/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/tests/datasets.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/tests/resources/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/tests/resources/edf2nx_config_files/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/tests/resources/fluo2nx_config_files/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/tests/resources/h52nx_config_files/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/tests/test_version.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/tests/utils/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/tests/utils/bliss.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/tests/utils/dxfile.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/__init__.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/_os.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/flat_reducer.py +1 -1
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/h5pyutils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/hdf5.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/io.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/nexus.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/pintutils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/tests/test_flat_reducer.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/tests/test_h5pyutils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/tests/test_nexus_utils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/tests/test_utils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/utils/utils.py +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill.egg-info/dependency_links.txt +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill.egg-info/entry_points.txt +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill.egg-info/requires.txt +0 -0
- {nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nxtomomill
|
|
3
|
-
Version: 2.2.0.
|
|
3
|
+
Version: 2.2.0.dev2
|
|
4
4
|
Summary: applications and library to convert raw format to NXtomo format
|
|
5
5
|
Author-email: Henri Payno <henri.payno@esrf.fr>, Pierre Paleo <pierre.paleo@esrf.fr>, Pierre-Olivier Autran <pierre-olivier.autran@esrf.fr>, Jérôme Lesaint <jerome.lesaint@esrf.fr>, Alessandro Mirone <mirone@esrf.fr>
|
|
6
6
|
License:
|
|
@@ -10,7 +10,9 @@ For a complete tutorial you can have a look at: :ref:`Tomoh52nx`
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
import argparse
|
|
13
|
+
import cProfile
|
|
13
14
|
import logging
|
|
15
|
+
import os
|
|
14
16
|
|
|
15
17
|
from tqdm import tqdm
|
|
16
18
|
|
|
@@ -331,12 +333,35 @@ def main(argv):
|
|
|
331
333
|
"links to the raw data. Defaults to the 'NXTOMOMILL_RESOLVE_VDS' "
|
|
332
334
|
"environment variable if set, else resolving is enabled.",
|
|
333
335
|
)
|
|
336
|
+
parser.add_argument(
|
|
337
|
+
"--profiling",
|
|
338
|
+
"--profile",
|
|
339
|
+
help="Profile the conversion with 'cProfile' and dump the statistics "
|
|
340
|
+
"to a file (see '--profiling-output-file').",
|
|
341
|
+
action="store_true",
|
|
342
|
+
default=False,
|
|
343
|
+
)
|
|
344
|
+
parser.add_argument(
|
|
345
|
+
"--profiling-output-file",
|
|
346
|
+
"--profiling_output_file",
|
|
347
|
+
default="profiling.out",
|
|
348
|
+
help="Output file to dump the 'cProfile' statistics to when "
|
|
349
|
+
"'--profiling' is provided. If this file already exists the "
|
|
350
|
+
"conversion won't be launched (default: 'profiling.out').",
|
|
351
|
+
)
|
|
334
352
|
options = parser.parse_args(argv[1:])
|
|
335
353
|
if options.request_input:
|
|
336
354
|
callback_det_sel = _ask_for_selecting_detector
|
|
337
355
|
else:
|
|
338
356
|
callback_det_sel = None
|
|
339
357
|
|
|
358
|
+
if options.profiling and os.path.exists(options.profiling_output_file):
|
|
359
|
+
_logger.error(
|
|
360
|
+
f"Profiling output file already exists: '{options.profiling_output_file}'. "
|
|
361
|
+
"Remove it or provide another one with '--profiling-output-file'."
|
|
362
|
+
)
|
|
363
|
+
return 1
|
|
364
|
+
|
|
340
365
|
try:
|
|
341
366
|
configuration_handler = TomoHDF5ConfigHandler(options)
|
|
342
367
|
except Exception:
|
|
@@ -355,6 +380,15 @@ def main(argv):
|
|
|
355
380
|
input_callback=None,
|
|
356
381
|
detector_sel_callback=callback_det_sel,
|
|
357
382
|
)
|
|
358
|
-
|
|
383
|
+
if options.profiling:
|
|
384
|
+
profiler = cProfile.Profile()
|
|
385
|
+
profiler.enable()
|
|
386
|
+
try:
|
|
387
|
+
converter.convert()
|
|
388
|
+
finally:
|
|
389
|
+
profiler.disable()
|
|
390
|
+
profiler.dump_stats(options.profiling_output_file)
|
|
391
|
+
else:
|
|
392
|
+
converter.convert()
|
|
359
393
|
if converter.has_failed_acquisitions:
|
|
360
394
|
return 1
|
|
@@ -12,7 +12,9 @@ import copy
|
|
|
12
12
|
|
|
13
13
|
import h5py
|
|
14
14
|
|
|
15
|
+
import nxtomomill
|
|
15
16
|
from nxtomo.application.nxtomo import NXtomo
|
|
17
|
+
from nxtomo.io import HDF5File
|
|
16
18
|
from nxtomomill.utils.h5pyutils import from_data_url_to_virtual_source
|
|
17
19
|
from nxtomomill.utils.hdf5 import EntryReader
|
|
18
20
|
from nxtomomill.utils.utils import embed_url # noqa F401
|
|
@@ -30,7 +32,8 @@ from silx.io.url import DataUrl
|
|
|
30
32
|
from silx.io.utils import h5py_read_dataset
|
|
31
33
|
|
|
32
34
|
from nxtomomill.models.h52nx.h52nx import H52nxModel
|
|
33
|
-
from .
|
|
35
|
+
from nxtomomill.models.h52nx._context import _Key
|
|
36
|
+
from .utils._keys import keys_to_str_tuple, split_keys_by_priority
|
|
34
37
|
from .utils._context import read_key, MissingValue, InvalidValue
|
|
35
38
|
|
|
36
39
|
_ureg = pint.get_application_registry()
|
|
@@ -302,6 +305,12 @@ class BaseAcquisition:
|
|
|
302
305
|
use_abs_path_for_vds=self.configuration.use_abs_path_for_vds,
|
|
303
306
|
overwrite=self.configuration.overwrite,
|
|
304
307
|
)
|
|
308
|
+
# record the nxtomomill version used to create this NXtomo as attributes
|
|
309
|
+
# on the NXtomo entry group itself
|
|
310
|
+
with HDF5File(output_file, mode="a") as h5f:
|
|
311
|
+
entry_grp = h5f[data_path]
|
|
312
|
+
entry_grp.attrs["creator"] = "nxtomomill"
|
|
313
|
+
entry_grp.attrs["creator_version"] = nxtomomill.__version__
|
|
305
314
|
# check rotation angle
|
|
306
315
|
if nx_tomo.sample.rotation_angle is not None:
|
|
307
316
|
unique_angles = numpy.unique(
|
|
@@ -410,10 +419,11 @@ class BaseAcquisition:
|
|
|
410
419
|
# skip values containing '*DIS*'
|
|
411
420
|
continue
|
|
412
421
|
except InvalidValue:
|
|
413
|
-
# dataset reports an 'ERR' value:
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
422
|
+
# dataset reports an 'ERR' value: skip it and try the next key
|
|
423
|
+
_logger.warning(
|
|
424
|
+
f"{info_retrieve} reports an 'ERR' value for {node.name} - {key}. This key will be skipped."
|
|
425
|
+
)
|
|
426
|
+
continue
|
|
417
427
|
except KeyError as e:
|
|
418
428
|
_logger.info(
|
|
419
429
|
f"Cannot solve key {key}. Most likely one dataset is not there. Error is {e}"
|
|
@@ -619,6 +629,55 @@ class BaseAcquisition:
|
|
|
619
629
|
|
|
620
630
|
return None
|
|
621
631
|
|
|
632
|
+
@staticmethod
|
|
633
|
+
def _get_values_from_nodes(
|
|
634
|
+
nodes: tuple[h5py.Group | None, ...],
|
|
635
|
+
n_frame: int | None,
|
|
636
|
+
keys: tuple[_Key, ...],
|
|
637
|
+
info_retrieve: str,
|
|
638
|
+
expected_unit: pint.Unit,
|
|
639
|
+
) -> pint.Quantity | None:
|
|
640
|
+
"""
|
|
641
|
+
Look for the values of 'keys' in 'nodes'.
|
|
642
|
+
|
|
643
|
+
Keys resolved from the bliss-tomo 'tomoconfig' are looked at first (on all nodes, arrays
|
|
644
|
+
first then scalars). The other keys (default keys) are only used as a fallback if none of
|
|
645
|
+
the 'tomoconfig' keys could be found.
|
|
646
|
+
|
|
647
|
+
:return: values as a pint.Quantity or None if no key could be found.
|
|
648
|
+
"""
|
|
649
|
+
tomo_config_keys, fallback_keys = split_keys_by_priority(keys)
|
|
650
|
+
|
|
651
|
+
def look_for_keys(keys_to_check: tuple[str, ...]) -> pint.Quantity | None:
|
|
652
|
+
for node in nodes:
|
|
653
|
+
if node is None:
|
|
654
|
+
continue
|
|
655
|
+
try:
|
|
656
|
+
values, unit = BaseAcquisition._get_node_values_for_frame_array(
|
|
657
|
+
node=node,
|
|
658
|
+
n_frame=n_frame,
|
|
659
|
+
keys=keys_to_check,
|
|
660
|
+
info_retrieve=info_retrieve,
|
|
661
|
+
expected_unit=expected_unit,
|
|
662
|
+
)
|
|
663
|
+
except (ValueError, KeyError):
|
|
664
|
+
pass
|
|
665
|
+
else:
|
|
666
|
+
return values * unit
|
|
667
|
+
return None
|
|
668
|
+
|
|
669
|
+
if len(tomo_config_keys) > 0:
|
|
670
|
+
result = look_for_keys(tomo_config_keys)
|
|
671
|
+
if result is not None:
|
|
672
|
+
return result
|
|
673
|
+
_logger.warning(
|
|
674
|
+
f"Unable to find {info_retrieve} from the bliss-tomo 'tomoconfig' datasets {tomo_config_keys}. "
|
|
675
|
+
f"Will look at the fallback datasets {fallback_keys}."
|
|
676
|
+
)
|
|
677
|
+
if len(fallback_keys) > 0:
|
|
678
|
+
return look_for_keys(fallback_keys)
|
|
679
|
+
return None
|
|
680
|
+
|
|
622
681
|
def _get_rotation_angle(self, root_node: h5py.Group, n_frame: int) -> pint.Quantity:
|
|
623
682
|
"""
|
|
624
683
|
return the list of rotation angle for each frame.
|
|
@@ -629,23 +688,19 @@ class BaseAcquisition:
|
|
|
629
688
|
if not isinstance(root_node, h5py.Group):
|
|
630
689
|
raise TypeError("root_node is expected to be a h5py.Group")
|
|
631
690
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
except (ValueError, KeyError):
|
|
646
|
-
pass
|
|
647
|
-
else:
|
|
648
|
-
return angles * unit
|
|
691
|
+
angles = self._get_values_from_nodes(
|
|
692
|
+
nodes=(
|
|
693
|
+
self._get_positioners_node(root_node),
|
|
694
|
+
root_node,
|
|
695
|
+
self._get_measurement_node(root_node),
|
|
696
|
+
),
|
|
697
|
+
n_frame=n_frame,
|
|
698
|
+
keys=self.configuration.rotation_angle_keys,
|
|
699
|
+
info_retrieve="rotation angle",
|
|
700
|
+
expected_unit=_ureg.degree,
|
|
701
|
+
)
|
|
702
|
+
if angles is not None:
|
|
703
|
+
return angles
|
|
649
704
|
|
|
650
705
|
mess = f"Unable to find rotation angle for {root_node.name}"
|
|
651
706
|
if self.raise_error_if_issue:
|
|
@@ -657,19 +712,15 @@ class BaseAcquisition:
|
|
|
657
712
|
|
|
658
713
|
def _get_sample_x(self, root_node, n_frame) -> pint.Quantity:
|
|
659
714
|
"""return the list of translation for each frame"""
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
except (ValueError, KeyError):
|
|
670
|
-
pass
|
|
671
|
-
else:
|
|
672
|
-
return x_tr * unit
|
|
715
|
+
translation = self._get_values_from_nodes(
|
|
716
|
+
nodes=(self._get_positioners_node(root_node), root_node),
|
|
717
|
+
n_frame=n_frame,
|
|
718
|
+
keys=self.configuration.sample_x_keys,
|
|
719
|
+
info_retrieve="sample x translation",
|
|
720
|
+
expected_unit=_ureg.mm,
|
|
721
|
+
)
|
|
722
|
+
if translation is not None:
|
|
723
|
+
return translation
|
|
673
724
|
|
|
674
725
|
mess = f"Unable to find sample x for {root_node.name}"
|
|
675
726
|
if self.raise_error_if_issue:
|
|
@@ -681,19 +732,15 @@ class BaseAcquisition:
|
|
|
681
732
|
|
|
682
733
|
def _get_sample_y(self, root_node, n_frame) -> pint.Quantity:
|
|
683
734
|
"""return the list of translation for each frame"""
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
except (ValueError, KeyError):
|
|
694
|
-
pass
|
|
695
|
-
else:
|
|
696
|
-
return y_tr * unit
|
|
735
|
+
translation = self._get_values_from_nodes(
|
|
736
|
+
nodes=(self._get_positioners_node(root_node), root_node),
|
|
737
|
+
n_frame=n_frame,
|
|
738
|
+
keys=self.configuration.sample_y_keys,
|
|
739
|
+
info_retrieve="sample y translation",
|
|
740
|
+
expected_unit=_ureg.mm,
|
|
741
|
+
)
|
|
742
|
+
if translation is not None:
|
|
743
|
+
return translation
|
|
697
744
|
|
|
698
745
|
mess = f"Unable to find sample y for {root_node.name}"
|
|
699
746
|
if self.raise_error_if_issue:
|
|
@@ -705,24 +752,15 @@ class BaseAcquisition:
|
|
|
705
752
|
|
|
706
753
|
def _get_translation_x(self, root_node, n_frame) -> pint.Quantity | None:
|
|
707
754
|
"""return the list of translation for each frame"""
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
except InvalidValue:
|
|
718
|
-
_logger.error(
|
|
719
|
-
f"translation x reports an 'ERR' value for {root_node.name}. Translation x will be set to None."
|
|
720
|
-
)
|
|
721
|
-
return None
|
|
722
|
-
except (ValueError, KeyError):
|
|
723
|
-
pass
|
|
724
|
-
else:
|
|
725
|
-
return x_tr * unit
|
|
755
|
+
translation = self._get_values_from_nodes(
|
|
756
|
+
nodes=(self._get_positioners_node(root_node), root_node),
|
|
757
|
+
n_frame=n_frame,
|
|
758
|
+
keys=self.configuration.translation_x_keys,
|
|
759
|
+
info_retrieve="x base translation",
|
|
760
|
+
expected_unit=_ureg.mm,
|
|
761
|
+
)
|
|
762
|
+
if translation is not None:
|
|
763
|
+
return translation
|
|
726
764
|
|
|
727
765
|
mess = f"Unable to find translation x for {root_node.name}"
|
|
728
766
|
if self.raise_error_if_issue:
|
|
@@ -734,24 +772,15 @@ class BaseAcquisition:
|
|
|
734
772
|
|
|
735
773
|
def _get_translation_y(self, root_node, n_frame) -> pint.Quantity | None:
|
|
736
774
|
"""return the list of translation for each frame"""
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
except InvalidValue:
|
|
747
|
-
_logger.error(
|
|
748
|
-
f"translation y reports an 'ERR' value for {root_node.name}. Translation y will be set to None."
|
|
749
|
-
)
|
|
750
|
-
return None
|
|
751
|
-
except (ValueError, KeyError):
|
|
752
|
-
pass
|
|
753
|
-
else:
|
|
754
|
-
return y_tr * unit
|
|
775
|
+
translation = self._get_values_from_nodes(
|
|
776
|
+
nodes=(self._get_positioners_node(root_node), root_node),
|
|
777
|
+
n_frame=n_frame,
|
|
778
|
+
keys=self.configuration.translation_y_keys,
|
|
779
|
+
info_retrieve="y base translation",
|
|
780
|
+
expected_unit=_ureg.mm,
|
|
781
|
+
)
|
|
782
|
+
if translation is not None:
|
|
783
|
+
return translation
|
|
755
784
|
|
|
756
785
|
mess = f"Unable to find translation y for {root_node.name}"
|
|
757
786
|
if self.raise_error_if_issue:
|
|
@@ -765,24 +794,15 @@ class BaseAcquisition:
|
|
|
765
794
|
def get_translation_z_frm(
|
|
766
795
|
root_node, n_frame: int, configuration: H52nxModel
|
|
767
796
|
) -> pint.Quantity | None:
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
except InvalidValue:
|
|
778
|
-
_logger.error(
|
|
779
|
-
f"translation z reports an 'ERR' value for {root_node.name}. Translation z will be set to None."
|
|
780
|
-
)
|
|
781
|
-
return None
|
|
782
|
-
except (ValueError, KeyError):
|
|
783
|
-
pass
|
|
784
|
-
else:
|
|
785
|
-
return z_tr * unit
|
|
797
|
+
translation = BaseAcquisition._get_values_from_nodes(
|
|
798
|
+
nodes=(BaseAcquisition._get_positioners_node(root_node), root_node),
|
|
799
|
+
n_frame=n_frame,
|
|
800
|
+
keys=configuration.translation_z_keys,
|
|
801
|
+
info_retrieve="z translation",
|
|
802
|
+
expected_unit=_ureg.mm,
|
|
803
|
+
)
|
|
804
|
+
if translation is not None:
|
|
805
|
+
return translation
|
|
786
806
|
|
|
787
807
|
mess = f"Unable to find translation z on node {root_node.name}"
|
|
788
808
|
if configuration.raises_error:
|
|
@@ -65,6 +65,10 @@ from .utils._keys import keys_to_str_tuple
|
|
|
65
65
|
_ureg = pint.get_application_registry()
|
|
66
66
|
_logger = logging.getLogger(__name__)
|
|
67
67
|
|
|
68
|
+
_MAX_VDS_SOURCES_TO_RESOLVE = 100
|
|
69
|
+
"""If a camera dataset virtual source relies on that many (or more) distinct files, skip
|
|
70
|
+
resolving external links / virtual dataset sources for it."""
|
|
71
|
+
|
|
68
72
|
|
|
69
73
|
__all__ = ["StandardAcquisition"]
|
|
70
74
|
|
|
@@ -346,7 +350,19 @@ class StandardAcquisition(BaseAcquisition):
|
|
|
346
350
|
image_key_control = frame_type.to_image_key_control()
|
|
347
351
|
self._image_key_control.extend([image_key_control.value] * n_frame)
|
|
348
352
|
|
|
349
|
-
|
|
353
|
+
n_vds_files = (
|
|
354
|
+
len({vs_info.file_name for vs_info in data_dataset.virtual_sources()})
|
|
355
|
+
if data_dataset.is_virtual
|
|
356
|
+
else 0
|
|
357
|
+
)
|
|
358
|
+
if n_vds_files >= _MAX_VDS_SOURCES_TO_RESOLVE:
|
|
359
|
+
_logger.warning(
|
|
360
|
+
f"{camera_dataset_url.path()} relies on {n_vds_files} files "
|
|
361
|
+
f"(>= {_MAX_VDS_SOURCES_TO_RESOLVE}). Skip external link / VDS "
|
|
362
|
+
"resolution to avoid opening too many files."
|
|
363
|
+
)
|
|
364
|
+
solved_camera_dataset_urls = (camera_dataset_url,)
|
|
365
|
+
elif self.configuration.resolve_vds:
|
|
350
366
|
try:
|
|
351
367
|
solved_camera_dataset_urls = resolve_link(
|
|
352
368
|
dataset_url=camera_dataset_url,
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
import os
|
|
4
4
|
import tempfile
|
|
5
5
|
|
|
6
|
+
import logging
|
|
7
|
+
|
|
6
8
|
import h5py
|
|
9
|
+
import numpy
|
|
7
10
|
import pytest
|
|
8
11
|
from silx.io.url import DataUrl
|
|
9
12
|
|
|
@@ -13,6 +16,7 @@ from nxtomomill.converter.hdf5.acquisition.baseacquisition import (
|
|
|
13
16
|
get_dataset_name_from_motor,
|
|
14
17
|
)
|
|
15
18
|
from nxtomomill.io.config import TomoHDF5Config
|
|
19
|
+
from nxtomomill.models.h52nx._context import _Key
|
|
16
20
|
from nxtomomill.tests.datasets import GitlabDataset
|
|
17
21
|
from nxtomomill import converter
|
|
18
22
|
from nxtomo.application.nxtomo import NXtomo
|
|
@@ -56,20 +60,80 @@ def test_get_dataset_name_from_motor():
|
|
|
56
60
|
@pytest.mark.parametrize("raises_error", (True, False))
|
|
57
61
|
def test_translation_with_err_value(tmp_path, raises_error):
|
|
58
62
|
"""
|
|
59
|
-
Test that translation
|
|
60
|
-
|
|
63
|
+
Test that translation datasets reporting an 'ERR' value are skipped:
|
|
64
|
+
the next valid key is used and, if none is valid, it behaves as if the
|
|
65
|
+
translation was not found (raises or default to 0).
|
|
61
66
|
"""
|
|
62
67
|
file_path = os.path.join(tmp_path, "test.h5")
|
|
63
68
|
with HDF5File(file_path, mode="w") as h5f:
|
|
64
69
|
h5f["/entry/instrument/positioners/tx"] = "ERR"
|
|
65
70
|
h5f["/entry/instrument/positioners/ty"] = "ERR"
|
|
66
71
|
h5f["/entry/instrument/positioners/tz"] = "ERR"
|
|
72
|
+
h5f["/entry/instrument/positioners/sz"] = 2.0
|
|
73
|
+
h5f["/entry/instrument/positioners/sz"].attrs["units"] = "mm"
|
|
67
74
|
|
|
68
75
|
config = TomoHDF5Config()
|
|
69
76
|
config.raises_error = raises_error
|
|
70
77
|
config.translation_x_keys = ("tx",)
|
|
71
78
|
config.translation_y_keys = ("ty",)
|
|
72
|
-
config.translation_z_keys = ("tz",)
|
|
79
|
+
config.translation_z_keys = ("tz", "sz")
|
|
80
|
+
|
|
81
|
+
url = DataUrl(file_path=file_path, data_path="/entry", scheme="silx")
|
|
82
|
+
std_acq = BaseAcquisition(
|
|
83
|
+
root_url=url,
|
|
84
|
+
configuration=config,
|
|
85
|
+
detector_sel_callback=None,
|
|
86
|
+
start_index=0,
|
|
87
|
+
)
|
|
88
|
+
with h5py.File(file_path, mode="r") as h5f:
|
|
89
|
+
root_node = h5f["/entry"]
|
|
90
|
+
# 'tz' reports 'ERR': fall back to 'sz'
|
|
91
|
+
z_tr = std_acq._get_translation_z(root_node=root_node, n_frame=1)
|
|
92
|
+
assert z_tr.to("mm").magnitude.tolist() == [2.0]
|
|
93
|
+
|
|
94
|
+
# no valid key: same behavior as a missing translation
|
|
95
|
+
if raises_error:
|
|
96
|
+
with pytest.raises(ValueError):
|
|
97
|
+
std_acq._get_translation_x(root_node=root_node, n_frame=1)
|
|
98
|
+
with pytest.raises(ValueError):
|
|
99
|
+
std_acq._get_translation_y(root_node=root_node, n_frame=1)
|
|
100
|
+
else:
|
|
101
|
+
x_tr = std_acq._get_translation_x(root_node=root_node, n_frame=1)
|
|
102
|
+
assert x_tr.magnitude.tolist() == [0]
|
|
103
|
+
y_tr = std_acq._get_translation_y(root_node=root_node, n_frame=1)
|
|
104
|
+
assert y_tr.magnitude.tolist() == [0]
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_tomo_config_keys_priority(tmp_path, caplog):
|
|
108
|
+
"""
|
|
109
|
+
Test that keys resolved from the bliss-tomo 'tomoconfig' are looked at first (array then scalar)
|
|
110
|
+
and that the default keys are only used as fallback.
|
|
111
|
+
"""
|
|
112
|
+
n_frame = 3
|
|
113
|
+
file_path = os.path.join(tmp_path, "test.h5")
|
|
114
|
+
with HDF5File(file_path, mode="w") as h5f:
|
|
115
|
+
# tomoconfig motor is static (scalar) while a default key records an array
|
|
116
|
+
h5f["/entry/instrument/positioners/real_sx"] = 1.0
|
|
117
|
+
h5f["/entry/instrument/positioners/samx"] = numpy.array([5.0, 6.0, 7.0])
|
|
118
|
+
# tomoconfig motor only exists in root_node while a default key exists in positioners
|
|
119
|
+
h5f["/entry/real_sy"] = numpy.array([1.0, 2.0, 3.0])
|
|
120
|
+
h5f["/entry/instrument/positioners/samy"] = numpy.array([5.0, 6.0, 7.0])
|
|
121
|
+
# tomoconfig motor doesn't exist: fallback on the default key
|
|
122
|
+
h5f["/entry/instrument/positioners/sz"] = numpy.array([5.0, 6.0, 7.0])
|
|
123
|
+
|
|
124
|
+
config = TomoHDF5Config()
|
|
125
|
+
config.sample_x_keys = (
|
|
126
|
+
_Key(dataset="real_sx", contexts=set(), resolved_from_tomo_config=True),
|
|
127
|
+
_Key(dataset="samx", contexts=set()),
|
|
128
|
+
)
|
|
129
|
+
config.sample_y_keys = (
|
|
130
|
+
_Key(dataset="real_sy", contexts=set(), resolved_from_tomo_config=True),
|
|
131
|
+
_Key(dataset="samy", contexts=set()),
|
|
132
|
+
)
|
|
133
|
+
config.translation_z_keys = (
|
|
134
|
+
_Key(dataset="real_tz", contexts=set(), resolved_from_tomo_config=True),
|
|
135
|
+
_Key(dataset="sz", contexts=set()),
|
|
136
|
+
)
|
|
73
137
|
|
|
74
138
|
url = DataUrl(file_path=file_path, data_path="/entry", scheme="silx")
|
|
75
139
|
std_acq = BaseAcquisition(
|
|
@@ -80,9 +144,14 @@ def test_translation_with_err_value(tmp_path, raises_error):
|
|
|
80
144
|
)
|
|
81
145
|
with h5py.File(file_path, mode="r") as h5f:
|
|
82
146
|
root_node = h5f["/entry"]
|
|
83
|
-
|
|
84
|
-
assert
|
|
85
|
-
|
|
147
|
+
sample_x = std_acq._get_sample_x(root_node=root_node, n_frame=n_frame)
|
|
148
|
+
assert sample_x.magnitude.tolist() == [1.0] * n_frame
|
|
149
|
+
sample_y = std_acq._get_sample_y(root_node=root_node, n_frame=n_frame)
|
|
150
|
+
assert sample_y.magnitude.tolist() == [1.0, 2.0, 3.0]
|
|
151
|
+
with caplog.at_level(logging.WARNING):
|
|
152
|
+
z_tr = std_acq._get_translation_z(root_node=root_node, n_frame=n_frame)
|
|
153
|
+
assert z_tr.magnitude.tolist() == [5.0, 6.0, 7.0]
|
|
154
|
+
assert "Will look at the fallback datasets" in caplog.text
|
|
86
155
|
|
|
87
156
|
|
|
88
157
|
def test_frame_flips(tmp_path, monkeypatch):
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""A set of utils related to keys management"""
|
|
2
|
+
|
|
3
|
+
from .....models.h52nx._context import _Key
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def keys_to_str_tuple(keys: tuple[_Key]) -> tuple[str]:
|
|
7
|
+
for key in keys:
|
|
8
|
+
if not isinstance(key, _Key):
|
|
9
|
+
raise TypeError(f"key should be an instance of {_Key}. Got {type(key)}")
|
|
10
|
+
return tuple([key.dataset for key in keys])
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def split_keys_by_priority(
|
|
14
|
+
keys: tuple[_Key, ...],
|
|
15
|
+
) -> tuple[tuple[str, ...], tuple[str, ...]]:
|
|
16
|
+
"""
|
|
17
|
+
Split keys between the ones resolved from the bliss-tomo 'tomoconfig' (to be looked at first)
|
|
18
|
+
and the fallback ones (default keys).
|
|
19
|
+
"""
|
|
20
|
+
for key in keys:
|
|
21
|
+
if not isinstance(key, _Key):
|
|
22
|
+
raise TypeError(f"key should be an instance of {_Key}. Got {type(key)}")
|
|
23
|
+
tomo_config_keys = tuple(
|
|
24
|
+
key.dataset for key in keys if key.resolved_from_tomo_config
|
|
25
|
+
)
|
|
26
|
+
fallback_keys = tuple(
|
|
27
|
+
key.dataset for key in keys if not key.resolved_from_tomo_config
|
|
28
|
+
)
|
|
29
|
+
return tomo_config_keys, fallback_keys
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import h5py
|
|
6
|
+
import numpy
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from nxtomo import NXtomo
|
|
10
|
+
from nxtomomill.models.h52nx import H52nxModel
|
|
11
|
+
from nxtomomill.converter.hdf5.hdf5converter import from_h5_to_nx
|
|
12
|
+
from nxtomomill.tests.datasets import GitlabDataset
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture()
|
|
16
|
+
def dataset_with_err():
|
|
17
|
+
dataset_path = (
|
|
18
|
+
"h5_datasets/handling_ERR/15.12um_A327_lung_overview__TA2_REF_B_000_0001.h5"
|
|
19
|
+
)
|
|
20
|
+
source_file = GitlabDataset.get_dataset(dataset_path)
|
|
21
|
+
if source_file is None:
|
|
22
|
+
raise FileNotFoundError(f"Unable to download {dataset_path}")
|
|
23
|
+
return source_file
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_err_translation_fallback(tmp_path, dataset_with_err):
|
|
27
|
+
"""
|
|
28
|
+
Make sure that if a translation candidate reports an 'ERR' value
|
|
29
|
+
('mrsz') the next valid candidate ('sz') is used.
|
|
30
|
+
"""
|
|
31
|
+
with h5py.File(dataset_with_err, mode="r") as h5f:
|
|
32
|
+
assert h5f["4.1/instrument/positioners/mrsz"][()] == b"ERR"
|
|
33
|
+
expected_z = h5f["4.1/instrument/positioners/sz"][()]
|
|
34
|
+
|
|
35
|
+
output_file = os.path.join(tmp_path, "output.nx")
|
|
36
|
+
model = H52nxModel(
|
|
37
|
+
input_file=dataset_with_err,
|
|
38
|
+
output_file=output_file,
|
|
39
|
+
single_file=True,
|
|
40
|
+
)
|
|
41
|
+
from_h5_to_nx(configuration=model)
|
|
42
|
+
assert os.path.exists(output_file)
|
|
43
|
+
|
|
44
|
+
nxtomo = NXtomo().load(file_path=output_file, data_path="entry0000")
|
|
45
|
+
# ESRF z axis is stored as the NXtomo (McStas) y axis
|
|
46
|
+
y_translation = nxtomo.sample.y_translation
|
|
47
|
+
assert y_translation is not None
|
|
48
|
+
numpy.testing.assert_allclose(y_translation.to("mm").magnitude, expected_z)
|
{nxtomomill-2.2.0.dev1 → nxtomomill-2.2.0.dev2}/nxtomomill/converter/hdf5/tests/test_h52nx_utils.py
RENAMED
|
@@ -97,15 +97,19 @@ def test_update_config_keys_from_tomo_config_context():
|
|
|
97
97
|
# the real (per-frame) motor name is tried first, the bliss alias (static / scalar value) is
|
|
98
98
|
# kept as a fallback in case the real motor name doesn't exist in a given (sub-)scan.
|
|
99
99
|
assert model.sample_x_keys == (
|
|
100
|
-
_Key(dataset="real_sx", contexts=set()),
|
|
101
|
-
_Key(dataset="alias_sx", contexts=set()),
|
|
100
|
+
_Key(dataset="real_sx", contexts=set(), resolved_from_tomo_config=True),
|
|
101
|
+
_Key(dataset="alias_sx", contexts=set(), resolved_from_tomo_config=True),
|
|
102
102
|
)
|
|
103
103
|
assert model.sample_y_keys == (
|
|
104
|
-
_Key(dataset="real_sy+real_ty", contexts=set()),
|
|
105
|
-
_Key(
|
|
104
|
+
_Key(dataset="real_sy+real_ty", contexts=set(), resolved_from_tomo_config=True),
|
|
105
|
+
_Key(
|
|
106
|
+
dataset="alias_sy+alias_ty", contexts=set(), resolved_from_tomo_config=True
|
|
107
|
+
),
|
|
106
108
|
)
|
|
107
109
|
# when tomo_config only registered a single name there is nothing to fall back to: no duplicate
|
|
108
|
-
assert model.valid_camera_names == (
|
|
110
|
+
assert model.valid_camera_names == (
|
|
111
|
+
_Key(dataset="single_su", contexts=set(), resolved_from_tomo_config=True),
|
|
112
|
+
)
|
|
109
113
|
|
|
110
114
|
|
|
111
115
|
def test_update_config_keys_from_beamline_context():
|