nxtomomill 2.1.0.dev2__tar.gz → 2.1.0.dev3__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.
Files changed (188) hide show
  1. {nxtomomill-2.1.0.dev2/nxtomomill.egg-info → nxtomomill-2.1.0.dev3}/PKG-INFO +3 -2
  2. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/h52nx.py +14 -12
  3. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/patch_nx.py +4 -1
  4. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/split_nxfile.py +18 -2
  5. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/z_concatenate_scans.py +3 -1
  6. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/dxfile/dxfileconverter.py +28 -10
  7. nxtomomill-2.1.0.dev3/nxtomomill/converter/edf/_Blosc2Jp2kWrapper.py +63 -0
  8. nxtomomill-2.1.0.dev3/nxtomomill/converter/hdf5/acquisition/_bliss_activeconfig.py +34 -0
  9. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/baseacquisition.py +27 -12
  10. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/multitomo.py +86 -9
  11. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/standardacquisition.py +161 -48
  12. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/tests/test_acquisition.py +37 -0
  13. nxtomomill-2.1.0.dev3/nxtomomill/converter/hdf5/acquisition/tests/test_multitomo_zseries.py +109 -0
  14. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/tests/test_multitomoacquisition.py +9 -0
  15. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/utils/bliss_scan_type.py +4 -2
  16. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/zseriesacquisition.py +10 -3
  17. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisitionConstructor.py +12 -4
  18. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/hdf5converter.py +10 -6
  19. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/post_processing/dark_flat_copy.py +4 -0
  20. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/tests/test_frame_flip.py +7 -5
  21. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/tests/test_hdf5converter.py +15 -12
  22. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/config/confighandler.py +2 -0
  23. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/config/tests/test_confighandler.py +2 -0
  24. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/general_section.py +9 -0
  25. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/h52nx.py +1 -0
  26. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/tests/datasets.py +4 -5
  27. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/flat_reducer.py +19 -4
  28. nxtomomill-2.1.0.dev3/nxtomomill/utils/h5pyutils.py +219 -0
  29. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/hdf5.py +47 -21
  30. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/nexus.py +14 -4
  31. nxtomomill-2.1.0.dev3/nxtomomill/utils/tests/test_h5pyutils.py +209 -0
  32. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/tests/test_utils.py +15 -0
  33. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/utils.py +18 -8
  34. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/version.py +1 -1
  35. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3/nxtomomill.egg-info}/PKG-INFO +3 -2
  36. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill.egg-info/SOURCES.txt +4 -10
  37. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill.egg-info/requires.txt +2 -1
  38. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill.egg-info/top_level.txt +2 -0
  39. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/pyproject.toml +2 -1
  40. nxtomomill-2.1.0.dev2/nxtomomill/nexus/__init__.py +0 -8
  41. nxtomomill-2.1.0.dev2/nxtomomill/nexus/nxdetector.py +0 -10
  42. nxtomomill-2.1.0.dev2/nxtomomill/nexus/nxinstrument.py +0 -10
  43. nxtomomill-2.1.0.dev2/nxtomomill/nexus/nxmonitor.py +0 -10
  44. nxtomomill-2.1.0.dev2/nxtomomill/nexus/nxobject.py +0 -10
  45. nxtomomill-2.1.0.dev2/nxtomomill/nexus/nxsample.py +0 -10
  46. nxtomomill-2.1.0.dev2/nxtomomill/nexus/nxsource.py +0 -10
  47. nxtomomill-2.1.0.dev2/nxtomomill/nexus/nxtomo.py +0 -10
  48. nxtomomill-2.1.0.dev2/nxtomomill/nexus/nxtransformations.py +0 -10
  49. nxtomomill-2.1.0.dev2/nxtomomill/nexus/utils.py +0 -10
  50. nxtomomill-2.1.0.dev2/nxtomomill/utils/h5pyutils.py +0 -58
  51. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/LICENSE +0 -0
  52. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/README.md +0 -0
  53. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/doc/conf.py +0 -0
  54. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/__init__.py +0 -0
  55. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/__main__.py +0 -0
  56. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/__init__.py +0 -0
  57. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/blissfluo2nx.py +0 -0
  58. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/blissfluoconfig.py +0 -0
  59. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/dxfile2nx.py +0 -0
  60. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/edf2nx.py +0 -0
  61. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/edf2nx_check.py +0 -0
  62. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/edfconfig.py +0 -0
  63. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/fluo2nx.py +0 -0
  64. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/fluoconfig.py +0 -0
  65. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/fscan2nx.py +0 -0
  66. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/h5config.py +0 -0
  67. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/nxcopy.py +0 -0
  68. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/tests/test_bliss_fluo2nx_app.py +0 -0
  69. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/tests/test_dxfile2nx_app.py +0 -0
  70. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/tests/test_edf2nx_app.py +0 -0
  71. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/tests/test_edf_config_app.py +0 -0
  72. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/tests/test_fluo2nx_app.py +0 -0
  73. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/tests/test_h52nx_app.py +0 -0
  74. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/tests/test_h5_config_app.py +0 -0
  75. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/tests/test_nx_copy.py +0 -0
  76. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/tests/test_patch_nx_app.py +0 -0
  77. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/tests/test_split_nxfile_app.py +0 -0
  78. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/app/zstages2nxs.py +0 -0
  79. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/__init__.py +0 -0
  80. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/baseconverter.py +0 -0
  81. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/dxfile/__init__.py +0 -0
  82. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/dxfile/tests/test_dxfile.py +0 -0
  83. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/edf/__init__.py +0 -0
  84. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/edf/checks.py +0 -0
  85. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/edf/edfconverter.py +0 -0
  86. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/edf/tests/test_checks.py +0 -0
  87. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/edf/tests/test_edf2nx.py +0 -0
  88. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/edf/tests/test_edf2nx_check.py +0 -0
  89. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/fluo/__init__.py +0 -0
  90. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/fluo/blissfluoscan.py +0 -0
  91. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/fluo/fluoconverter.py +0 -0
  92. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/fluo/fluoscan.py +0 -0
  93. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/fluo/tests/__init__.py +0 -0
  94. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/fluo/tests/test_fluoscan2D.py +0 -0
  95. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/fluo/tests/test_fluoscan3D.py +0 -0
  96. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/fscan/__init__.py +0 -0
  97. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/fscan/fscanconverter.py +0 -0
  98. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/__init__.py +0 -0
  99. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/__init__.py +0 -0
  100. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/backandforth.py +0 -0
  101. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/blisstomoconfig.py +0 -0
  102. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/pcotomoacquisition.py +0 -0
  103. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/tests/bliss_tomo_datasets.py +0 -0
  104. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/tests/test_acquisition_utils.py +0 -0
  105. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/tests/test_back_and_forth.py +0 -0
  106. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/tests/test_bliss_tomo_config.py +0 -0
  107. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/tests/test_holotomo.py +0 -0
  108. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/tests/test_legacy.py +0 -0
  109. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/utils/__init__.py +0 -0
  110. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/utils/_context.py +0 -0
  111. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/utils/_keys.py +0 -0
  112. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/utils/_scan_type_finder.py +0 -0
  113. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/utils/detector.py +0 -0
  114. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/utils/machine_current.py +0 -0
  115. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/utils/series.py +0 -0
  116. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/acquisition/utils/timestamps.py +0 -0
  117. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/post_processing/__init__.py +0 -0
  118. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/tests/test_h52nx_utils.py +0 -0
  119. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/hdf5/utils.py +0 -0
  120. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/converter/version.py +0 -0
  121. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/__init__.py +0 -0
  122. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/config/__init__.py +0 -0
  123. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/config/configbase.py +0 -0
  124. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/config/dxconfig.py +0 -0
  125. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/config/edfconfig.py +0 -0
  126. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/config/fluoconfig.py +0 -0
  127. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/config/hdf5config.py +0 -0
  128. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/config/tests/__init__.py +0 -0
  129. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/tests/test_frame_group.py +0 -0
  130. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/io/tests/utils.py +0 -0
  131. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/__init__.py +0 -0
  132. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/base/ConfigBase.py +0 -0
  133. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/base/FrmFlatToNestedBase.py +0 -0
  134. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/base/NestedModelBase.py +0 -0
  135. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/base/__init__.py +0 -0
  136. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/base/general_section.py +0 -0
  137. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/base/instrument_section.py +0 -0
  138. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/base/source_section.py +0 -0
  139. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/blissfluo2nx/__init__.py +0 -0
  140. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/blissfluo2nx/blissfluo2nx.py +0 -0
  141. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/blissfluo2nx/general_section.py +0 -0
  142. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/dx2nx.py +0 -0
  143. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/edf2nx/__init__.py +0 -0
  144. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/edf2nx/dark_and_flat_section.py +0 -0
  145. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/edf2nx/detector_section.py +0 -0
  146. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/edf2nx/edf2nx.py +0 -0
  147. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/edf2nx/general_section.py +0 -0
  148. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/edf2nx/keys_section.py +0 -0
  149. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/edf2nx/sample_section.py +0 -0
  150. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/edf2nx/unit_section.py +0 -0
  151. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/fluo2nx/__init__.py +0 -0
  152. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/fluo2nx/fluo2nx.py +0 -0
  153. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/fluo2nx/general_section.py +0 -0
  154. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/FrameGroup.py +0 -0
  155. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/__init__.py +0 -0
  156. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/_acquisitionstep.py +0 -0
  157. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/_context.py +0 -0
  158. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/entries_and_title_section.py +0 -0
  159. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/extra_params_section.py +0 -0
  160. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/frame_type_section.py +0 -0
  161. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/keys_section.py +0 -0
  162. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/h52nx/multitomo_section.py +0 -0
  163. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/tests/test_context.py +0 -0
  164. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/tests/test_edf2nx_model.py +0 -0
  165. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/tests/test_fluo2nx_model.py +0 -0
  166. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/tests/test_h52nx_model.py +0 -0
  167. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/tests/test_io_utils.py +0 -0
  168. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/models/utils.py +0 -0
  169. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/settings.py +0 -0
  170. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/test.py +0 -0
  171. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/tests/__init__.py +0 -0
  172. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/tests/resources/__init__.py +0 -0
  173. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/tests/resources/edf2nx_config_files/__init__.py +0 -0
  174. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/tests/resources/fluo2nx_config_files/__init__.py +0 -0
  175. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/tests/resources/h52nx_config_files/__init__.py +0 -0
  176. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/tests/test_version.py +0 -0
  177. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/tests/utils/__init__.py +0 -0
  178. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/tests/utils/bliss.py +0 -0
  179. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/tests/utils/dxfile.py +0 -0
  180. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/__init__.py +0 -0
  181. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/_os.py +0 -0
  182. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/io.py +0 -0
  183. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/pintutils.py +0 -0
  184. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/tests/test_flat_reducer.py +0 -0
  185. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill/utils/tests/test_nexus_utils.py +0 -0
  186. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill.egg-info/dependency_links.txt +0 -0
  187. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/nxtomomill.egg-info/entry_points.txt +0 -0
  188. {nxtomomill-2.1.0.dev2 → nxtomomill-2.1.0.dev3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nxtomomill
3
- Version: 2.1.0.dev2
3
+ Version: 2.1.0.dev3
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:
@@ -55,13 +55,14 @@ License-File: LICENSE
55
55
  Requires-Dist: numpy
56
56
  Requires-Dist: h5py>=3.0
57
57
  Requires-Dist: silx>=2.0
58
- Requires-Dist: nxtomo>=3.0.0dev0
58
+ Requires-Dist: nxtomo>=3.1.0dev0
59
59
  Requires-Dist: pint
60
60
  Requires-Dist: packaging
61
61
  Requires-Dist: tomoscan[full]>=2.2.0a4
62
62
  Requires-Dist: tqdm
63
63
  Requires-Dist: pydantic
64
64
  Requires-Dist: eval_type_backport; python_version < "3.10"
65
+ Requires-Dist: platformdirs
65
66
  Provides-Extra: test
66
67
  Requires-Dist: pytest; extra == "test"
67
68
  Requires-Dist: python-gitlab; extra == "test"
@@ -11,7 +11,6 @@ For a complete tutorial you can have a look at: :ref:`Tomoh52nx`
11
11
 
12
12
  import argparse
13
13
  import logging
14
- import os
15
14
 
16
15
  from tqdm import tqdm
17
16
 
@@ -206,9 +205,10 @@ def main(argv):
206
205
  help="Y pixel size key to read",
207
206
  )
