tomwer 1.2.8__py3-none-any.whl → 1.3.0a0__py3-none-any.whl

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 (253) hide show
  1. orangecontrib/tomwer/tutorials/icat_publication.ows +58 -0
  2. orangecontrib/tomwer/widgets/__init__.py +1 -0
  3. orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +2 -2
  4. orangecontrib/tomwer/widgets/control/DataListOW.py +9 -7
  5. orangecontrib/tomwer/widgets/control/DataSelectorOW.py +21 -10
  6. orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +11 -5
  7. orangecontrib/tomwer/widgets/control/EmailOW.py +4 -4
  8. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +31 -18
  9. orangecontrib/tomwer/widgets/control/NXtomoConcatenate.py +14 -7
  10. orangecontrib/tomwer/widgets/control/NotifierOW.py +1 -0
  11. orangecontrib/tomwer/widgets/control/VolumeSelector.py +7 -4
  12. orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +182 -182
  13. orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +4 -4
  14. orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +4 -4
  15. orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +3 -3
  16. orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +2 -0
  17. orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +3 -3
  18. orangecontrib/tomwer/widgets/edit/test/test_nxtomo_editor.py +3 -3
  19. orangecontrib/tomwer/widgets/icat/PublishProcessedDataOW.py +115 -0
  20. orangecontrib/tomwer/widgets/icat/RawDataScreenshotCreatorOW.py +98 -0
  21. orangecontrib/tomwer/widgets/icat/SaveToGalleryAndPublishOW.py +129 -0
  22. orangecontrib/tomwer/widgets/icat/__init__.py +13 -0
  23. orangecontrib/tomwer/widgets/icat/icons/add_gallery.png +0 -0
  24. orangecontrib/tomwer/widgets/icat/icons/add_gallery.svg +82 -0
  25. orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.png +0 -0
  26. orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.svg +95 -0
  27. orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.png +0 -0
  28. orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.svg +143 -0
  29. orangecontrib/tomwer/widgets/icons/tomwer_data_portal.png +0 -0
  30. orangecontrib/tomwer/widgets/icons/tomwer_data_portal.svg +76 -0
  31. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +9 -8
  32. orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +3 -3
  33. orangecontrib/tomwer/widgets/reconstruction/NabuHelicalPrepareWeightsDoubleOW.py +179 -169
  34. orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +23 -0
  35. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +39 -5
  36. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +7 -13
  37. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +7 -17
  38. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +3 -4
  39. orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +1 -1
  40. orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +3 -3
  41. orangecontrib/tomwer/widgets/visualization/VolumeViewerOW.py +3 -29
  42. tomwer/__main__.py +11 -58
  43. tomwer/app/canvas.py +8 -0
  44. tomwer/app/canvas_launcher/config.py +13 -11
  45. tomwer/app/darkref.py +1 -1
  46. tomwer/app/darkrefpatch.py +1 -1
  47. tomwer/app/imagekeyeditor.py +5 -5
  48. tomwer/app/imagekeyupgrader.py +5 -5
  49. tomwer/app/intensitynormalization.py +2 -2
  50. tomwer/app/radiostack.py +2 -2
  51. tomwer/app/zstitching.py +74 -3
  52. tomwer/core/cluster/cluster.py +26 -0
  53. tomwer/core/log/logger.py +7 -5
  54. tomwer/core/process/conditions/filters.py +1 -1
  55. tomwer/core/process/control/datalistener/datalistener.py +3 -3
  56. tomwer/core/process/control/nxtomoconcatenate.py +13 -13
  57. tomwer/core/process/control/nxtomomill.py +83 -25
  58. tomwer/core/process/control/scantransfer.py +11 -10
  59. tomwer/core/process/control/scanvalidator.py +3 -2
  60. tomwer/core/process/control/test/test_concatenate_nxtomos.py +9 -9
  61. tomwer/core/process/control/test/test_email.py +4 -4
  62. tomwer/core/process/control/test/test_h52nx_process.py +59 -7
  63. tomwer/core/process/control/test/test_volume_link.py +64 -64
  64. tomwer/core/process/control/timer.py +1 -1
  65. tomwer/core/process/control/volumesymlink.py +200 -200
  66. tomwer/core/process/edit/darkflatpatch.py +6 -6
  67. tomwer/core/process/edit/imagekeyeditor.py +17 -18
  68. tomwer/core/process/icat/__init__.py +0 -0
  69. tomwer/core/process/icat/createscreenshots.py +100 -0
  70. tomwer/core/process/icat/gallery.py +377 -0
  71. tomwer/core/process/icat/icatbase.py +36 -0
  72. tomwer/core/process/icat/publish.py +228 -0
  73. tomwer/core/process/icat/screenshots.py +26 -0
  74. tomwer/core/process/output.py +52 -0
  75. tomwer/core/process/reconstruction/axis/axis.py +17 -10
  76. tomwer/core/process/reconstruction/axis/mode.py +4 -0
  77. tomwer/core/process/reconstruction/axis/params.py +9 -4
  78. tomwer/core/process/reconstruction/darkref/darkrefs.py +8 -6
  79. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +1 -1
  80. tomwer/core/process/reconstruction/darkref/params.py +1 -1
  81. tomwer/core/process/reconstruction/lamino/tofu.py +4 -4
  82. tomwer/core/process/reconstruction/nabu/castvolume.py +1 -1
  83. tomwer/core/process/reconstruction/nabu/helical.py +9 -5
  84. tomwer/core/process/reconstruction/nabu/nabucommon.py +32 -62
  85. tomwer/core/process/reconstruction/nabu/nabuscores.py +387 -61
  86. tomwer/core/process/reconstruction/nabu/nabuslices.py +33 -21
  87. tomwer/core/process/reconstruction/nabu/nabuvolume.py +37 -14
  88. tomwer/core/process/reconstruction/nabu/settings.py +2 -2
  89. tomwer/core/process/reconstruction/nabu/utils.py +129 -24
  90. tomwer/core/process/reconstruction/output.py +108 -0
  91. tomwer/core/process/reconstruction/saaxis/saaxis.py +233 -263
  92. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +140 -86
  93. tomwer/core/process/reconstruction/scores/params.py +4 -1
  94. tomwer/core/process/reconstruction/scores/scores.py +13 -0
  95. tomwer/core/process/reconstruction/test/test_axis_params.py +2 -2
  96. tomwer/core/process/reconstruction/test/test_darkref.py +3 -3
  97. tomwer/core/process/reconstruction/test/test_darkref_copy.py +3 -3
  98. tomwer/core/process/reconstruction/test/test_saaxis.py +3 -4
  99. tomwer/core/process/reconstruction/test/test_sadeltabeta.py +2 -2
  100. tomwer/core/process/stitching/nabustitcher.py +2 -2
  101. tomwer/core/process/test/test_axis.py +6 -6
  102. tomwer/core/process/test/test_dark_and_flat.py +10 -7
  103. tomwer/core/process/test/test_data_transfer.py +7 -6
  104. tomwer/core/process/test/test_nabu.py +4 -4
  105. tomwer/core/process/test/test_normalization.py +2 -2
  106. tomwer/core/scan/edfscan.py +4 -1
  107. tomwer/core/scan/hdf5scan.py +19 -500
  108. tomwer/core/scan/nxtomoscan.py +532 -0
  109. tomwer/core/scan/scanbase.py +42 -20
  110. tomwer/core/scan/scanfactory.py +13 -13
  111. tomwer/core/scan/test/test_future_scan.py +2 -2
  112. tomwer/core/scan/test/test_h5.py +12 -10
  113. tomwer/core/scan/test/test_process_registration.py +2 -2
  114. tomwer/core/scan/test/test_scan.py +4 -3
  115. tomwer/core/settings.py +20 -0
  116. tomwer/core/test/test_scanutils.py +8 -7
  117. tomwer/core/test/test_utils.py +33 -26
  118. tomwer/core/utils/__init__.py +0 -466
  119. tomwer/core/utils/deprecation.py +1 -1
  120. tomwer/core/utils/dictutils.py +14 -0
  121. tomwer/core/utils/lbsram.py +35 -0
  122. tomwer/core/utils/nxtomoutils.py +1 -1
  123. tomwer/core/utils/scanutils.py +6 -6
  124. tomwer/core/utils/spec.py +263 -0
  125. tomwer/core/volume/volumefactory.py +2 -2
  126. tomwer/gui/cluster/slurm.py +260 -60
  127. tomwer/gui/cluster/test/test_cluster.py +13 -0
  128. tomwer/gui/cluster/test/test_supervisor.py +2 -2
  129. tomwer/gui/configuration/__init__.py +0 -0
  130. tomwer/gui/{reconstruction/nabu → configuration}/action.py +1 -32
  131. tomwer/gui/configuration/level.py +22 -0
  132. tomwer/gui/control/actions.py +54 -0
  133. tomwer/gui/control/datalist.py +78 -16
  134. tomwer/gui/control/datalistener.py +4 -16
  135. tomwer/gui/control/{email.py → emailnotifier.py} +9 -18
  136. tomwer/gui/control/history.py +2 -2
  137. tomwer/gui/control/observations.py +2 -2
  138. tomwer/gui/control/reducedarkflatselector.py +1 -1
  139. tomwer/gui/control/selectorwidgetbase.py +36 -9
  140. tomwer/gui/control/serie/seriecreator.py +5 -22
  141. tomwer/gui/control/test/test_email.py +1 -1
  142. tomwer/gui/control/test/test_scanvalidator.py +6 -5
  143. tomwer/gui/control/test/test_single_tomo_obj.py +2 -2
  144. tomwer/gui/control/tomoobjdisplaymode.py +8 -0
  145. tomwer/gui/debugtools/datasetgenerator.py +3 -3
  146. tomwer/gui/edit/dkrfpatch.py +16 -22
  147. tomwer/gui/edit/imagekeyeditor.py +8 -11
  148. tomwer/gui/edit/nxtomoeditor.py +111 -44
  149. tomwer/gui/edit/nxtomowarmer.py +4 -4
  150. tomwer/gui/edit/test/test_dkrf_patch.py +7 -7
  151. tomwer/gui/edit/test/test_image_key_editor.py +3 -3
  152. tomwer/gui/edit/test/test_nx_editor.py +40 -16
  153. tomwer/gui/icat/__init__.py +0 -0
  154. tomwer/gui/icat/createscreenshots.py +80 -0
  155. tomwer/gui/icat/gallery.py +214 -0
  156. tomwer/gui/icat/publish.py +187 -0
  157. tomwer/gui/reconstruction/axis/axis.py +171 -57
  158. tomwer/gui/reconstruction/axis/radioaxis.py +80 -95
  159. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +3 -2
  160. tomwer/gui/reconstruction/lamino/tofu/projections.py +1 -1
  161. tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +3 -6
  162. tomwer/gui/reconstruction/nabu/castvolume.py +1 -1
  163. tomwer/gui/reconstruction/nabu/check.py +9 -9
  164. tomwer/gui/reconstruction/nabu/helical.py +29 -12
  165. tomwer/gui/reconstruction/nabu/nabuconfig/base.py +2 -4
  166. tomwer/gui/reconstruction/nabu/nabuconfig/output.py +110 -33
  167. tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +9 -12
  168. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +219 -29
  169. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +3 -6
  170. tomwer/gui/reconstruction/nabu/nabuflow.py +12 -20
  171. tomwer/gui/reconstruction/nabu/slices.py +6 -7
  172. tomwer/gui/reconstruction/nabu/volume.py +22 -10
  173. tomwer/gui/reconstruction/normalization/intensity.py +15 -23
  174. tomwer/gui/reconstruction/saaxis/corrangeselector.py +7 -23
  175. tomwer/gui/reconstruction/saaxis/dimensionwidget.py +1 -1
  176. tomwer/gui/reconstruction/saaxis/saaxis.py +7 -9
  177. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +2 -1
  178. tomwer/gui/reconstruction/scores/control.py +2 -9
  179. tomwer/gui/reconstruction/scores/scoreplot.py +11 -5
  180. tomwer/gui/reconstruction/test/test_axis.py +23 -12
  181. tomwer/gui/reconstruction/test/test_lamino.py +8 -3
  182. tomwer/gui/reconstruction/test/test_nabu.py +28 -9
  183. tomwer/gui/reconstruction/test/test_saaxis.py +3 -3
  184. tomwer/gui/reconstruction/test/test_sadeltabeta.py +2 -2
  185. tomwer/gui/settings.py +5 -28
  186. tomwer/gui/stackplot.py +2 -5
  187. tomwer/gui/stitching/action.py +49 -0
  188. tomwer/gui/stitching/config/axisparams.py +7 -24
  189. tomwer/gui/stitching/config/output.py +10 -8
  190. tomwer/gui/stitching/config/positionoveraxis.py +22 -23
  191. tomwer/gui/stitching/normalization.py +117 -0
  192. tomwer/gui/stitching/stitchandbackground.py +4 -6
  193. tomwer/gui/stitching/stitching.py +265 -43
  194. tomwer/gui/stitching/stitching_preview.py +62 -5
  195. tomwer/gui/stitching/stitching_raw.py +2 -5
  196. tomwer/gui/stitching/z_stitching/fineestimation.py +0 -60
  197. tomwer/gui/utils/buttons.py +112 -29
  198. tomwer/gui/utils/inputwidget.py +33 -25
  199. tomwer/gui/utils/scandescription.py +4 -0
  200. tomwer/gui/utils/step.py +144 -0
  201. tomwer/gui/utils/unitsystem.py +2 -5
  202. tomwer/gui/utils/vignettes.py +176 -15
  203. tomwer/gui/visualization/dataviewer.py +1 -18
  204. tomwer/gui/visualization/diffviewer/diffviewer.py +7 -16
  205. tomwer/gui/visualization/diffviewer/shiftwidget.py +2 -5
  206. tomwer/gui/visualization/scanoverview.py +1 -1
  207. tomwer/gui/visualization/sinogramviewer.py +1 -10
  208. tomwer/gui/visualization/test/test_diffviewer.py +3 -3
  209. tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +4 -4
  210. tomwer/gui/visualization/test/test_sinogramviewer.py +2 -2
  211. tomwer/gui/visualization/test/test_stacks.py +3 -3
  212. tomwer/gui/visualization/test/test_volumeviewer.py +2 -2
  213. tomwer/io/utils/raw_and_processed_data.py +84 -0
  214. tomwer/io/utils/tomoobj.py +4 -6
  215. tomwer/resources/gui/icons/ruler.png +0 -0
  216. tomwer/resources/gui/icons/ruler.svg +273 -0
  217. tomwer/resources/gui/icons/short_description.png +0 -0
  218. tomwer/resources/gui/icons/short_description.svg +58 -0
  219. tomwer/resources/gui/icons/url.png +0 -0
  220. tomwer/resources/gui/icons/url.svg +58 -0
  221. tomwer/synctools/stacks/edit/darkflatpatch.py +2 -2
  222. tomwer/synctools/stacks/edit/imagekeyeditor.py +2 -2
  223. tomwer/synctools/stacks/reconstruction/axis.py +4 -4
  224. tomwer/synctools/stacks/reconstruction/castvolume.py +2 -2
  225. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +4 -10
  226. tomwer/synctools/stacks/reconstruction/nabu.py +2 -2
  227. tomwer/synctools/stacks/reconstruction/normalization.py +2 -2
  228. tomwer/synctools/stacks/reconstruction/saaxis.py +2 -2
  229. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +2 -2
  230. tomwer/synctools/test/test_darkRefs.py +7 -58
  231. tomwer/synctools/test/test_foldertransfer.py +6 -6
  232. tomwer/synctools/utils/scanstages.py +6 -6
  233. tomwer/tests/conftest.py +34 -0
  234. tomwer/tests/datasets.py +13 -0
  235. tomwer/tests/test_scripts.py +92 -39
  236. tomwer/tests/utils.py +5 -0
  237. tomwer/version.py +3 -3
  238. {tomwer-1.2.8.dist-info → tomwer-1.3.0a0.dist-info}/METADATA +39 -44
  239. {tomwer-1.2.8.dist-info → tomwer-1.3.0a0.dist-info}/RECORD +248 -209
  240. tomwer/resources/gui/icons/esrf_1.svg +0 -307
  241. tomwer/resources/gui/icons/triangle.svg +0 -80
  242. tomwer/synctools/test/test_scanstages.py +0 -162
  243. tomwer/tests/utils/__init__.py +0 -247
  244. tomwer/tests/utils/utilstest.py +0 -220
  245. /tomwer/app/{saaxis.py → multicor.py} +0 -0
  246. /tomwer/app/{sadeltabeta.py → multipag.py} +0 -0
  247. /tomwer/core/process/control/{email.py → emailnotifier.py} +0 -0
  248. /tomwer-1.2.8-py3.11-nspkg.pth → /tomwer-1.3.0a0-py3.11-nspkg.pth +0 -0
  249. {tomwer-1.2.8.dist-info → tomwer-1.3.0a0.dist-info}/LICENSE +0 -0
  250. {tomwer-1.2.8.dist-info → tomwer-1.3.0a0.dist-info}/WHEEL +0 -0
  251. {tomwer-1.2.8.dist-info → tomwer-1.3.0a0.dist-info}/entry_points.txt +0 -0
  252. {tomwer-1.2.8.dist-info → tomwer-1.3.0a0.dist-info}/namespace_packages.txt +0 -0
  253. {tomwer-1.2.8.dist-info → tomwer-1.3.0a0.dist-info}/top_level.txt +0 -0
