nabu 2025.1.0rc4__tar.gz → 2025.1.0rc6__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 (331) hide show
  1. {nabu-2025.1.0rc4/nabu.egg-info → nabu-2025.1.0rc6}/PKG-INFO +1 -1
  2. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/__init__.py +1 -1
  3. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/cli_configs.py +15 -0
  4. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/estimate_motion.py +21 -0
  5. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/reader.py +12 -4
  6. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/tests/test_readers.py +37 -34
  7. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/estimators.py +7 -2
  8. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/fullfield/chunked.py +23 -9
  9. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/fullfield/processconfig.py +2 -1
  10. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/flatfield.py +3 -3
  11. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/azim.py +7 -3
  12. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/mlem.py +2 -2
  13. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/dataset_analyzer.py +35 -0
  14. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/nxflatfield.py +1 -1
  15. nabu-2025.1.0rc6/nabu/resources/tests/test_dataset_analyzer.py +37 -0
  16. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/testutils.py +34 -0
  17. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6/nabu.egg-info}/PKG-INFO +1 -1
  18. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu.egg-info/SOURCES.txt +1 -0
  19. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/LICENSE +0 -0
  20. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/README.md +0 -0
  21. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/doc/conf.py +0 -0
  22. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/doc/create_conf_doc.py +0 -0
  23. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/doc/get_mathjax.py +0 -0
  24. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/__init__.py +0 -0
  25. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/bootstrap.py +0 -0
  26. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/bootstrap_stitching.py +0 -0
  27. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/cast_volume.py +0 -0
  28. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/compare_volumes.py +0 -0
  29. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/composite_cor.py +0 -0
  30. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/create_distortion_map_from_poly.py +0 -0
  31. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/diag_to_pix.py +0 -0
  32. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/diag_to_rot.py +0 -0
  33. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/double_flatfield.py +0 -0
  34. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/generate_header.py +0 -0
  35. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/histogram.py +0 -0
  36. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/multicor.py +0 -0
  37. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/nx_z_splitter.py +0 -0
  38. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/parse_reconstruction_log.py +0 -0
  39. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/pcaflats.py +0 -0
  40. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/prepare_weights_double.py +0 -0
  41. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/reconstruct.py +0 -0
  42. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/reconstruct_helical.py +0 -0
  43. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/reduce_dark_flat.py +0 -0
  44. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/rotate.py +0 -0
  45. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/shrink_dataset.py +0 -0
  46. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/stitching.py +0 -0
  47. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/tests/__init__.py +0 -0
  48. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/tests/test_reduce_dark_flat.py +0 -0
  49. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/utils.py +0 -0
  50. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/app/validator.py +0 -0
  51. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/__init__.py +0 -0
  52. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/convolution.py +0 -0
  53. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/fft.py +0 -0
  54. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/kernel.py +0 -0
  55. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/medfilt.py +0 -0
  56. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/padding.py +0 -0
  57. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/processing.py +0 -0
  58. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/ElementOp.cu +0 -0
  59. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/backproj.cu +0 -0
  60. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/backproj_polar.cu +0 -0
  61. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/boundary.h +0 -0
  62. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/cone.cu +0 -0
  63. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/convolution.cu +0 -0
  64. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/dfi_fftshift.cu +0 -0
  65. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/flatfield.cu +0 -0
  66. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/fourier_wavelets.cu +0 -0
  67. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/halftomo.cu +0 -0
  68. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/helical_padding.cu +0 -0
  69. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/hierarchical_backproj.cu +0 -0
  70. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/histogram.cu +0 -0
  71. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/interpolation.cu +0 -0
  72. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/medfilt.cu +0 -0
  73. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/normalization.cu +0 -0
  74. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/padding.cu +0 -0
  75. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/proj.cu +0 -0
  76. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/rotation.cu +0 -0
  77. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/src/transpose.cu +0 -0
  78. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/tests/__init__.py +0 -0
  79. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/cuda/utils.py +0 -0
  80. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/__init__.py +0 -0
  81. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/alignment.py +0 -0
  82. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/cor.py +0 -0
  83. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/cor_sino.py +0 -0
  84. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/distortion.py +0 -0
  85. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/focus.py +0 -0
  86. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/motion.py +0 -0
  87. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/tests/__init__.py +0 -0
  88. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/tests/test_alignment.py +0 -0
  89. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/tests/test_cor.py +0 -0
  90. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/tests/test_focus.py +0 -0
  91. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/tests/test_motion_estimation.py +0 -0
  92. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/tests/test_tilt.py +0 -0
  93. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/tests/test_translation.py +0 -0
  94. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/tilt.py +0 -0
  95. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/translation.py +0 -0
  96. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/estimation/utils.py +0 -0
  97. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/__init__.py +0 -0
  98. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/cast_volume.py +0 -0
  99. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/detector_distortion.py +0 -0
  100. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/reader_helical.py +0 -0
  101. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/tests/__init__.py +0 -0
  102. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/tests/test_cast_volume.py +0 -0
  103. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/tests/test_remove_volume.py +0 -0
  104. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/tests/test_writers.py +0 -0
  105. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/utils.py +0 -0
  106. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/io/writer.py +0 -0
  107. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/__init__.py +0 -0
  108. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/binning.py +0 -0
  109. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/fftshift.py +0 -0
  110. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/filters.py +0 -0
  111. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/fourier_filters.py +0 -0
  112. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/histogram.py +0 -0
  113. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/histogram_cuda.py +0 -0
  114. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/kernel_base.py +0 -0
  115. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/padding.py +0 -0
  116. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/padding_base.py +0 -0
  117. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/processing_base.py +0 -0
  118. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/rotation.py +0 -0
  119. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/rotation_cuda.py +0 -0
  120. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/tests/__init__.py +0 -0
  121. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/tests/test_binning.py +0 -0
  122. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/tests/test_interpolation.py +0 -0
  123. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/transpose.py +0 -0
  124. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/unsharp.py +0 -0
  125. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/unsharp_cuda.py +0 -0
  126. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/unsharp_opencl.py +0 -0
  127. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/misc/utils.py +0 -0
  128. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/__init__.py +0 -0
  129. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/fft.py +0 -0
  130. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/kernel.py +0 -0
  131. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/memcpy.py +0 -0
  132. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/padding.py +0 -0
  133. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/processing.py +0 -0
  134. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/src/ElementOp.cl +0 -0
  135. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/src/backproj.cl +0 -0
  136. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/src/fftshift.cl +0 -0
  137. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/src/halftomo.cl +0 -0
  138. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/src/padding.cl +0 -0
  139. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/src/roll.cl +0 -0
  140. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/src/transpose.cl +0 -0
  141. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/tests/__init__.py +0 -0
  142. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/opencl/utils.py +0 -0
  143. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/__init__.py +0 -0
  144. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/config.py +0 -0
  145. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/config_validators.py +0 -0
  146. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/datadump.py +0 -0
  147. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/dataset_validator.py +0 -0
  148. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/detector_distortion_provider.py +0 -0
  149. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/fullfield/__init__.py +0 -0
  150. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/fullfield/chunked_cuda.py +0 -0
  151. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/fullfield/computations.py +0 -0
  152. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/fullfield/dataset_validator.py +0 -0
  153. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/fullfield/get_double_flatfield.py +0 -0
  154. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/fullfield/nabu_config.py +0 -0
  155. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/fullfield/reconstruction.py +0 -0
  156. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/__init__.py +0 -0
  157. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/dataset_validator.py +0 -0
  158. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/fbp.py +0 -0
  159. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/filtering.py +0 -0
  160. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/gridded_accumulator.py +0 -0
  161. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/helical_chunked_regridded.py +0 -0
  162. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/helical_chunked_regridded_cuda.py +0 -0
  163. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/helical_reconstruction.py +0 -0
  164. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/helical_utils.py +0 -0
  165. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/nabu_config.py +0 -0
  166. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/processconfig.py +0 -0
  167. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/span_strategy.py +0 -0
  168. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/tests/__init__.py +0 -0
  169. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/helical/weight_balancer.py +0 -0
  170. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/params.py +0 -0
  171. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/processconfig.py +0 -0
  172. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/reader.py +0 -0
  173. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/tests/__init__.py +0 -0
  174. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/tests/test_estimators.py +0 -0
  175. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/utils.py +0 -0
  176. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/writer.py +0 -0
  177. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/pipeline/xrdct/__init__.py +0 -0
  178. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/__init__.py +0 -0
  179. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/alignment.py +0 -0
  180. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/ccd.py +0 -0
  181. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/ccd_cuda.py +0 -0
  182. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/ctf.py +0 -0
  183. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/ctf_cuda.py +0 -0
  184. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/distortion.py +0 -0
  185. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/double_flatfield.py +0 -0
  186. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/double_flatfield_cuda.py +0 -0
  187. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/double_flatfield_variable_region.py +0 -0
  188. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/flatfield_cuda.py +0 -0
  189. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/flatfield_variable_region.py +0 -0
  190. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/phase.py +0 -0
  191. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/phase_cuda.py +0 -0
  192. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/shift.py +0 -0
  193. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/shift_cuda.py +0 -0
  194. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/tests/__init__.py +0 -0
  195. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/tests/test_ccd_corr.py +0 -0
  196. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/tests/test_ctf.py +0 -0
  197. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/tests/test_double_flatfield.py +0 -0
  198. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/tests/test_flatfield.py +0 -0
  199. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/tests/test_paganin.py +0 -0
  200. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/tests/test_pcaflats.py +0 -0
  201. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/preproc/tests/test_vshift.py +0 -0
  202. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/__init__.py +0 -0
  203. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/convolution_cuda.py +0 -0
  204. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/fft_base.py +0 -0
  205. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/fft_cuda.py +0 -0
  206. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/fft_opencl.py +0 -0
  207. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/fftshift.py +0 -0
  208. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/histogram.py +0 -0
  209. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/histogram_cuda.py +0 -0
  210. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/kernel_base.py +0 -0
  211. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/medfilt_cuda.py +0 -0
  212. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/muladd.py +0 -0
  213. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/muladd_cuda.py +0 -0
  214. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/padding_base.py +0 -0
  215. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/padding_cuda.py +0 -0
  216. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/padding_opencl.py +0 -0
  217. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/processing_base.py +0 -0
  218. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/roll_opencl.py +0 -0
  219. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/rotation.py +0 -0
  220. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/rotation_cuda.py +0 -0
  221. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/__init__.py +0 -0
  222. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/test_fft.py +0 -0
  223. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/test_fftshift.py +0 -0
  224. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/test_histogram.py +0 -0
  225. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/test_medfilt.py +0 -0
  226. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/test_muladd.py +0 -0
  227. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/test_padding.py +0 -0
  228. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/test_roll.py +0 -0
  229. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/test_rotation.py +0 -0
  230. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/test_transpose.py +0 -0
  231. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/tests/test_unsharp.py +0 -0
  232. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/transpose.py +0 -0
  233. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/unsharp.py +0 -0
  234. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/unsharp_cuda.py +0 -0
  235. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/processing/unsharp_opencl.py +0 -0
  236. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/__init__.py +0 -0
  237. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/cone.py +0 -0
  238. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/fbp.py +0 -0
  239. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/fbp_base.py +0 -0
  240. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/fbp_opencl.py +0 -0
  241. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/filtering.py +0 -0
  242. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/filtering_cuda.py +0 -0
  243. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/filtering_opencl.py +0 -0
  244. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/hbp.py +0 -0
  245. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/projection.py +0 -0
  246. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/reconstructor.py +0 -0
  247. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/reconstructor_cuda.py +0 -0
  248. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/rings.py +0 -0
  249. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/rings_cuda.py +0 -0
  250. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/sinogram.py +0 -0
  251. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/sinogram_cuda.py +0 -0
  252. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/sinogram_opencl.py +0 -0
  253. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/tests/__init__.py +0 -0
  254. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/tests/test_cone.py +0 -0
  255. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/tests/test_deringer.py +0 -0
  256. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/tests/test_fbp.py +0 -0
  257. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/tests/test_filtering.py +0 -0
  258. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/tests/test_halftomo.py +0 -0
  259. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/tests/test_mlem.py +0 -0
  260. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/tests/test_projector.py +0 -0
  261. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/tests/test_reconstructor.py +0 -0
  262. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/reconstruction/tests/test_sino_normalization.py +0 -0
  263. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/__init__.py +0 -0
  264. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/cli/__init__.py +0 -0
  265. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/cor.py +0 -0
  266. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/gpu.py +0 -0
  267. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/logger.py +0 -0
  268. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/templates/__init__.py +0 -0
  269. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/templates/bm05_pag.conf +0 -0
  270. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/templates/id16_ctf.conf +0 -0
  271. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/templates/id16_holo.conf +0 -0
  272. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/templates/id16a_fluo.conf +0 -0
  273. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/templates/id19_pag.conf +0 -0
  274. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/tests/__init__.py +0 -0
  275. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/tests/test_extract.py +0 -0
  276. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/tests/test_nxflatfield.py +0 -0
  277. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/tests/test_units.py +0 -0
  278. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/resources/utils.py +0 -0
  279. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/__init__.py +0 -0
  280. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/alignment.py +0 -0
  281. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/config.py +0 -0
  282. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/definitions.py +0 -0
  283. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/frame_composition.py +0 -0
  284. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/overlap.py +0 -0
  285. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/sample_normalization.py +0 -0
  286. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/single_axis_stitching.py +0 -0
  287. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/slurm_utils.py +0 -0
  288. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/__init__.py +0 -0
  289. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/base.py +0 -0
  290. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/dumper/__init__.py +0 -0
  291. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/dumper/base.py +0 -0
  292. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/dumper/postprocessing.py +0 -0
  293. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/dumper/preprocessing.py +0 -0
  294. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/post_processing.py +0 -0
  295. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/pre_processing.py +0 -0
  296. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/single_axis.py +0 -0
  297. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/stitcher.py +0 -0
  298. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/y_stitcher.py +0 -0
  299. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher/z_stitcher.py +0 -0
  300. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/stitcher_2D.py +0 -0
  301. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/tests/test_alignment.py +0 -0
  302. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/tests/test_config.py +0 -0
  303. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/tests/test_frame_composition.py +0 -0
  304. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/tests/test_overlap.py +0 -0
  305. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/tests/test_sample_normalization.py +0 -0
  306. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/tests/test_slurm_utils.py +0 -0
  307. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/tests/test_utils.py +0 -0
  308. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/tests/test_y_preprocessing_stitching.py +0 -0
  309. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/tests/test_z_postprocessing_stitching.py +0 -0
  310. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/tests/test_z_preprocessing_stitching.py +0 -0
  311. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/utils/__init__.py +0 -0
  312. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/utils/post_processing.py +0 -0
  313. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/utils/tests/__init__.py +0 -0
  314. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/utils/tests/test_post-processing.py +0 -0
  315. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/utils/utils.py +0 -0
  316. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/y_stitching.py +0 -0
  317. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/stitching/z_stitching.py +0 -0
  318. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/tests.py +0 -0
  319. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/thirdparty/__init__.py +0 -0
  320. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/thirdparty/algotom_convert_sino.py +0 -0
  321. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/thirdparty/pore3d_deringer_munch.py +0 -0
  322. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/thirdparty/tomocupy_remove_stripe.py +0 -0
  323. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/thirdparty/tomopy_phase.py +0 -0
  324. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/thirdparty/tomwer_load_flats_darks.py +0 -0
  325. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu/utils.py +0 -0
  326. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu.egg-info/dependency_links.txt +0 -0
  327. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu.egg-info/entry_points.txt +0 -0
  328. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu.egg-info/requires.txt +0 -0
  329. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/nabu.egg-info/top_level.txt +0 -0
  330. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/pyproject.toml +0 -0
  331. {nabu-2025.1.0rc4 → nabu-2025.1.0rc6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nabu
3
- Version: 2025.1.0rc4
3
+ Version: 2025.1.0rc6
4
4
  Summary: Nabu - Tomography software
5
5
  Author-email: Pierre Paleo <pierre.paleo@esrf.fr>, Henri Payno <henri.payno@esrf.fr>, Alessandro Mirone <mirone@esrf.fr>, Jérôme Lesaint <jerome.lesaint@esrf.fr>
6
6
  Maintainer-email: Pierre Paleo <pierre.paleo@esrf.fr>
@@ -1,4 +1,4 @@
1
- __version__ = "2025.1.0-rc4"
1
+ __version__ = "2025.1.0-rc6"
2
2
  __nabu_modules__ = [
3
3
  "app",
4
4
  "cuda",
@@ -353,6 +353,11 @@ EstimateMotionConfig = {
353
353
  "default": 2,
354
354
  "type": int,
355
355
  },
356
+ "win_size": {
357
+ "help": "Size of the look-up window for half-tomography",
358
+ "default": 300,
359
+ "type": int,
360
+ },
356
361
  "verbose": {
357
362
  "help": "Whether to plot the movement estimation fit",
358
363
  "default": 1,
@@ -365,6 +370,16 @@ EstimateMotionConfig = {
365
370
  "help": "Whether to only generate motion file for horizontal or vertical movement: --only horizontal or --only vertical",
366
371
  "default": "",
367
372
  },
373
+ "ccd_filter_size": {
374
+ "help": "Size of conditional median filter to apply on radios. Default is zero (disabled)",
375
+ "default": 0,
376
+ "type": int,
377
+ },
378
+ "ccd_filter_threshold": {
379
+ "help": "Threshold for median filter, 'ccd_filter_size' is not zero. Default is 0.04",
380
+ "default": 0.04,
381
+ "type": float,
382
+ },
368
383
  }
369
384
 
370
385
  # Default configuration for "stitching" command
@@ -1,8 +1,11 @@
1
1
  from os import path
2
+ from multiprocessing.pool import ThreadPool
2
3
 
4
+ from ..utils import get_num_threads
3
5
  from ..resources.nxflatfield import update_dataset_info_flats_darks
4
6
  from ..resources.logger import LoggerOrPrint
5
7
  from ..resources.dataset_analyzer import analyze_dataset
8
+ from ..preproc.ccd import CCDFilter
6
9
  from ..pipeline.config_validators import convert_to_bool
7
10
  from ..pipeline.estimators import TranslationsEstimator
8
11
  from .utils import parse_params_values
@@ -26,6 +29,22 @@ def estimate_motion():
26
29
  if do_ff:
27
30
  update_dataset_info_flats_darks(dataset_info, True, loading_mode="load_if_present")
28
31
 
32
+ radios_filter = None
33
+ do_ccd_filter = args["ccd_filter_size"] > 0
34
+ if do_ccd_filter:
35
+ radios_filter_obj = CCDFilter(
36
+ dataset_info.radio_dims[::-1],
37
+ kernel_size=args["ccd_filter_size"],
38
+ median_clip_thresh=args["ccd_filter_threshold"],
39
+ )
40
+
41
+ def radios_filter(images):
42
+ def _apply_median_clip(img):
43
+ radios_filter_obj.median_clip_correction(img, output=img)
44
+
45
+ with ThreadPool(get_num_threads()) as tp:
46
+ tp.map(_apply_median_clip, images)
47
+
29
48
  est = TranslationsEstimator(
30
49
  dataset_info,
31
50
  do_flatfield=do_ff,
@@ -34,6 +53,8 @@ def estimate_motion():
34
53
  deg_xy=args["deg_xy"],
35
54
  deg_z=args["deg_z"],
36
55
  shifts_estimator="phase_cross_correlation",
56
+ radios_filter=radios_filter,
57
+ extra_options={"window_size": args["win_size"]},
37
58
  )
38
59
 
39
60
  estimated_shifts_h, estimated_shifts_v, cor = est.estimate_motion()
@@ -556,7 +556,11 @@ class VolReaderBase:
556
556
  slice_x = None
557
557
  if isinstance(sub_region, (tuple, list)):
558
558
  slice_angle, slice_z, slice_x = sub_region
559
- self.sub_region = (slice_angle or slice(None, None), slice_z or slice(None, None), slice_x or slice(None, None))
559
+ self.sub_region = (
560
+ slice_angle if slice_angle is not None else slice(None, None),
561
+ slice_z if slice_z is not None else slice(None, None),
562
+ slice_x if slice_x is not None else slice(None, None),
563
+ )
560
564
 
561
565
  def _set_processing_function(self, processing_func, processing_func_args, processing_func_kwargs):
562
566
  self.processing_func = processing_func
@@ -682,9 +686,13 @@ class NXTomoReader(VolReaderBase):
682
686
  # In this case, we can use h5py read_direct() to avoid extraneous memory consumption
683
687
  image_key_slice = self._image_key_slices[0]
684
688
  # merge image key selection and user selection (if any)
685
- self._source_selection = (
686
- merge_slices(image_key_slice, self.sub_region[0] or slice(None, None)),
687
- ) + self.sub_region[1:]
689
+ angles_slice = self.sub_region[0]
690
+ if isinstance(angles_slice, slice) or angles_slice is None:
691
+ angles_slice = merge_slices(image_key_slice, self.sub_region[0] or slice(None, None))
692
+ else: # assuming numpy array
693
+ # TODO more elegant
694
+ angles_slice = np.arange(self.data_shape_total[0], dtype=np.uint64)[image_key_slice][angles_slice]
695
+ self._source_selection = (angles_slice,) + self.sub_region[1:]
688
696
  else:
689
697
  user_selection_dim0 = self.sub_region[0]
690
698
  indices = np.arange(self.data_shape_total[0])
@@ -1,41 +1,23 @@
1
1
  from math import ceil
2
2
  from tempfile import TemporaryDirectory
3
- from dataclasses import dataclass
4
3
  from tomoscan.io import HDF5File
5
4
  import pytest
6
5
  import numpy as np
7
6
  from nxtomo.application.nxtomo import ImageKey
8
7
  from tomoscan.esrf import EDFVolume
9
8
  from nabu.pipeline.reader import NXTomoReaderBinning
10
- from nabu.testutils import utilstest, __do_long_tests__, get_file
9
+ from nabu.testutils import utilstest, __do_long_tests__, get_file, get_dummy_nxtomo_info
11
10
  from nabu.utils import indices_to_slices, merge_slices
12
11
  from nabu.io.reader import EDFStackReader, NXTomoReader, NXDarksFlats
13
-
14
-
15
- @dataclass
16
- class SimpleNXTomoDescription:
17
- n_darks: int = 0
18
- n_flats1: int = 0
19
- n_projs: int = 0
20
- n_flats2: int = 0
21
- n_align: int = 0
22
- frame_shape: tuple = None
23
- dtype: np.dtype = np.uint16
12
+ from nabu.resources.dataset_analyzer import analyze_dataset
24
13
 
25
14
 
26
15
  @pytest.fixture(scope="class")
27
16
  def bootstrap_nx_reader(request):
28
17
  cls = request.cls
29
-
30
- cls.nx_fname = utilstest.getfile("dummy_nxtomo.nx")
31
- cls.nx_data_path = "entry/instrument/detector/data"
32
- cls.data_desc = SimpleNXTomoDescription(
33
- n_darks=10, n_flats1=11, n_projs=100, n_flats2=11, n_align=12, frame_shape=(11, 10), dtype=np.uint16
18
+ cls.nx_fname, cls.data_desc, cls.image_key, cls.projs_vals, cls.darks_vals, cls.flats1_vals, cls.flats2_vals = (
19
+ get_dummy_nxtomo_info()
34
20
  )
35
- cls.projs_vals = np.arange(cls.data_desc.n_projs) + cls.data_desc.n_flats1 + cls.data_desc.n_darks
36
- cls.darks_vals = np.arange(cls.data_desc.n_darks)
37
- cls.flats1_vals = np.arange(cls.data_desc.n_darks, cls.data_desc.n_darks + cls.data_desc.n_flats1)
38
- cls.flats2_vals = np.arange(cls.data_desc.n_darks, cls.data_desc.n_darks + cls.data_desc.n_flats2)
39
21
 
40
22
  yield
41
23
  # teardown
@@ -45,7 +27,7 @@ def bootstrap_nx_reader(request):
45
27
  class TestNXReader:
46
28
  def test_incorrect_path(self):
47
29
  with pytest.raises(FileNotFoundError):
48
- reader = NXTomoReader("/invalid/path", self.nx_data_path)
30
+ reader = NXTomoReader("/invalid/path")
49
31
  with pytest.raises(KeyError):
50
32
  reader = NXTomoReader(self.nx_fname, "/bad/data/path") # noqa: F841
51
33
 
@@ -53,7 +35,7 @@ class TestNXReader:
53
35
  """
54
36
  Test NXTomoReader with simplest settings
55
37
  """
56
- reader1 = NXTomoReader(self.nx_fname, self.nx_data_path)
38
+ reader1 = NXTomoReader(self.nx_fname)
57
39
  data1 = reader1.load_data()
58
40
  assert data1.shape == (self.data_desc.n_projs,) + self.data_desc.frame_shape
59
41
  assert np.allclose(data1[:, 0, 0], self.projs_vals)
@@ -62,15 +44,15 @@ class TestNXReader:
62
44
  """
63
45
  Test the data selection using "image_key".
64
46
  """
65
- reader_projs = NXTomoReader(self.nx_fname, self.nx_data_path, image_key=ImageKey.PROJECTION.value)
47
+ reader_projs = NXTomoReader(self.nx_fname, image_key=ImageKey.PROJECTION.value)
66
48
  data = reader_projs.load_data()
67
49
  assert np.allclose(data[:, 0, 0], self.projs_vals)
68
50
 
69
- reader_darks = NXTomoReader(self.nx_fname, self.nx_data_path, image_key=ImageKey.DARK_FIELD.value)
51
+ reader_darks = NXTomoReader(self.nx_fname, image_key=ImageKey.DARK_FIELD.value)
70
52
  data_darks = reader_darks.load_data()
71
53
  assert np.allclose(data_darks[:, 0, 0], self.darks_vals)
72
54
 
73
- reader_flats = NXTomoReader(self.nx_fname, self.nx_data_path, image_key=ImageKey.FLAT_FIELD.value)
55
+ reader_flats = NXTomoReader(self.nx_fname, image_key=ImageKey.FLAT_FIELD.value)
74
56
  data_flats = reader_flats.load_data()
75
57
  assert np.allclose(data_flats[:, 0, 0], np.concatenate([self.flats1_vals, self.flats2_vals]))
76
58
 
@@ -83,10 +65,10 @@ class TestNXReader:
83
65
  def _check_correct_shape_succeeds(shape, sub_region, test_description=""):
84
66
  err_msg = "Something wrong with the following test:" + test_description
85
67
  data_buffer = np.zeros(shape, dtype="f")
86
- reader1 = NXTomoReader(self.nx_fname, self.nx_data_path, sub_region=sub_region)
68
+ reader1 = NXTomoReader(self.nx_fname, sub_region=sub_region)
87
69
  data1 = reader1.load_data(output=data_buffer)
88
70
  assert id(data1) == id(data_buffer), err_msg
89
- reader2 = NXTomoReader(self.nx_fname, self.nx_data_path, sub_region=sub_region)
71
+ reader2 = NXTomoReader(self.nx_fname, sub_region=sub_region)
90
72
  data2 = reader2.load_data()
91
73
  assert np.allclose(data1, data2), err_msg
92
74
 
@@ -124,7 +106,6 @@ class TestNXReader:
124
106
  data_buffer_wrong_shape = np.zeros(wrong_shape, dtype="f")
125
107
  reader = NXTomoReader(
126
108
  self.nx_fname,
127
- self.nx_data_path,
128
109
  sub_region=test_case["sub_region"],
129
110
  )
130
111
  reader.load_data(output=data_buffer_wrong_shape)
@@ -148,7 +129,7 @@ class TestNXReader:
148
129
  ]
149
130
 
150
131
  for test_case in test_cases:
151
- reader = NXTomoReader(self.nx_fname, self.nx_data_path, sub_region=test_case["sub_region"])
132
+ reader = NXTomoReader(self.nx_fname, sub_region=test_case["sub_region"])
152
133
  data = reader.load_data()
153
134
  assert data.shape == test_case["expected_shape"]
154
135
  assert np.allclose(data[:, 0, 0], test_case["expected_values"])
@@ -156,7 +137,7 @@ class TestNXReader:
156
137
  def test_reading_with_binning_(self):
157
138
  from nabu.pipeline.reader import NXTomoReaderBinning
158
139
 
159
- reader_with_binning = NXTomoReaderBinning((2, 2), self.nx_fname, self.nx_data_path)
140
+ reader_with_binning = NXTomoReaderBinning((2, 2), self.nx_fname)
160
141
  data = reader_with_binning.load_data()
161
142
  assert data.shape == (self.data_desc.n_projs,) + tuple(n // 2 for n in self.data_desc.frame_shape)
162
143
 
@@ -177,7 +158,6 @@ class TestNXReader:
177
158
  reader_distortion_corr = NXTomoReaderDistortionCorrection(
178
159
  distortion_corrector,
179
160
  self.nx_fname,
180
- self.nx_data_path,
181
161
  sub_region=sub_region,
182
162
  )
183
163
 
@@ -220,7 +200,7 @@ class TestNXReader:
220
200
  for test_case in test_cases:
221
201
  binning = test_case.get("binning", None)
222
202
  reader_cls = NXTomoReader
223
- init_args = [self.nx_fname, self.nx_data_path]
203
+ init_args = [self.nx_fname]
224
204
  init_kwargs = {"sub_region": test_case["sub_region"]}
225
205
  if binning is not None:
226
206
  reader_cls = NXTomoReaderBinning
@@ -231,6 +211,29 @@ class TestNXReader:
231
211
  assert data.shape == test_case["expected_shape"], err_msg
232
212
  assert np.allclose(data[:, 0, 0], test_case["expected_values"]), err_msg
233
213
 
214
+ def test_load_exclude_projections(self):
215
+ n_z, n_x = self.data_desc.frame_shape
216
+ # projs_idx = np.where(self.image_key == 0)[0]
217
+ projs_idx = np.arange(self.data_desc.n_projs, dtype=np.int64)
218
+ excluded_projs_idx_1 = projs_idx[10:20]
219
+ excluded_projs_idx_2 = np.concatenate([projs_idx[10:14], projs_idx[50:57]])
220
+
221
+ set_to_nparray = lambda x: np.array(sorted(list(x)))
222
+
223
+ projs_idx1 = set_to_nparray(set(projs_idx) - set(excluded_projs_idx_1))
224
+ projs_idx2 = set_to_nparray(set(projs_idx) - set(excluded_projs_idx_2))
225
+
226
+ sub_regions_to_test = (
227
+ (projs_idx1, None, None),
228
+ (projs_idx1, slice(0, n_z // 2), None),
229
+ (projs_idx2, None, None),
230
+ (projs_idx2, slice(3, n_z // 2), None),
231
+ )
232
+ for sub_region in sub_regions_to_test:
233
+ reader = NXTomoReader(self.nx_fname, sub_region=sub_region)
234
+ data = reader.load_data()
235
+ assert np.allclose(data[:, 0, 0], self.projs_vals[sub_region[0]])
236
+
234
237
 
235
238
  @pytest.fixture(scope="class")
236
239
  def bootstrap_edf_reader(request):
@@ -1000,7 +1000,7 @@ def estimate_translations(dataset_info, do_flatfield=True): ...
1000
1000
  class TranslationsEstimator:
1001
1001
 
1002
1002
  _default_extra_options = {
1003
- "window_size": 200,
1003
+ "window_size": 300,
1004
1004
  }
1005
1005
 
1006
1006
  def __init__(
@@ -1013,6 +1013,7 @@ class TranslationsEstimator:
1013
1013
  deg_xy=2,
1014
1014
  deg_z=2,
1015
1015
  shifts_estimator="phase_cross_correlation",
1016
+ radios_filter=None,
1016
1017
  extra_options=None,
1017
1018
  ):
1018
1019
  self._configure_extra_options(extra_options)
@@ -1021,6 +1022,7 @@ class TranslationsEstimator:
1021
1022
  self.angular_subsampling = angular_subsampling
1022
1023
  self.do_360 = self.dataset_info.is_360
1023
1024
  self.do_flatfield = do_flatfield
1025
+ self.radios_filter = radios_filter
1024
1026
  self.radios = None
1025
1027
  self._deg_xy = deg_xy
1026
1028
  self._deg_z = deg_z
@@ -1163,6 +1165,9 @@ class TranslationsEstimator:
1163
1165
  def estimate_motion(self):
1164
1166
  self._load_data()
1165
1167
  self._apply_flatfield()
1168
+ if self.radios_filter is not None:
1169
+ self.logger.debug("[MotionEstimation] applying radios filter")
1170
+ self.radios_filter(self.radios)
1166
1171
 
1167
1172
  n_projs_tot = self.dataset_info.n_angles
1168
1173
  if self.do_360:
@@ -1210,7 +1215,7 @@ class TranslationsEstimator:
1210
1215
  self.sample_shifts_z = estimated_shifts_v
1211
1216
  if self._cor is None:
1212
1217
  self.logger.info(
1213
- "[MotionEstimation] Estimated center of rotation (relative to middle of detector): %.2f" % cor
1218
+ "[MotionEstimation] Estimated center of rotation (relative to left-most pixel): %.2f" % cor
1214
1219
  )
1215
1220
  return estimated_shifts_h, estimated_shifts_v, cor
1216
1221
 
@@ -1,6 +1,5 @@
1
1
  from os import path
2
2
  from time import time
3
- from math import ceil
4
3
  import numpy as np
5
4
  from silx.io.url import DataUrl
6
5
 
@@ -127,10 +126,10 @@ class ChunkedPipeline:
127
126
  if len(chunk_shape) != 3:
128
127
  raise ValueError("Expected chunk_shape to be a tuple of length 3 in the form (n_z, n_y, n_x)")
129
128
  self.chunk_shape = tuple(int(c) for c in chunk_shape) # cast to int, as numpy.int64 can make pycuda crash
130
- # TODO: sanity check (eg. compare to size of radios in dataset_info) ?
129
+ ss_start = getattr(self.process_config, "subsampling_start", 0)
131
130
  # (n_a, n_z, n_x)
132
131
  self.radios_shape = (
133
- ceil(self.chunk_shape[0] / self.process_config.subsampling_factor),
132
+ np.arange(self.chunk_shape[0])[ss_start :: self.process_config.subsampling_factor].size,
134
133
  self.chunk_shape[1] // self.process_config.binning[1],
135
134
  self.chunk_shape[2] // self.process_config.binning[0],
136
135
  )
@@ -340,13 +339,28 @@ class ChunkedPipeline:
340
339
  subs_z = None
341
340
  subs_x = None
342
341
  angular_sub_region = slice(*(self.sub_region[0]))
342
+
343
+ # exclude(subsample(.)) != subsample(exclude(.))
344
+ # Here we want the latter: first exclude the user-defined angular range, and then subsample the remaining indices
345
+ if len(self.dataset_info.get_excluded_projections_indices()) > 0:
346
+ angular_sub_region = np.array(
347
+ [
348
+ self.dataset_info.index_to_proj_number(i)
349
+ for i in sorted(list(self.dataset_info.projections.keys()))
350
+ ]
351
+ )
343
352
  if self.process_config.subsampling_factor:
344
353
  subs_angles = self.process_config.subsampling_factor
345
- angular_sub_region = slice(
346
- getattr(self.process_config, "subsampling_start", 0) + self.sub_region[0][0],
347
- self.sub_region[0][1],
348
- subs_angles,
349
- )
354
+ start = getattr(self.process_config, "subsampling_start", 0) + self.sub_region[0][0]
355
+ if isinstance(angular_sub_region, slice):
356
+ angular_sub_region = slice(
357
+ start,
358
+ self.sub_region[0][1],
359
+ subs_angles,
360
+ )
361
+ else:
362
+ angular_sub_region = angular_sub_region[start::subs_angles]
363
+
350
364
  reader_sub_region = (
351
365
  angular_sub_region,
352
366
  slice(*(self.sub_region[1]) + ((subs_z,) if subs_z else ())),
@@ -363,7 +377,7 @@ class ChunkedPipeline:
363
377
  if self.dataset_info.kind == "nx":
364
378
  self.chunk_reader = NXTomoReader(
365
379
  self.dataset_info.dataset_hdf5_url.file_path(),
366
- self.dataset_info.dataset_hdf5_url.data_path(),
380
+ data_path=self.dataset_info.dataset_hdf5_url.data_path(),
367
381
  sub_region=reader_sub_region,
368
382
  image_key=0,
369
383
  **other_reader_kwargs,
@@ -12,6 +12,7 @@ from ...resources.nxflatfield import update_dataset_info_flats_darks
12
12
  from ...resources.utils import get_quantities_and_units
13
13
  from ..estimators import estimate_cor
14
14
  from ..processconfig import ProcessConfigBase
15
+ from ..config_validators import convert_to_bool
15
16
  from .nabu_config import nabu_config, renamed_keys
16
17
  from .dataset_validator import FullFieldDatasetValidator
17
18
  from nxtomo.nxobject.nxdetector import ImageKey
@@ -475,7 +476,7 @@ class ProcessConfig(ProcessConfigBase):
475
476
  # Double flat field
476
477
  #
477
478
  # ---- COMPAT ----
478
- if nabu_config["preproc"].get("double_flatfield_enabled", False):
479
+ if convert_to_bool(nabu_config["preproc"].get("double_flatfield_enabled", False))[0]:
479
480
  deprecation_warning(
480
481
  "'double_flatfield_enabled' has been renamed to 'double_flatfield'. Please update your configuration file"
481
482
  )
@@ -456,10 +456,10 @@ class FlatFieldDataUrls(FlatField):
456
456
 
457
457
 
458
458
  class PCAFlatsNormalizer:
459
- """This class implement a flatfield normalization based on a PCA of a series of acauired flatfields.
459
+ """This class implement a flatfield normalization based on a PCA of a series of acquired flatfields.
460
460
  The PCA decomposition is handled by a PCAFlatsDecomposer object.
461
461
 
462
- This implementation was proposed by Jailin C. et al in https://doi.org/10.1107/S1600577516015812.
462
+ This implementation was proposed by Jailin C. et al in https://journals.iucr.org/s/issues/2017/01/00/fv5055/
463
463
 
464
464
  Code initially written by ID11 @ ESRF staff.
465
465
  Jonathan Wright - Implementation based on research paper
@@ -619,7 +619,7 @@ class PCAFlatsDecomposer:
619
619
  """This class implements a PCA decomposition of a serie of acquired flatfields.
620
620
  The PCA decomposition is used to normalize the projections through a PCAFLatNormalizer object.
621
621
 
622
- This implementation was proposed by Jailin C. et al in https://doi.org/10.1107/S1600577516015812.
622
+ This implementation was proposed by Jailin C. et al in https://journals.iucr.org/s/issues/2017/01/00/fv5055/
623
623
 
624
624
  Code initially written by ID11 @ ESRF staff.
625
625
  Jonathan Wright - Implementation based on research paper
@@ -96,8 +96,11 @@ def do_radial_distribution(ip, X0, Y0, mR, nBins=None, use_calibration=False, ca
96
96
  Accumulator = np.zeros((2, nBins))
97
97
 
98
98
  # Define the bounding box
99
- xmin, xmax = X0 - mR, X0 + mR
100
- ymin, ymax = Y0 - mR, Y0 + mR
99
+ height, width = ip.shape
100
+ xmin = max(int(X0 - mR), 0)
101
+ xmax = min(int(X0 + mR), width)
102
+ ymin = max(int(Y0 - mR), 0)
103
+ ymax = min(int(Y0 + mR), height)
101
104
 
102
105
  # Create grid of coordinates
103
106
  x = np.arange(xmin, xmax)
@@ -112,10 +115,11 @@ def do_radial_distribution(ip, X0, Y0, mR, nBins=None, use_calibration=False, ca
112
115
  bins = np.clip(bins - 1, 0, nBins - 1) # Adjust bins to be in range [0, nBins-1]
113
116
 
114
117
  # Accumulate values
118
+ sub_image = ip[xmin:xmax, ymin:ymax] # prevent issue on non-square images
115
119
  for b in range(nBins):
116
120
  mask = bins == b
117
121
  Accumulator[0, b] = np.sum(mask)
118
- Accumulator[1, b] = np.sum(ip[mask])
122
+ Accumulator[1, b] = np.sum(sub_image[mask])
119
123
 
120
124
  # Normalize integrated intensity
121
125
  Accumulator[1] /= Accumulator[0]
@@ -104,7 +104,7 @@ class MLEMReconstructor:
104
104
  def reset_rot_center(self, cor):
105
105
  self.cor = -cor + (self.sinos_shape[-1] - 1) / 2.0
106
106
 
107
- def reconstruct(self, data_vwu):
107
+ def reconstruct(self, data_vwu, x0=None):
108
108
  """
109
109
  data_align_vwu: numpy.ndarray or pycuda.gpuarray
110
110
  Raw data, with shape (n_sinograms, n_angles, width)
@@ -134,5 +134,5 @@ class MLEMReconstructor:
134
134
  with cct.projectors.ProjectorUncorrected(
135
135
  self.vol_geom_align, self.angles_rad, rot_axis_shift_pix=self.cor, prj_geom=self.prj_geom_align
136
136
  ) as A:
137
- rec, _ = solver(A, data_vwu, iterations=self.n_iterations, **self.solver_opts)
137
+ rec, _ = solver(A, data_vwu, iterations=self.n_iterations, x0=x0, **self.solver_opts)
138
138
  return rec * self.scale_factor
@@ -396,6 +396,11 @@ class EDFDatasetAnalyzer(DatasetAnalyzer):
396
396
  def scan_dirname(self):
397
397
  return self.dataset_scanner.path
398
398
 
399
+ def get_excluded_projections_indices(self, including_other_frames_types=True):
400
+ if not (including_other_frames_types):
401
+ raise NotImplementedError
402
+ return self.dataset_scanner.get_ignored_projection_indices()
403
+
399
404
 
400
405
  class HDF5DatasetAnalyzer(DatasetAnalyzer):
401
406
  """
@@ -606,6 +611,36 @@ class HDF5DatasetAnalyzer(DatasetAnalyzer):
606
611
  def get_frame(self, idx):
607
612
  return get_data(self.dataset_scanner.frames[idx].url)
608
613
 
614
+ def get_frames_indices(self, frame_type):
615
+ return self._select_according_to_frame_type(np.arange(self.dataset_scanner.image_key_control.size), frame_type)
616
+
617
+ def index_to_proj_number(self, proj_index):
618
+ """
619
+ Return the projection *number*, from its frame *index*.
620
+
621
+ For example if there are 11 flats before projections,
622
+ then projections will have indices [11, 12, .....] (possibly not contiguous)
623
+ while their number is [0, 1, ..., ] (contiguous, starts from 0)
624
+ """
625
+ all_projs_indices = self.get_frames_indices("projection")
626
+ return search_sorted(all_projs_indices, proj_index)
627
+
628
+ def get_excluded_projections_indices(self, including_other_frames_types=True):
629
+ # Get indices of ALL projections (even excluded ones)
630
+ # the index accounts for flats/darks !
631
+ # Get indices of excluded projs (again, accounting for flats/darks)
632
+ ignored_projs_indices = self.dataset_scanner.get_ignored_projection_indices()
633
+ ignored_projs_indices = [
634
+ idx for idx in ignored_projs_indices if self.dataset_scanner.frames[idx].is_control is False
635
+ ]
636
+ if including_other_frames_types:
637
+ return ignored_projs_indices
638
+ # Get indices of excluded projs, now relative to the pure projections stack
639
+ ignored_projs_indices_rel = [
640
+ self.index_to_proj_number(ignored_proj_idx_abs) for ignored_proj_idx_abs in ignored_projs_indices
641
+ ]
642
+ return ignored_projs_indices_rel
643
+
609
644
 
610
645
  def get_angle_at_index(all_angles, index):
611
646
  """
@@ -71,7 +71,7 @@ def save_reduced_frames(dataset_info, reduced_frames_arrays, reduced_frames_urls
71
71
  darks_flats_dir_url = reduced_frames_urls.get("user", None)
72
72
  if darks_flats_dir_url is not None:
73
73
  output_url = darks_flats_dir_url
74
- elif is_writeable(os.path.dirname(reduced_frames_urls["dataset"]["flats"].file_path())):
74
+ elif is_writeable(os.path.abspath(os.path.dirname(reduced_frames_urls["dataset"]["flats"].file_path()))):
75
75
  output_url = reduced_frames_urls["dataset"]
76
76
  else:
77
77
  output_url = reduced_frames_urls["output"]
@@ -0,0 +1,37 @@
1
+ import pytest
2
+ import numpy as np
3
+ from nabu.testutils import get_dummy_nxtomo_info
4
+ from nabu.resources.dataset_analyzer import analyze_dataset
5
+
6
+
7
+ @pytest.fixture(scope="class")
8
+ def bootstrap_nx(request):
9
+ cls = request.cls
10
+ cls.nx_fname, cls.data_desc, cls.image_key, cls.projs_vals, cls.darks_vals, cls.flats1_vals, cls.flats2_vals = (
11
+ get_dummy_nxtomo_info()
12
+ )
13
+
14
+
15
+ @pytest.mark.usefixtures("bootstrap_nx")
16
+ class TestNXDataset:
17
+
18
+ def test_exclude_projs_angular_range(self):
19
+ dataset_info_with_all_projs = analyze_dataset(self.nx_fname)
20
+
21
+ # Test exclude angular range - angles min and max in degrees
22
+ angular_ranges_to_test = [(0, 15), (5, 6), (50, 58.5)]
23
+ for angular_range in angular_ranges_to_test:
24
+ angle_min, angle_max = angular_range
25
+ dataset_info = analyze_dataset(
26
+ self.nx_fname,
27
+ extra_options={"exclude_projections": {"type": "angular_range", "range": [angle_min, angle_max]}},
28
+ )
29
+ excluded_projs_indices = dataset_info.get_excluded_projections_indices()
30
+ # Check that get_excluded_projections_indices() angles are correct
31
+ for excluded_proj_index in excluded_projs_indices:
32
+ frame_angle_deg = dataset_info.dataset_scanner.frames[excluded_proj_index].rotation_angle
33
+ assert angle_min <= frame_angle_deg and frame_angle_deg <= angle_max
34
+
35
+ assert set(dataset_info_with_all_projs.projections.keys()) - set(dataset_info.projections.keys()) == set(
36
+ excluded_projs_indices
37
+ )
@@ -1,3 +1,4 @@
1
+ from dataclasses import dataclass
1
2
  from itertools import product
2
3
  import tarfile
3
4
  import os
@@ -5,6 +6,7 @@ import numpy as np
5
6
  from scipy.signal.windows import gaussian
6
7
  from silx.resources import ExternalResources
7
8
  from silx.io.dictdump import nxtodict, dicttonx
9
+ from nxtomo.application.nxtomo import ImageKey
8
10
 
9
11
  utilstest = ExternalResources(
10
12
  project="nabu", url_base="http://www.silx.org/pub/nabu/data/", env_key="NABU_DATA", timeout=60
@@ -56,6 +58,38 @@ def get_data(*dataset_path):
56
58
  return np.load(dataset_downloaded_path)
57
59
 
58
60
 
61
+ @dataclass
62
+ class SimpleNXTomoDescription:
63
+ n_darks: int = 0
64
+ n_flats1: int = 0
65
+ n_projs: int = 0
66
+ n_flats2: int = 0
67
+ n_align: int = 0
68
+ frame_shape: tuple = None
69
+ dtype: np.dtype = np.uint16
70
+
71
+
72
+ def get_dummy_nxtomo_info():
73
+ nx_fname = utilstest.getfile("dummy_nxtomo.nx")
74
+ data_desc = SimpleNXTomoDescription(
75
+ n_darks=10, n_flats1=11, n_projs=100, n_flats2=11, n_align=12, frame_shape=(11, 10), dtype=np.uint16
76
+ )
77
+ image_key = np.concatenate(
78
+ [
79
+ np.zeros(data_desc.n_darks, dtype=np.int32) + ImageKey.DARK_FIELD.value,
80
+ np.zeros(data_desc.n_flats1, dtype=np.int32) + ImageKey.FLAT_FIELD.value,
81
+ np.zeros(data_desc.n_projs, dtype=np.int32) + ImageKey.PROJECTION.value,
82
+ np.zeros(data_desc.n_flats2, dtype=np.int32) + ImageKey.FLAT_FIELD.value,
83
+ np.zeros(data_desc.n_align, dtype=np.int32) + ImageKey.ALIGNMENT.value,
84
+ ]
85
+ )
86
+ projs_vals = np.arange(data_desc.n_projs) + data_desc.n_flats1 + data_desc.n_darks
87
+ darks_vals = np.arange(data_desc.n_darks)
88
+ flats1_vals = np.arange(data_desc.n_darks, data_desc.n_darks + data_desc.n_flats1)
89
+ flats2_vals = np.arange(data_desc.n_darks, data_desc.n_darks + data_desc.n_flats2)
90
+ return nx_fname, data_desc, image_key, projs_vals, darks_vals, flats1_vals, flats2_vals
91
+
92
+
59
93
  def get_array_of_given_shape(img, shape, dtype):
60
94
  """
61
95
  From a given image, returns an array of the wanted shape and dtype.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nabu
3
- Version: 2025.1.0rc4
3
+ Version: 2025.1.0rc6
4
4
  Summary: Nabu - Tomography software
5
5
  Author-email: Pierre Paleo <pierre.paleo@esrf.fr>, Henri Payno <henri.payno@esrf.fr>, Alessandro Mirone <mirone@esrf.fr>, Jérôme Lesaint <jerome.lesaint@esrf.fr>
6
6
  Maintainer-email: Pierre Paleo <pierre.paleo@esrf.fr>
@@ -278,6 +278,7 @@ nabu/resources/templates/id16_holo.conf
278
278
  nabu/resources/templates/id16a_fluo.conf
279
279
  nabu/resources/templates/id19_pag.conf
280
280
  nabu/resources/tests/__init__.py
281
+ nabu/resources/tests/test_dataset_analyzer.py
281
282
  nabu/resources/tests/test_extract.py
282
283
  nabu/resources/tests/test_nxflatfield.py
283
284
  nabu/resources/tests/test_units.py
File without changes
File without changes
File without changes