208
207
  parser.add_argument(
209
- "--read-mode",
208
+ "--open_mode_for_reading",
209
+ "--open-mode-for-reading",
210
210
  default="robust",
211
- help="Options when reading bliss file. Valid values are 'locking', 'swmr' and 'safe'. 'robust' is the default h5py read mode.",
211
+ help="Options when reading bliss file. Valid values are 'robust' or 'safe'. 'robust' is the default h5py read mode.",
212
212
  )
213
213
  # scan titles
214
214
  parser.add_argument(
@@ -301,21 +301,23 @@ def main(argv):
301
301
  help="file containing the full configuration to convert from h5 "
302
302
  "bliss to nexus",
303
303
  )
304
-
304
+ parser.add_argument(
305
+ "--use-abs-path-for-vds",
306
+ "--abs-path-for-vds",
307
+ "--use_abs_path_for_vds",
308
+ "--use-abs-path-for-vds",
309
+ default=False,
310
+ action="store_true",
311
+ help="Generated NXtomo file contains relative path by default. "
312
+ "Sometime relative link cannot be solved (GPFS vs NFS). "
313
+ "In this case you might be forced to use absolute path.",
314
+ )
305
315
  options = parser.parse_args(argv[1:])
306
316
  if options.request_input:
307
317
  callback_det_sel = _ask_for_selecting_detector