@@ -43,21 +43,27 @@ from processview.core.manager.manager import ProcessManager, DatasetState
43
43
  from processview.core.superviseprocess import SuperviseProcess
44
44
 
45
45
  from silx.io.utils import h5py_read_dataset
46
- from silx.utils.deprecation import deprecated_warning
46
+ from tomwer.core.utils.deprecation import deprecated_warning
47
47
 
48
48
  from tomoscan.io import HDF5File
49
49
 
50
50
  from tomwer.core.cluster.cluster import SlurmClusterConfiguration
51
51
  from tomwer.core.futureobject import FutureTomwerObject
52
52
  from tomwer.core.process.task import Task
53
+ from tomwer.core.process.icat.gallery import (
54
+ IcatScreenshots,
55
+ deduce_dataset_gallery_location,
56
+ select_screenshot_from_volume,
57
+ )
53
58
  from tomwer.core.scan.edfscan import EDFTomoScan
54
- from tomwer.core.scan.hdf5scan import HDF5TomoScan
59
+ from tomwer.core.scan.nxtomoscan import NXtomoScan
55
60
  from tomwer.core.scan.scanbase import TomwerScanBase
56
61
  from tomwer.core.scan.scanfactory import ScanFactory
62
+ from tomwer.core.utils.dictutils import concatenate_dict
57
63
  from tomwer.core.utils.scanutils import data_identifier_to_scan