308
318
  else:
309
319
  callback_det_sel = None
310
320
 
311
- # define reading mode
312
- read_mode = os.getenv("NXTOMOMILL_HDF5_READ_MODE", "robust")
313
- if options.read_mode not in ("robust", "safe", "swmr"):
314
- raise ValueError(
315
- f"Invalid read mode: {read_mode}. Valid values are 'robust', 'safe' and 'swmr'"
316
- )
317
- os.environ["NXTOMOMILL_HDF5_READ_MODE"] = options.read_mode
318
-
319
321
  try:
320
322
  configuration_handler = TomoHDF5ConfigHandler(options)
321
323
  except Exception:
@@ -253,7 +253,9 @@ def main(argv):
253
253
  "No url provided for dark or flats or frame type to "
254
254
  "modify. Nothing to be done."
255
255
  )
256
- elif not utils.is_nx_tomo_entry(file_path=options.file_path, entry=options.entry):
256
+ elif not utils.is_nx_tomo_entry(
257
+ file_path=options.file_path, entry=options.entry, open_mode_for_reading="safe"
258
+ ):
257
259
  _logger.error(
258
260
  f"{options.entry}@{options.file_path} is not recognized as a valid NXTomo entry."
259
261
  )
@@ -292,4 +294,5 @@ def main(argv):
292
294
  flats_end=flat_end_url,
293
295
  embed_data=True,
294
296
  logger=_logger,
297
+ open_mode_for_reading="robust",
295
298
  )
@@ -47,7 +47,17 @@ def main(argv):
47
47
  help="Make all NXtomo free of any external link. As a result this will duplicate data",
48
48
  nargs="?",
49
49
  )
50
-
50
+ parser.add_argument(
51
+ "--use_abs_path_for_vds",
52
+ "--use-abs-path-for-vds",
53
+ "--abs-path-for-vds",
54
+ "--abs_path_for_vds",
55
+ default=False,
56
+ action="store_true",
57
+ help="Generated NXtomo file contains relative path by default. "
58
+ "Sometime relative link cannot be solved (GPFS vs NFS). "
59
+ "In this case you might be forced to use absolute path.",
60
+ )
51
61
  options = parser.parse_args(argv[1:])
52
62
  output_file_pattern = options.output_file_pattern
53
63
  if "{input_file_name}" in output_file_pattern:
@@ -61,6 +71,7 @@ def main(argv):
61
71
  input_file=options.input_file,
62
72
  output_file_pattern=output_file_pattern,
63
73
  overwrite=options.overwrite,
74
+ force_abs_path=options.use_abs_path_for_vds,
64
75
  )
65
76
 
66
77
 
@@ -69,11 +80,13 @@ def split(
69
80
  output_file_pattern: str,
70
81
  overwrite: bool = False,
71
82
  duplicate_data: bool = False,
83
+ force_abs_path: bool = False,
72
84
  ) -> tuple:
73
85
  """
74
86
  :param input_file: path to the file to be splitted
75
87
  :param output_file_pattern: pattern of the file to create. Must contain either `{entry_name}` or `{index}`
76
88
  :param overwrite: can we overwrite output file if alread exists
89
+ :param force_abs_path: should the generated NXtomo contains absolute path (True) or relative path (False, default)
77
90
 
78
91
  :return: tuple of identifier of all the NXtomo generated
79
92
  """
@@ -128,7 +141,10 @@ def split(
128
141
  if dirname and not os.path.exists(dirname):
129
142
  os.makedirs(dirname)
130
143
  nx_tomo.save(
131
- file_path=output_file, data_path=entry, overwrite=overwrite
144
+ file_path=output_file,
145
+ data_path=entry,
146
+ overwrite=overwrite,
147
+ use_abs_path_for_vds=force_abs_path,
132
148
  )
133
149
  result.append(NXtomoScan(output_file, entry))
134
150
 
@@ -209,7 +209,9 @@ def main(argv):
209
209
  if dummy_frame is None:
210
210
  if len(nxt.instrument.detector.data) > 0:
211
211
  # create empty frame to give it to the 'invalid_nxt' NXtomo later
212
- with DatasetReader(nxt.instrument.detector.data[0]) as raw_data:
212
+ with DatasetReader(
213
+ nxt.instrument.detector.data[0], open_mode_for_reading="safe"
214
+ ) as raw_data:
213
215
  data_type = raw_data.dtype
214
216
  # FIXME: avoid keeping some file open. not clear why this is needed
215
217
  raw_data = None
@@ -143,7 +143,7 @@ class _DxFileToNxConverter(BaseConverter):
143
143
  output_file = os.path.join(
144
144
  os.path.dirname(input_file),
145
145
  os.path.basename(input_file_basename)
146
- + self._configuration.file_extension,
146
+ + self._configuration.file_extension.value,
147
147
  )
148
148
  else:
149
149
  output_file = os.path.abspath(self.output_file)
@@ -329,7 +329,9 @@ class _DxFileToNxConverter(BaseConverter):
329
329
  self._copy_count_time()
330
330
 
331
331
  # start time
332
- with EntryReader(self.input_root_url) as input_entry:
332
+ with EntryReader(
333
+ self.input_root_url, open_mode_for_reading="safe"
334
+ ) as input_entry:
333
335
  if "file_creation_datetime" in input_entry:
334
336
  with HDF5File(self.output_file, mode="a") as h5f:
335
337
  root_grp = h5f.require_group(self.output_entry)
@@ -365,7 +367,9 @@ class _DxFileToNxConverter(BaseConverter):
365
367
  f"Failed to get 'count_time' / 'exposure_period'. reason is {e}"
366
368
  )