64
+ from tomwer.core.volume.volumefactory import VolumeFactory
58
65
  from tomwer.io.utils.h5pyutils import EntryReader
59
66
  from tomwer.utils import docstring
60
- from tomwer.core.utils import concatenate_dict
61
67
  from tomwer.io.utils import format_stderr_stdout
62
68
 
63
69
  from . import settings, utils
@@ -143,8 +149,8 @@ def run_volume_reconstruction(
143
149
  assert len(results) == 1, "only one volume should be reconstructed"
144
150
  res = results[0]
145
151
  # tag latest reconstructions
146
- if isinstance(res, ResultsLocalRun) and res.results_urls is not None:
147
- scan.set_latest_vol_reconstructions(res.results_urls)
152
+ if isinstance(res, ResultsLocalRun) and res.results_identifiers is not None:
153
+ scan.set_latest_vol_reconstructions(res.results_identifiers)
148
154
  # create future if needed
149
155
  if isinstance(res, ResultSlurmRun):
150
156
  future_tomo_obj = FutureTomwerObject(
@@ -292,8 +298,8 @@ class VolumeRunner(_NabuBaseReconstructor):
292
298
  def process(self, fn):
293
299
  if fn.done() and not (fn.cancelled() or fn.exception()):
294
300
  # update reconstruction urls only if processing succeed.
295
- recons_urls = self.f_partial()
296
- self.scan.add_latest_vol_reconstructions(recons_urls)
301
+ recons_identifiers = self.f_partial()
302
+ self.scan.add_latest_vol_reconstructions(recons_identifiers)
297
303
 
298
304
  file_format = config_to_dump["output"]["file_format"]
299
305
  callback = functools.partial(
@@ -303,9 +309,6 @@ class VolumeRunner(_NabuBaseReconstructor):
303
309
  file_format=file_format,
304
310
  scan=self.scan,
305
311
  slice_index=None,
306
- start_z=config_to_dump["reconstruction"]["start_z"],
307
- end_z=config_to_dump["reconstruction"]["end_z"],
308
- expects_single_slice=False,
309
312
  )
310
313
 
311
314
  return (CallBack(callback, self.scan),)
@@ -346,7 +349,7 @@ class VolumeRunner(_NabuBaseReconstructor):
346
349
  """
347
350
  assert type(db) in (int, type(None))
348
351
  assert not pag == ctf == True, "cannot ask for both pag and ctf active"
349
- if isinstance(self.scan, HDF5TomoScan):
352
+ if isinstance(self.scan, NXtomoScan):
350
353
  basename, _ = os.path.splitext(self.scan.master_file)
351
354
  basename = os.path.basename(basename)
352
355
  try:
@@ -371,7 +374,7 @@ class NabuVolumeTask(
371
374
  Task,
372
375
  SuperviseProcess,
373
376
  input_names=("data", "nabu_params"),
374
- output_names=("data", "volumes", "future_tomo_obj"),
377
+ output_names=("data", "volumes", "future_tomo_obj", "screenshots"),
375
378
  optional_input_names=(
376
379
  "dry_run",
377
380
  "nabu_extra_params", # some parameter that must update 'nabu_params' before launching the reconstruction. Such as z range...
@@ -462,8 +465,8 @@ class NabuVolumeTask(
462
465
  future_tomo_obj = None
463
466
  else:
464
467
  # tag latest reconstructions
465
- if isinstance(res, ResultsLocalRun) and res.results_urls is not None:
466
- scan.set_latest_vol_reconstructions(res.results_urls)
468
+ if isinstance(res, ResultsLocalRun) and res.results_identifiers is not None:
469
+ scan.set_latest_vol_reconstructions(res.results_identifiers)
467
470
  # create future if needed
468
471
  if isinstance(res, ResultSlurmRun):
469
472
  future_tomo_obj = FutureTomwerObject(
@@ -527,6 +530,26 @@ class NabuVolumeTask(
527
530
  self.outputs.volumes = scan.latest_vol_reconstructions
528
531
  self.outputs.future_tomo_obj = future_tomo_obj
529
532
 
533
+ # build screenshots
534
+ try:
535
+ screenshots = {}
536
+ [
537
+ screenshots.update(
538
+ select_screenshot_from_volume(
539
+ VolumeFactory.create_tomo_object_from_identifier(rec_identifier)
540
+ )
541
+ )
542
+ for rec_identifier in scan.latest_vol_reconstructions
543
+ ]
544
+ except Exception as e:
545
+ _logger.error(f"screenshot creation failed. Error is {e}")
546
+ else:
547
+ self.outputs.screenshots = IcatScreenshots(
548
+ data_dir=deduce_dataset_gallery_location(scan),
549
+ screenshots=screenshots,
550
+ scan=scan,
551
+ )
552
+
530
553
  def set_configuration(self, configuration: dict) -> None:
531
554
  Task.set_configuration(self, configuration=configuration)
532
555
  if "dry_run" in configuration:
@@ -33,8 +33,6 @@ import logging
33
33
  _logger = logging.getLogger(__name__)
34
34
 
35
35
 
36
- NABU_FILE_PER_GROUP = 100
37
-
38
36
  NABU_CONFIG_FILE_EXTENSION = ".cfg"
39
37
 
40
38
  NABU_CFG_FILE_FOLDER = "nabu_cfg_files"
@@ -60,3 +58,5 @@ else:
60
58
 
61
59
 
62
60
  NABU_CAST_APP_PATH = "nabu.app.cast_volume"
61
+
62
+ NABU_MULTICOR_PATH = "nabu.app.multicor"
@@ -42,7 +42,7 @@ from silx.utils.enum import Enum as _Enum
42
42
 
43
43
  import tomwer.version
44
44
  from tomwer.core.scan.edfscan import EDFTomoScan
45
- from tomwer.core.scan.hdf5scan import HDF5TomoScan
45
+ from tomwer.core.scan.nxtomoscan import NXtomoScan
46
46
  from tomwer.core.scan.scanbase import TomwerScanBase
47
47
  from tomwer.core.volume.edfvolume import EDFVolume
48
48
  from tomwer.core.volume.hdf5volume import HDF5Volume
@@ -148,9 +148,6 @@ def get_recons_volume_identifier(
148
148
  file_format: str,
149
149
  scan: TomwerScanBase,
150
150
  slice_index: typing.Union[int, None],
151
- start_z: typing.Union[int, None],
152
- end_z: typing.Union[int, None],
153
- expects_single_slice: bool,
154
151
  ) -> tuple:
155
152
  """
156
153
  return tuple of DataUrl for existings slices
@@ -165,7 +162,7 @@ def get_recons_volume_identifier(
165
162
  file_name = ".".join((file_name, file_format))
166
163
  file_path = os.path.join(location, file_name)
167
164
 
168
- if isinstance(scan, HDF5TomoScan):
165
+ if isinstance(scan, NXtomoScan):
169
166
  entry = scan.entry
170
167
  elif isinstance(scan, EDFTomoScan):
171
168
  entry = "entry"
@@ -223,6 +220,75 @@ def get_recons_volume_identifier(
223
220
  return tuple([volume.get_identifier() for volume in volumes])
224
221
 
225
222
 
223
+ def get_multi_cor_recons_volume_identifiers(
224
+ scan: TomwerScanBase,
225
+ slice_index: int,
226
+ location: str,
227
+ file_prefix: str,
228
+ cors: tuple,
229
+ file_format: str,
230
+ ) -> dict:
231
+ """
232
+ util to retrieve Volumes (identifier) reconstructed by nabu-multicor
233
+
234
+ :param TomwerScanBase scan: scam processed by the nabu-multicor
235
+ :param str location: location of the files
236
+ :param tuple cors: cors for which we want the reconstructed slices. As this extension is created by nabu
237
+ the cor reference is in absolute.
238
+ :param str file_format: file format of the reconstruction
239
+
240
+ :return: a dict with absolute cor value as key and the Volume identifier as value
241
+ """
242
+ _logger.info("Deduce volume identifiers for nabu-multicor")
243
+ if isinstance(slice_index, str):
244
+ slice_index = slice_index_to_int(slice_index=slice_index, scan=scan)
245
+ assert isinstance(
246
+ slice_index, int
247
+ ), "slice_index is expected to be an int or to be converted to it"
248
+ res = {}
249
+ if isinstance(scan, EDFTomoScan):
250
+ entry = "entry"
251
+ else:
252
+ entry = scan.entry
253
+
254
+ for cor in cors:
255
+ file_path = os.path.join(
256
+ location,
257
+ f"{file_prefix}_{cor:.3f}_{str(slice_index).zfill(5)}.{file_format}",
258
+ )
259
+
260
+ if file_format in ("hdf5", "h5", "hdf"):
261
+ file_path = os.path.join(
262
+ location,
263
+ f"{file_prefix}_{cor:.3f}", # this level is expected to be removed on the future nabu versions
264
+ f"{file_prefix}_{cor:.3f}_{str(slice_index).zfill(5)}.{file_format}",
265
+ )
266
+ volume = HDF5Volume(
267
+ file_path=file_path,
268
+ data_path="/".join([entry, "reconstruction"]),
269
+ )
270
+ elif file_format in ("vol", "raw"):
271
+ volume = (RawVolume(file_path=file_path),)
272
+ elif file_format in ("jp2", "jp2k", "edf", "tiff"):
273
+ if file_format in ("jp2k", "jp2"):
274
+ constructor = JP2KVolume
275
+ elif file_format == "edf":
276
+ constructor = EDFVolume
277
+ elif file_format == "tiff":
278
+ constructor = TIFFVolume
279
+ else:
280
+ raise NotImplementedError
281
+ file_path = location
282
+ volume = constructor(
283
+ folder=os.path.dirname(file_path),
284
+ volume_basename=os.path.basename(file_path),
285
+ )
286
+ else:
287
+ raise ValueError(f"file_format {file_format} is not handled for now")
288
+ res[cor] = volume.get_identifier()
289
+ return res
290
+
291
+
226
292
  class _NabuMode(_Enum):
227
293
  FULL_FIELD = "standard acquisition"
228
294
  HALF_ACQ = "half acquisition"
@@ -302,24 +368,6 @@ class _NabuProcessing(_Enum):
302
368
  return (_NabuProcessing.RECONSTRUCTION,)
303
369
 
304
370
 
305
- class ConfigurationLevel(_Enum):
306
- REQUIRED = "required"
307
- OPTIONAL = "optional"
308
- ADVANCED = "advanced"
309
-
310
- def _get_num_value(self) -> int:
311
- if self is self.REQUIRED:
312
- return 0
313
- elif self is self.OPTIONAL:
314
- return 1
315
- elif self is self.ADVANCED:
316
- return 2
317
-
318
- def __le__(self, other):
319
- assert isinstance(other, ConfigurationLevel)
320
- return self._get_num_value() <= other._get_num_value()
321
-
322
-
323
371
  class _NabuPostProcessing(_Enum):
324
372
  """Define all the post processing action available"""
325
373
 
@@ -374,9 +422,12 @@ class _NabuPaddingType(_Enum):
374
422
  EDGES = "edges"
375
423
 
376
424
 
377
- class _RingCorrectionMethod(_Enum):
425
+ class RingCorrectionMethod(_Enum):
378
426
  NONE = "None"
379
427
  MUNCH = "munch"
428
+ VO = "vo"
429
+ MEAN_SUBTRACTION = "mean-subtraction"
430
+ MEAN_DIVISION = "mean-division"
380
431
 
381
432
 
382
433
  def nabu_std_err_has_error(errs: typing.Optional[bytes]):
@@ -397,6 +448,7 @@ def nabu_std_err_has_error(errs: typing.Optional[bytes]):
397
448
  or "self.module = SourceModule(self.src, **self.sourcemodule_kwargs)"
398
449
  in line
399
450
  or "return SourceModule(" in line
451
+ or "CUBLAS" in line
400
452
  )
401
453
 
402
454
  if errs is None:
@@ -438,3 +490,56 @@ def update_cfg_file_after_transfer(config_file_path, old_path, new_path):
438
490
  config=config_as_dict,
439
491
  options_level="advanced",
440
492
  )
493
+
494
+
495
+ def slice_index_to_int(
496
+ slice_index: typing.Union[int, str], scan: TomwerScanBase
497
+ ) -> int:
498
+ """
499
+ cast a slice to an index. The slice can be a string in ['first', 'last', 'middle']
500
+ """
501
+ if slice_index == "fisrt":
502
+ return 0
503
+ elif slice_index == "last":
504
+ if scan is None:
505
+ # backward compatibility in the case the scan is not provided. Should not happen anymore
506
+ _logger.warning("Scan not provided. Consider the 2048 width detector")
507
+ return 2047
508
+ elif scan.dim_2 is not None:
509
+ return scan.dim_2 - 1
510
+ else:
511
+ # this could happen on some EDF scans. Not expected to happen for HDF5
512
+ _logger.warning("unable to get dim size, guess this is 2048 width")
513
+ # in this
514
+ return 2047
515
+ elif slice_index == "middle":
516
+ if scan is None:
517
+ # backward compatibility in the case the scan is not provided. Should not happen anymore
518
+ _logger.warning("Scan not provided. Consider the 1024 width detector")
519
+ # default middle.
520
+ return 1024
521
+ elif scan.dim_2 is None:
522
+ _logger.warning("unable to get dim size, guess this is 2048 width")
523
+ return 1024
524
+ else:
525
+ return scan.dim_2 // 2
526
+ else:
527
+ return int(slice_index)
528
+
529
+
530
+ def get_nabu_multicor_file_prefix(scan):
531
+ if isinstance(scan, EDFTomoScan):
532
+ dataset_path = scan.path
533
+ elif isinstance(scan, NXtomoScan):
534
+ dataset_path = scan.master_file
535
+ else:
536
+ raise TypeError(f"{type(scan)} is not handled")
537
+
538
+ if os.path.isfile(dataset_path): # hdf5
539
+ file_prefix = os.path.basename(dataset_path).split(".")[0]
540
+ elif os.path.isdir(dataset_path):
541
+ file_prefix = os.path.basename(dataset_path)
542
+ else:
543
+ raise ValueError(f"dataset location {scan.path} is neither a file or directory")
544
+ file_prefix += "_rec" # avoid overwriting dataset
545
+ return file_prefix
@@ -0,0 +1,108 @@
1
+ from __future__ import annotations
2
+ import os
3
+ import logging
4
+ from silx.utils.enum import Enum as _Enum
5
+ from tomwer.io.utils.raw_and_processed_data import (
6
+ to_processed_data_path,
7
+ to_raw_data_path,
8
+ )
9
+ from tomwer.core.scan.scanbase import TomwerScanBase
10
+ from tomwer.core.utils.scanutils import format_output_location
11
+
12
+ _logger = logging.getLogger(__name__)
13
+
14
+
15
+ PROCESS_FOLDER_NAME = "reconstructed_volumes"
16
+
17
+
18
+ class ProcessDataOutputDirMode(_Enum):
19
+ IN_SCAN_FOLDER = "same folder as scan"
20
+ PROCESSED_DATA_FOLDER = "PROCESSED_DATA folder"
21
+ RAW_DATA_FOLDER = "RAW_DATA folder"
22
+ OTHER = "other"
23
+
24
+
25
+ class NabuOutputFileFormat(_Enum):
26
+ TIFF = "tiff"
27
+ HDF5 = "hdf5"
28
+ JP2K = "jp2"
29
+ EDF = "edf"
30
+ RAW = "vol"
31
+
32
+ @classmethod
33
+ def from_value(cls, value):
34
+ if isinstance(value, str):
35
+ value = value.lstrip(".")
36
+ return super().from_value(value)
37
+
38
+
39
+ def get_file_format(file_str):
40
+ extension = os.path.splitext(file_str.lower())[-1]
41
+ extension = extension.lstrip(".")
42
+ if extension in ("tiff", "tif"):
43
+ return NabuOutputFileFormat.TIFF
44
+ elif extension in ("hdf5", "hdf", "h5"):
45
+ return NabuOutputFileFormat.HDF5
46
+ elif extension in ("jp2", "jp2k", "jpg2k"):
47
+ return NabuOutputFileFormat.JP2K
48
+ elif extension in ("edf",):
49
+ return NabuOutputFileFormat.EDF
50
+ elif extension in ("vol", "raw"):
51
+ return NabuOutputFileFormat.RAW
52
+ else:
53
+ raise ValueError(f"Unrecognized file extension {extension} from {file_str}")
54
+
55
+
56
+ def get_output_folder_from_scan(
57
+ mode: ProcessDataOutputDirMode,
58
+ scan: TomwerScanBase,
59
+ nabu_location: str | None,
60
+ file_basename: str,
61
+ file_format: NabuOutputFileFormat,
62
+ ) -> tuple[str, str]:
63
+ """
64
+ :return: (location, location_cfg_files). Location is the nabu configuration field 'output/location' 'location_cfg_files' is the information on where to save the nabu configuration file
65
+
66
+ """
67
+ output_mode = ProcessDataOutputDirMode.from_value(mode)
68
+ file_format = NabuOutputFileFormat.from_value(file_format)
69
+
70
+ if output_mode is ProcessDataOutputDirMode.OTHER and nabu_location in ("", None):
71
+ _logger.info(
72
+ "output dir requested is other bit no path provided. Fall back on the output dir to the scan folder"
73
+ )
74
+ # note: this is only an info because we expect to pass by this one for all .ows configuration (before 1.3 version)
75
+ # as there was no different option by the time
76
+ output_mode = ProcessDataOutputDirMode.IN_SCAN_FOLDER
77
+
78
+ if output_mode is ProcessDataOutputDirMode.OTHER:
79
+ assert nabu_location not in (
80
+ "",
81
+ None,
82
+ ), "nabu_location not provided when expected"
83
+ location = format_output_location(nabu_location, scan=scan)
84
+ location_cfg_files = location
85
+ elif output_mode in (
86
+ ProcessDataOutputDirMode.IN_SCAN_FOLDER,
87
+ ProcessDataOutputDirMode.PROCESSED_DATA_FOLDER,
88
+ ProcessDataOutputDirMode.RAW_DATA_FOLDER,
89
+ ):
90
+ # otherwise default location will be the data root level
91
+ location = os.path.join(scan.path, PROCESS_FOLDER_NAME)
92
+ location_cfg_files = location
93
+ if file_format in (
94
+ NabuOutputFileFormat.EDF.value,
95
+ NabuOutputFileFormat.TIFF.value,
96
+ NabuOutputFileFormat.JP2K.value,
97
+ ): # if user specify the location
98
+ location = "/".join([location, file_basename])
99
+ if output_mode is ProcessDataOutputDirMode.PROCESSED_DATA_FOLDER:
100
+ location = to_processed_data_path(location)
101
+ location_cfg_files = to_processed_data_path(location_cfg_files)
102
+ if output_mode is ProcessDataOutputDirMode.RAW_DATA_FOLDER:
103
+ location = to_raw_data_path(location)
104
+ location_cfg_files = to_raw_data_path(location_cfg_files)
105
+ else:
106
+ raise NotImplementedError(f"mode {output_mode.value} is not implemented yet")
107
+
108
+ return location, location_cfg_files