367
369
 
368
- with EntryReader(self.input_root_url) as input_entry:
370
+ with EntryReader(
371
+ self.input_root_url, open_mode_for_reading="safe"
372
+ ) as input_entry:
369
373
  if "measurement" in input_entry:
370
374
  measurement_grp = input_entry["measurement"]
371
375
  if "detector" in measurement_grp:
@@ -469,7 +473,9 @@ class _DxFileToNxConverter(BaseConverter):
469
473
  n_proj = 0
470
474
  # handle darks
471
475
  try:
472
- with DatasetReader(self._data_darks_url) as dark_dataset:
476
+ with DatasetReader(
477
+ self._data_darks_url, open_mode_for_reading="safe"
478
+ ) as dark_dataset:
473
479
  n_dark = dark_dataset.shape[0]
474
480
  # FIXME: avoid keeping some file open. not clear why this is needed
475
481
  dark_dataset = None
@@ -491,7 +497,9 @@ class _DxFileToNxConverter(BaseConverter):
491
497
 
492
498
  # handle flats
493
499
  try:
494
- with DatasetReader(self._data_flats_url) as flat_dataset:
500
+ with DatasetReader(
501
+ self._data_flats_url, open_mode_for_reading="safe"
502
+ ) as flat_dataset:
495
503
  n_flat = flat_dataset.shape[0]
496
504
  # FIXME: avoid keeping some file open. not clear why this is needed
497
505
  flat_dataset = None
@@ -513,7 +521,9 @@ class _DxFileToNxConverter(BaseConverter):
513
521
 
514
522
  # handle projections
515
523
  try:
516
- with DatasetReader(self._data_proj_url) as proj_dataset:
524
+ with DatasetReader(
525
+ self._data_proj_url, open_mode_for_reading="safe"
526
+ ) as proj_dataset:
517
527
  n_proj = proj_dataset.shape[0]
518
528
  # FIXME: avoid keeping some file open. not clear why this is needed
519
529
  proj_dataset = None
@@ -554,7 +564,9 @@ class _DxFileToNxConverter(BaseConverter):
554
564
  self._path_nxtomo_attrs(root_grp)
555
565
 
556
566
  def _read_sample_detector_distance(self):
557
- with EntryReader(self.input_root_url) as input_entry:
567
+ with EntryReader(
568
+ self.input_root_url, open_mode_for_reading="safe"
569
+ ) as input_entry:
558
570
  path = "/".join(
559
571
  ("measurement", "instrument", "sample", "setup", "detector_distance")
560
572
  )
@@ -568,7 +580,9 @@ class _DxFileToNxConverter(BaseConverter):
568
580
  return distance * unit
569
581
 
570
582
  def _read_energy(self):
571
- with EntryReader(self.input_root_url) as input_entry:
583
+ with EntryReader(
584
+ self.input_root_url, open_mode_for_reading="safe"
585
+ ) as input_entry:
572
586
  path = "/".join(("measurement", "instrument", "source", "energy"))
573
587
  dataset = input_entry[path]
574
588
  energy = float(h5py_read_dataset(dataset))
@@ -580,7 +594,9 @@ class _DxFileToNxConverter(BaseConverter):
580
594
  return energy * unit
581
595
 
582
596
  def _read_x_pixel_size(self):
583
- with EntryReader(self.input_root_url) as input_entry:
597
+ with EntryReader(
598
+ self.input_root_url, open_mode_for_reading="safe"
599
+ ) as input_entry:
584
600
  path = "/".join(
585
601
  ("measurement", "instrument", "detector", "actual_pixel_size_x")
586
602
  )
@@ -594,7 +610,9 @@ class _DxFileToNxConverter(BaseConverter):
594
610
  return pixel_size * unit
595
611
 
596
612
  def _read_y_pixel_size(self):
597
- with EntryReader(self.input_root_url) as input_entry:
613
+ with EntryReader(
614
+ self.input_root_url, open_mode_for_reading="safe"
615
+ ) as input_entry:
598
616
  path = "/".join(
599
617
  ("measurement", "instrument", "detector", "actual_pixel_size_y")
600
618
  )
@@ -0,0 +1,63 @@
1
+ from __future__ import annotations
2
+ import numpy
3
+ from h5py import Dataset
4
+
5
+ try:
6
+ import blosc2
7
+ import blosc2_grok
8
+ except ImportError:
9
+ _has_blosc2 = False
10
+ else:
11
+ _has_blosc2 = True
12
+
13
+
14
+ class Blosc2Jp2kWrapper:
15
+ """Wrapper to apply JP2K conversion to a dataset"""
16
+
17
+ def __init__(self, dataset: Dataset, compression_params: dict):
18
+ self.dataset: Dataset = dataset
19
+ self.compression_params: dict = self.get_default_compression_params()
20
+ self.compression_params.update(compression_params)
21
+
22
+ blosc2_grok.set_params_defaults(
23
+ # codec=blosc2.Codec.GROK,
24
+ cod_format=blosc2_grok.GrkFileFmt.GRK_FMT_JP2,
25
+ num_threads=self.compression_params["nthreads"],
26
+ quality_mode="rates",
27
+ quality_layers=numpy.array(
28
+ [self.compression_params["cratio"]],
29
+ dtype=numpy.float64,
30
+ ),
31
+ verbose=True,
32
+ )
33
+
34
+ def __setitem__(self, name, value):
35
+ z, _, _ = name
36
+ Z, Y, X = self.dataset.shape
37
+
38
+ # Verify data type compatibility
39
+ if value.dtype not in [numpy.float32, numpy.float64, numpy.uint16]:
40
+ raise ValueError(f"Unsupported dtype: {value.dtype}")
41
+
42
+ b2im = blosc2.asarray(
43
+ value.reshape(1, Y, X),
44
+ chunks=(1, Y, X),
45
+ blocks=(1, Y, X),
46
+ cparams=self.compression_params,
47
+ )
48
+ cframe = b2im.schunk.to_cframe()
49
+ self.dataset.id.write_direct_chunk((z, 0, 0), cframe, filter_mask=0)
50
+
51
+ @classmethod
52
+ def get_default_compression_params(cls) -> dict:
53
+ if _has_blosc2:
54
+ return {
55
+ "codec": blosc2.Codec.GROK,
56
+ "filters": [],
57
+ "splitmode": blosc2.SplitMode.NEVER_SPLIT,
58
+ "nthreads": 4,
59
+ "cratio": 10,
60
+ "verbose": True,
61
+ }
62
+ else:
63
+ return {}
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ import h5py
4
+ from silx.io.utils import h5py_read_dataset
5
+
6
+ __all__ = [
7
+ "BlissActiveConfig",
8
+ ]
9
+
10
+
11
+ class BlissActiveConfig:
12
+ """
13
+ hold the bliss active config. Can retrieve the 'tomo_detector' that contains information about the optic
14
+ """
15
+
16
+ def __init__(self) -> None:
17
+ self._tomo_detector: None | tuple[str, ...] = None
18
+
19
+ @property
20
+ def tomo_detector(self) -> tuple[str, ...] | None:
21
+ return self._tomo_detector
22
+
23
+ @staticmethod
24
+ def from_hdf5_group(group: h5py.Group):
25
+ """
26
+ Create an instance of 'BlissActiveConfig' from a group (containing the bliss active configuration).
27
+ """
28
+ if not isinstance(group, h5py.Group):
29
+ raise TypeError
30
+
31
+ bliss_config = BlissActiveConfig()
32
+ if "tomo_detector" in group:
33
+ bliss_config._tomo_detector = h5py_read_dataset(group["tomo_detector"])
34
+ return bliss_config
@@ -64,6 +64,7 @@ class BaseAcquisition:
64
64
  )
65
65
 
66
66
  _INSTRUMENT_NAME_PATH = (
67
+ "instrument/name",
67
68
  "technique/saving/beamline",
68
69
  "instrument/title",
69
70
  )
@@ -98,14 +99,10 @@ class BaseAcquisition:
98
99
 
99
100
  _SOURCE_NAME = ("instrument/machine/name",)
100
101
 
101
- _BEAMLINE_NAME = (
102
- "instrument/name",
103
- "instrument/title",
104
- )
105
-
106
102
  _SOURCE_TYPE = ("instrument/machine/type",)
107
103
 
108
104
  _FRAME_FLIP_PATHS = (
105
+ "instrument/{active_config_tomo_detector}/data_axes", # note: data_axes are stored in the optic and not in the camera name.
109
106
  "technique/detector/{detector_name}/flipping",
110
107
  "technique/detector/flipping",
111
108
  )
@@ -203,7 +200,7 @@ class BaseAcquisition:
203
200
  if self.configuration.single_file or not divide_sub_files:
204
201
  en_output_file = self.configuration.output_file
205
202
  else:
206
- ext = file_extension_ or self.configuration.file_extension
203
+ ext = file_extension_ or self.configuration.file_extension.value
207
204
  file_name = (
208
205
  os.path.splitext(output_file_basename)[0]
209
206
  + "_"
@@ -284,7 +281,10 @@ class BaseAcquisition:
284
281
  and self._copy_frames[url.path()]
285
282
  ):
286
283
  new_url = embed_url(url, output_file=output_file)
287
- n_vs, _, _ = from_data_url_to_virtual_source(new_url)
284
+ n_vs, _, _ = from_data_url_to_virtual_source(
285
+ new_url,
286
+ open_mode_for_reading=self.configuration.open_mode_for_reading,
287
+ )
288
288
  new_vs.append(n_vs)
289
289
  else:
290
290
  new_vs.append(vs)
@@ -294,7 +294,11 @@ class BaseAcquisition:
294
294
  if input_file_path is not None:
295
295
  nx_tomo.bliss_original_files = (abspath(input_file_path),)
296
296
  # save data
297
- nx_tomo.save(file_path=output_file, data_path=data_path)
297
+ nx_tomo.save(
298
+ file_path=output_file,
299
+ data_path=data_path,
300
+ use_abs_path_for_vds=self.configuration.use_abs_path_for_vds,
301
+ )
298
302
  # check rotation angle
299
303
  if nx_tomo.sample.rotation_angle is not None:
300
304
  unique_angles = numpy.unique(
@@ -331,7 +335,10 @@ class BaseAcquisition:
331
335
  raise NotImplementedError("Base class")
332
336
 
333
337
  def read_entry(self):
334
- return EntryReader(self._root_url)
338
+ return EntryReader(
339
+ self._root_url,
340
+ open_mode_for_reading=self.configuration.open_mode_for_reading,
341
+ )
335
342
 
336
343
  def is_different_sequence(self, entry):
337
344
  """
@@ -346,7 +353,9 @@ class BaseAcquisition:
346
353
  return False
347
354
 
348
355
  def read_sample_node(url: DataUrl) -> str | None:
349
- with EntryReader(url=url) as entry:
356
+ with EntryReader(
357
+ url=url, open_mode_for_reading=self.configuration.open_mode_for_reading
358
+ ) as entry:
350
359
  sample_node = self._get_sample_node(entry)
351
360
  if sample_node is None:
352
361
  return None
@@ -536,7 +545,10 @@ class BaseAcquisition:
536
545
  _logger.warning("no root url. Unable to read rotation motor")
537
546
  return None
538
547
  else:
539
- with EntryReader(self._root_url) as entry:
548
+ with EntryReader(
549
+ self._root_url,
550
+ open_mode_for_reading=self.configuration.open_mode_for_reading,
551
+ ) as entry:
540
552
  for motor_path in self._TECHNIQUE_MOTOR_PATHS:
541
553
  if motor_path in entry:
542
554
  try:
@@ -809,7 +821,10 @@ class BaseAcquisition:
809
821
  _logger.warning("no root url. Unable to read detector roi")
810
822
  return None
811
823
  else:
812
- with EntryReader(self._root_url) as entry:
824
+ with EntryReader(
825
+ self._root_url,
826
+ open_mode_for_reading=self.configuration.open_mode_for_reading,
827
+ ) as entry:
813
828
  for roi_path in self._DETECTOR_ROI:
814
829
  if roi_path in entry:
815
830
  try:
@@ -5,7 +5,9 @@ module to define a multi-tomo acquistion (also know as pco-tomo)
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
+ import numpy
8
9
  import logging
10
+ from datetime import timezone
9
11
 
10
12
  from silx.io.url import DataUrl
11
13
  from silx.utils.proxy import docstring
@@ -129,21 +131,27 @@ class MultiTomoAcquisition(StandardAcquisition):
129
131
  )
130
132
 
131
133
  def get_nb_loop(self, url) -> int | None:
132
- with EntryReader(url) as entry:
134
+ with EntryReader(
135
+ url, open_mode_for_reading=self.configuration.open_mode_for_reading
136
+ ) as entry:
133
137
  for path in self._NB_LOOP_PATH:
134
138
  if path in entry:
135
139
  return entry[path][()]
136
140
  return None
137
141
 
138
142
  def get_nb_tomo(self, url) -> int | None:
139
- with EntryReader(url) as entry:
143
+ with EntryReader(
144
+ url, open_mode_for_reading=self.configuration.open_mode_for_reading
145
+ ) as entry:
140
146
  for path in self._NB_TOMO_PATH:
141
147
  if path in entry:
142
148
  return entry[path][()]
143
149
  return None
144
150
 
145
151
  def get_nb_turns(self, url) -> int | None:
146
- with EntryReader(url) as entry:
152
+ with EntryReader(
153
+ url, open_mode_for_reading=self.configuration.open_mode_for_reading
154
+ ) as entry:
147
155
  for path in self._NB_TURNS_PATH:
148
156
  if path in entry:
149
157
  return entry[path][()]
@@ -167,7 +175,12 @@ class MultiTomoAcquisition(StandardAcquisition):
167
175
  return the multitomo version according to the provider version (aka bliss)
168
176
  """
169
177
  with EntryReader(
170
- url=DataUrl(file_path=url.file_path(), data_path="/", scheme=url.scheme())
178
+ url=DataUrl(
179
+ file_path=url.file_path(),
180
+ data_path="/",
181
+ scheme=url.scheme(),
182
+ ),
183
+ open_mode_for_reading=self.configuration.open_mode_for_reading,
171
184
  ) as entry:
172
185
  if "creator_version" in entry.attrs:
173
186
  creator_version = entry.attrs["creator_version"]
@@ -263,13 +276,43 @@ class MultiTomoAcquisition(StandardAcquisition):
263
276
  elif len(projections_slices) == 0:
264
277
  raise ValueError("No projection found")
265
278
  else:
266
- results.extend(
267
- splitter.split(
268
- projections_slices[0],
269
- nb_part=int(self._nb_turns),
270
- tomo_n=self._get_tomo_n(),
279
+ tomo_n = self._get_tomo_n()
280
+ try:
281
+ start_times, end_times = self._estimate_start_and_stop_times(
282
+ proj_start_index=projections_slices[0].start,
283
+ proj_stop_index=projections_slices[0].stop,
284
+ time_stamps=sorted(self._frames_timestamp),
285
+ n_proj_per_nxtomo=tomo_n,
286
+ )
287
+ except IndexError as e:
288
+ _logger.error(
289
+ f"Fail to estimate sub-NXtomo start and stop time. Error is {e}."
271
290
  )
291
+ start_times = end_times = None
292
+
293
+ sub_nxtomos = splitter.split(
294
+ projections_slices[0],
295
+ nb_part=int(self._nb_turns),
296
+ tomo_n=tomo_n,
272
297
  )
298
+ # update sub-NXtomo `start_time` and `end_time`.
299
+ if start_times is not None and end_times is not None:
300
+ if len(start_times) != len(sub_nxtomos):
301
+ _logger.error(
302
+ "Incoherent number of 'start_time' and generated sub-NXtomo. Won't modify start time."
303
+ )
304
+ else:
305
+ for start_time, end_time, sub_nxtomo in zip(
306
+ start_times, end_times, sub_nxtomos
307
+ ):
308
+ sub_nxtomo.start_time = start_time.item().replace(
309
+ tzinfo=timezone.utc
310
+ )
311
+ sub_nxtomo.end_time = end_time.item().replace(
312
+ tzinfo=timezone.utc
313
+ )
314
+
315
+ results.extend(sub_nxtomos)
273
316
 
274
317
  if check_tomo_n:
275
318
  # if angle offset provided there is an hight probably this will mess up with the tomo_n, which is expected...
@@ -374,6 +417,40 @@ class MultiTomoAcquisition(StandardAcquisition):
374
417
 
375
418
  return tuple(results)
376
419
 
420
+ @staticmethod
421
+ def _estimate_start_and_stop_times(
422
+ proj_start_index: int,
423
+ proj_stop_index: int,
424
+ time_stamps: tuple[numpy.datetime64],
425
+ n_proj_per_nxtomo: None | int,
426
+ ) -> tuple[tuple[numpy.datetime64], tuple[numpy.datetime64]] | None:
427
+ """
428
+ Estimate the starts time for sub NXtomos. For this we read the timestamp of the first projection.
429
+ We canno use the dark / flats that could be duplicated or the original start time which is the start of the bliss sequence.
430
+
431
+ .. warning: this could create a discrepancy for other scans that are using the bliss-tomo start time.
432
+ """
433
+ if n_proj_per_nxtomo is None:
434
+ _logger.error(
435
+ "Unable to know the number of projection expected per nxtomo. Unable to estimate start time."
436
+ )
437
+ return None
438
+ first_projection_indices = numpy.arange(
439
+ proj_start_index,
440
+ proj_stop_index,
441
+ step=n_proj_per_nxtomo,
442
+ dtype=numpy.uint32,
443
+ )
444
+ last_projection_indices = numpy.arange(
445
+ proj_start_index + n_proj_per_nxtomo - 1,
446
+ proj_stop_index + 1, # +1 because stop index is not included in the range
447
+ step=n_proj_per_nxtomo,
448
+ dtype=numpy.uint32,
449
+ )
450
+ return tuple([time_stamps[i] for i in first_projection_indices]), tuple(
451
+ [time_stamps[i] for i in last_projection_indices]
452
+ )
453
+
377
454
  @staticmethod
378
455
  def _get_projections_slices(nx_tomo: NXtomo) -> tuple:
379
456
  """Return a tuple of slices for each group of contiguous projections"""