tomwer 1.2.1__py3-none-any.whl → 1.3.12__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 (334) hide show
  1. orangecontrib/tomwer/tutorials/icat_publication.ows +58 -0
  2. orangecontrib/tomwer/widgets/__init__.py +11 -11
  3. orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +2 -2
  4. orangecontrib/tomwer/widgets/control/DataListOW.py +9 -7
  5. orangecontrib/tomwer/widgets/control/DataListenerOW.py +6 -6
  6. orangecontrib/tomwer/widgets/control/DataSelectorOW.py +21 -10
  7. orangecontrib/tomwer/widgets/control/DataValidatorOW.py +6 -6
  8. orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +24 -7
  9. orangecontrib/tomwer/widgets/control/EmailOW.py +4 -4
  10. orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +3 -3
  11. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +64 -23
  12. orangecontrib/tomwer/widgets/control/NXtomoConcatenate.py +20 -8
  13. orangecontrib/tomwer/widgets/control/NotifierOW.py +1 -0
  14. orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +6 -6
  15. orangecontrib/tomwer/widgets/control/VolumeSelector.py +7 -4
  16. orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +182 -182
  17. orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +5 -5
  18. orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +4 -4
  19. orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +3 -3
  20. orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +8 -1
  21. orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +3 -3
  22. orangecontrib/tomwer/widgets/edit/test/test_nxtomo_editor.py +3 -3
  23. orangecontrib/tomwer/widgets/icat/PublishProcessedDataOW.py +115 -0
  24. orangecontrib/tomwer/widgets/icat/RawDataScreenshotCreatorOW.py +98 -0
  25. orangecontrib/tomwer/widgets/icat/SaveToGalleryAndPublishOW.py +129 -0
  26. orangecontrib/tomwer/widgets/icat/__init__.py +13 -0
  27. orangecontrib/tomwer/widgets/icat/icons/add_gallery.png +0 -0
  28. orangecontrib/tomwer/widgets/icat/icons/add_gallery.svg +82 -0
  29. orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.png +0 -0
  30. orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.svg +95 -0
  31. orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.png +0 -0
  32. orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.svg +143 -0
  33. orangecontrib/tomwer/widgets/icons/tomwer_data_portal.png +0 -0
  34. orangecontrib/tomwer/widgets/icons/tomwer_data_portal.svg +76 -0
  35. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +22 -20
  36. orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +19 -3
  37. orangecontrib/tomwer/widgets/reconstruction/NabuHelicalPrepareWeightsDoubleOW.py +184 -169
  38. orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +23 -0
  39. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +39 -5
  40. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +18 -22
  41. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +18 -26
  42. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +15 -19
  43. orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +9 -9
  44. orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
  45. orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +1 -1
  46. orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +3 -3
  47. orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +0 -1
  48. orangecontrib/tomwer/widgets/visualization/VolumeViewerOW.py +3 -29
  49. tomwer/__main__.py +7 -64
  50. tomwer/app/axis.py +3 -3
  51. tomwer/app/canvas.py +8 -0
  52. tomwer/app/canvas_launcher/config.py +16 -14
  53. tomwer/app/canvas_launcher/environ.py +1 -0
  54. tomwer/app/canvas_launcher/mainwindow.py +4 -1
  55. tomwer/app/darkref.py +1 -1
  56. tomwer/app/darkrefpatch.py +1 -1
  57. tomwer/app/diffframe.py +3 -3
  58. tomwer/app/imagekeyeditor.py +5 -5
  59. tomwer/app/imagekeyupgrader.py +5 -5
  60. tomwer/app/intensitynormalization.py +14 -13
  61. tomwer/app/{saaxis.py → multicor.py} +3 -3
  62. tomwer/app/{sadeltabeta.py → multipag.py} +3 -3
  63. tomwer/app/nabuapp.py +0 -11
  64. tomwer/app/radiostack.py +6 -4
  65. tomwer/app/samplemoved.py +3 -2
  66. tomwer/app/scanviewer.py +4 -2
  67. tomwer/app/sinogramviewer.py +3 -2
  68. tomwer/app/slicestack.py +3 -2
  69. tomwer/app/zstitching.py +88 -6
  70. tomwer/core/cluster/cluster.py +26 -0
  71. tomwer/core/log/logger.py +7 -5
  72. tomwer/core/process/conditions/filters.py +1 -1
  73. tomwer/core/process/control/datalistener/datalistener.py +19 -14
  74. tomwer/core/process/control/datawatcher/edfdwprocess.py +0 -9
  75. tomwer/core/process/control/nxtomoconcatenate.py +13 -13
  76. tomwer/core/process/control/nxtomomill.py +92 -34
  77. tomwer/core/process/control/scantransfer.py +20 -43
  78. tomwer/core/process/control/scanvalidator.py +3 -2
  79. tomwer/core/process/control/test/test_concatenate_nxtomos.py +9 -9
  80. tomwer/core/process/control/test/test_email.py +4 -4
  81. tomwer/core/process/control/test/test_h52nx_process.py +59 -7
  82. tomwer/core/process/control/test/test_volume_link.py +64 -64
  83. tomwer/core/process/control/timer.py +1 -1
  84. tomwer/core/process/control/volumesymlink.py +200 -200
  85. tomwer/core/process/edit/darkflatpatch.py +14 -15
  86. tomwer/core/process/edit/imagekeyeditor.py +41 -39
  87. tomwer/core/process/icat/__init__.py +0 -0
  88. tomwer/core/process/icat/createscreenshots.py +100 -0
  89. tomwer/core/process/icat/gallery.py +377 -0
  90. tomwer/core/process/icat/icatbase.py +36 -0
  91. tomwer/core/process/icat/publish.py +228 -0
  92. tomwer/core/process/icat/screenshots.py +27 -0
  93. tomwer/core/process/output.py +52 -0
  94. tomwer/core/process/reconstruction/axis/axis.py +280 -69
  95. tomwer/core/process/reconstruction/axis/mode.py +163 -48
  96. tomwer/core/process/reconstruction/axis/params.py +29 -21
  97. tomwer/core/process/reconstruction/darkref/darkrefs.py +41 -127
  98. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +4 -3
  99. tomwer/core/process/reconstruction/darkref/params.py +1 -1
  100. tomwer/core/process/reconstruction/nabu/castvolume.py +4 -4
  101. tomwer/core/process/reconstruction/nabu/helical.py +9 -5
  102. tomwer/core/process/reconstruction/nabu/nabucommon.py +71 -78
  103. tomwer/core/process/reconstruction/nabu/nabuscores.py +425 -53
  104. tomwer/core/process/reconstruction/nabu/nabuslices.py +114 -93
  105. tomwer/core/process/reconstruction/nabu/nabuvolume.py +54 -27
  106. tomwer/core/process/reconstruction/nabu/plane.py +9 -0
  107. tomwer/core/process/reconstruction/nabu/settings.py +2 -2
  108. tomwer/core/process/reconstruction/nabu/utils.py +164 -26
  109. tomwer/core/process/reconstruction/output.py +108 -0
  110. tomwer/core/process/reconstruction/saaxis/saaxis.py +238 -264
  111. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +151 -87
  112. tomwer/core/process/reconstruction/scores/params.py +7 -4
  113. tomwer/core/process/reconstruction/scores/scores.py +13 -0
  114. tomwer/core/process/reconstruction/test/test_axis_params.py +2 -2
  115. tomwer/core/process/reconstruction/test/test_darkref.py +3 -3
  116. tomwer/core/process/reconstruction/test/test_darkref_copy.py +7 -7
  117. tomwer/core/process/reconstruction/test/test_saaxis.py +3 -4
  118. tomwer/core/process/reconstruction/test/test_sadeltabeta.py +2 -2
  119. tomwer/core/process/stitching/nabustitcher.py +13 -12
  120. tomwer/core/process/task.py +34 -26
  121. tomwer/core/process/test/test_axis.py +13 -12
  122. tomwer/core/process/test/test_dark_and_flat.py +10 -7
  123. tomwer/core/process/test/test_data_transfer.py +10 -8
  124. tomwer/core/process/test/test_nabu.py +14 -6
  125. tomwer/core/process/test/test_normalization.py +4 -4
  126. tomwer/core/scan/blissscan.py +3 -3
  127. tomwer/core/scan/edfscan.py +13 -10
  128. tomwer/core/scan/hdf5scan.py +19 -530
  129. tomwer/core/scan/nxtomoscan.py +534 -0
  130. tomwer/core/scan/scanbase.py +72 -44
  131. tomwer/core/scan/scanfactory.py +13 -13
  132. tomwer/core/scan/test/test_edf.py +2 -2
  133. tomwer/core/scan/test/test_future_scan.py +3 -3
  134. tomwer/core/scan/test/test_h5.py +18 -16
  135. tomwer/core/scan/test/test_process_registration.py +4 -40
  136. tomwer/core/scan/test/test_scan.py +5 -78
  137. tomwer/core/settings.py +22 -2
  138. tomwer/core/test/test_scanutils.py +8 -7
  139. tomwer/core/test/test_utils.py +35 -28
  140. tomwer/core/tomwer_object.py +1 -1
  141. tomwer/core/utils/__init__.py +0 -466
  142. tomwer/core/utils/deprecation.py +1 -1
  143. tomwer/core/utils/dictutils.py +14 -0
  144. tomwer/core/utils/lbsram.py +35 -0
  145. tomwer/core/utils/nxtomoutils.py +1 -1
  146. tomwer/core/utils/scanutils.py +6 -6
  147. tomwer/core/utils/spec.py +263 -0
  148. tomwer/core/volume/edfvolume.py +6 -6
  149. tomwer/core/volume/hdf5volume.py +6 -6
  150. tomwer/core/volume/jp2kvolume.py +6 -6
  151. tomwer/core/volume/rawvolume.py +6 -6
  152. tomwer/core/volume/tiffvolume.py +12 -12
  153. tomwer/core/volume/volumefactory.py +2 -2
  154. tomwer/gui/cluster/slurm.py +274 -65
  155. tomwer/gui/cluster/supervisor.py +12 -0
  156. tomwer/gui/cluster/test/test_cluster.py +14 -2
  157. tomwer/gui/cluster/test/test_supervisor.py +3 -3
  158. tomwer/gui/configuration/__init__.py +0 -0
  159. tomwer/gui/{reconstruction/nabu → configuration}/action.py +1 -32
  160. tomwer/gui/configuration/level.py +22 -0
  161. tomwer/gui/control/actions.py +54 -0
  162. tomwer/gui/control/datalist.py +83 -16
  163. tomwer/gui/control/datalistener.py +4 -16
  164. tomwer/gui/control/datawatcher/controlwidget.py +2 -4
  165. tomwer/gui/control/datawatcher/datawatcher.py +1 -24
  166. tomwer/gui/control/{email.py → emailnotifier.py} +9 -18
  167. tomwer/gui/control/history.py +2 -2
  168. tomwer/gui/control/observations.py +2 -2
  169. tomwer/gui/control/reducedarkflatselector.py +9 -9
  170. tomwer/gui/control/selectorwidgetbase.py +36 -9
  171. tomwer/gui/control/serie/seriecreator.py +5 -22
  172. tomwer/gui/control/test/test_email.py +1 -1
  173. tomwer/gui/control/test/test_scanvalidator.py +6 -5
  174. tomwer/gui/control/test/test_single_tomo_obj.py +3 -3
  175. tomwer/gui/control/tomoobjdisplaymode.py +8 -0
  176. tomwer/gui/debugtools/datasetgenerator.py +3 -3
  177. tomwer/gui/edit/dkrfpatch.py +20 -26
  178. tomwer/gui/edit/imagekeyeditor.py +11 -12
  179. tomwer/gui/edit/nxtomoeditor.py +111 -44
  180. tomwer/gui/edit/nxtomowarmer.py +7 -6
  181. tomwer/gui/edit/test/test_dkrf_patch.py +13 -13
  182. tomwer/gui/edit/test/test_image_key_editor.py +3 -3
  183. tomwer/gui/edit/test/test_nx_editor.py +40 -16
  184. tomwer/gui/icat/__init__.py +0 -0
  185. tomwer/gui/icat/createscreenshots.py +80 -0
  186. tomwer/gui/icat/gallery.py +214 -0
  187. tomwer/gui/icat/publish.py +187 -0
  188. tomwer/gui/imagefromfile.py +2 -2
  189. tomwer/gui/qfolderdialog.py +24 -1
  190. tomwer/gui/reconstruction/axis/CompareImages.py +88 -168
  191. tomwer/gui/reconstruction/axis/axis.py +171 -57
  192. tomwer/gui/reconstruction/axis/radioaxis.py +122 -257
  193. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +3 -2
  194. tomwer/gui/reconstruction/darkref/darkrefwidget.py +2 -1
  195. tomwer/gui/reconstruction/nabu/castvolume.py +14 -3
  196. tomwer/gui/reconstruction/nabu/check.py +9 -9
  197. tomwer/gui/reconstruction/nabu/helical.py +29 -12
  198. tomwer/gui/reconstruction/nabu/nabuconfig/base.py +2 -4
  199. tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +2 -1
  200. tomwer/gui/reconstruction/nabu/nabuconfig/output.py +126 -35
  201. tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +39 -32
  202. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +222 -31
  203. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +57 -27
  204. tomwer/gui/reconstruction/nabu/nabuflow.py +12 -20
  205. tomwer/gui/reconstruction/nabu/slices.py +10 -11
  206. tomwer/gui/reconstruction/nabu/volume.py +22 -10
  207. tomwer/gui/reconstruction/normalization/intensity.py +18 -48
  208. tomwer/gui/reconstruction/saaxis/corrangeselector.py +8 -24
  209. tomwer/gui/reconstruction/saaxis/dimensionwidget.py +1 -1
  210. tomwer/gui/reconstruction/saaxis/saaxis.py +9 -21
  211. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +45 -12
  212. tomwer/gui/reconstruction/scores/control.py +2 -9
  213. tomwer/gui/reconstruction/scores/scoreplot.py +13 -11
  214. tomwer/gui/reconstruction/test/test_axis.py +41 -16
  215. tomwer/gui/reconstruction/test/test_nabu.py +31 -9
  216. tomwer/gui/reconstruction/test/test_saaxis.py +3 -3
  217. tomwer/gui/reconstruction/test/test_sadeltabeta.py +12 -2
  218. tomwer/gui/settings.py +5 -28
  219. tomwer/gui/stackplot.py +2 -5
  220. tomwer/gui/stitching/action.py +49 -0
  221. tomwer/gui/stitching/config/axisparams.py +7 -24
  222. tomwer/gui/stitching/config/output.py +10 -8
  223. tomwer/gui/stitching/config/positionoveraxis.py +22 -23
  224. tomwer/gui/stitching/normalization.py +117 -0
  225. tomwer/gui/stitching/stitchandbackground.py +4 -6
  226. tomwer/gui/stitching/stitching.py +267 -45
  227. tomwer/gui/stitching/stitching_preview.py +62 -55
  228. tomwer/gui/stitching/stitching_raw.py +13 -12
  229. tomwer/gui/stitching/z_stitching/fineestimation.py +0 -60
  230. tomwer/gui/utils/buttons.py +112 -29
  231. tomwer/gui/utils/inputwidget.py +43 -25
  232. tomwer/gui/utils/lineselector/lineselector.py +1 -1
  233. tomwer/gui/utils/scandescription.py +4 -0
  234. tomwer/gui/utils/step.py +144 -0
  235. tomwer/gui/utils/unitsystem.py +2 -5
  236. tomwer/gui/utils/vignettes.py +176 -15
  237. tomwer/gui/visualization/dataviewer.py +48 -35
  238. tomwer/gui/visualization/diffviewer/diffviewer.py +7 -16
  239. tomwer/gui/visualization/diffviewer/shiftwidget.py +2 -5
  240. tomwer/gui/visualization/scanoverview.py +1 -1
  241. tomwer/gui/visualization/sinogramviewer.py +20 -36
  242. tomwer/gui/visualization/test/test_diffviewer.py +3 -3
  243. tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +4 -4
  244. tomwer/gui/visualization/test/test_sinogramviewer.py +2 -2
  245. tomwer/gui/visualization/test/test_stacks.py +3 -3
  246. tomwer/gui/visualization/test/test_volumeviewer.py +65 -67
  247. tomwer/gui/visualization/volumeviewer.py +114 -113
  248. tomwer/io/utils/h5pyutils.py +3 -3
  249. tomwer/io/utils/raw_and_processed_data.py +84 -0
  250. tomwer/io/utils/tomoobj.py +4 -6
  251. tomwer/io/utils/utils.py +7 -7
  252. tomwer/resources/gui/icons/parameters.svg +1 -1
  253. tomwer/resources/gui/icons/ruler.png +0 -0
  254. tomwer/resources/gui/icons/ruler.svg +273 -0
  255. tomwer/resources/gui/icons/short_description.png +0 -0
  256. tomwer/resources/gui/icons/short_description.svg +58 -0
  257. tomwer/resources/gui/icons/url.png +0 -0
  258. tomwer/resources/gui/icons/url.svg +58 -0
  259. tomwer/resources/gui/illustrations/no_rot.svg +1 -1
  260. tomwer/synctools/stacks/edit/darkflatpatch.py +19 -14
  261. tomwer/synctools/stacks/edit/imagekeyeditor.py +2 -2
  262. tomwer/synctools/stacks/reconstruction/axis.py +4 -4
  263. tomwer/synctools/stacks/reconstruction/castvolume.py +22 -7
  264. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +25 -20
  265. tomwer/synctools/stacks/reconstruction/nabu.py +2 -2
  266. tomwer/synctools/stacks/reconstruction/normalization.py +2 -2
  267. tomwer/synctools/stacks/reconstruction/saaxis.py +2 -2
  268. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +2 -2
  269. tomwer/synctools/test/test_darkRefs.py +7 -58
  270. tomwer/synctools/test/test_foldertransfer.py +6 -6
  271. tomwer/synctools/utils/scanstages.py +6 -6
  272. tomwer/tests/conftest.py +34 -0
  273. tomwer/tests/datasets.py +13 -0
  274. tomwer/tests/test_scripts.py +91 -41
  275. tomwer/tests/utils.py +5 -0
  276. tomwer/third_part/WaitingOverlay.py +110 -0
  277. tomwer/third_part/__init__.py +0 -0
  278. tomwer/version.py +2 -2
  279. tomwer-1.3.12-py3.11-nspkg.pth +1 -0
  280. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/METADATA +73 -58
  281. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/RECORD +287 -286
  282. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/WHEEL +1 -1
  283. orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +0 -197
  284. orangecontrib/tomwer/widgets/reconstruction/icons/XY_lamino.svg +0 -168
  285. orangecontrib/tomwer/widgets/reconstruction/icons/XZ_lamino.svg +0 -275
  286. orangecontrib/tomwer/widgets/reconstruction/icons/YZ_lamino.svg +0 -182
  287. tomwer/app/lamino.py +0 -143
  288. tomwer/core/process/reconstruction/lamino/__init__.py +0 -1
  289. tomwer/core/process/reconstruction/lamino/tofu.py +0 -1000
  290. tomwer/core/process/test/test_lamino.py +0 -76
  291. tomwer/core/test/test_lamino.py +0 -92
  292. tomwer/gui/reconstruction/lamino/__init__.py +0 -31
  293. tomwer/gui/reconstruction/lamino/tofu/TofuOptionLoader.py +0 -107
  294. tomwer/gui/reconstruction/lamino/tofu/__init__.py +0 -1
  295. tomwer/gui/reconstruction/lamino/tofu/misc.py +0 -148
  296. tomwer/gui/reconstruction/lamino/tofu/projections.py +0 -896
  297. tomwer/gui/reconstruction/lamino/tofu/settings.py +0 -75
  298. tomwer/gui/reconstruction/lamino/tofu/tofu.py +0 -432
  299. tomwer/gui/reconstruction/lamino/tofu/tofuexpert.py +0 -567
  300. tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +0 -760
  301. tomwer/gui/reconstruction/test/test_lamino.py +0 -189
  302. tomwer/resources/gui/icons/esrf_1.svg +0 -307
  303. tomwer/resources/gui/icons/lamino_parameters.svg +0 -70
  304. tomwer/resources/gui/icons/triangle.svg +0 -80
  305. tomwer/resources/gui/illustrations/lamino_angle.png +0 -0
  306. tomwer/resources/gui/illustrations/lamino_angle.svg +0 -509
  307. tomwer/resources/gui/illustrations/lamino_beta_angle.png +0 -0
  308. tomwer/resources/gui/illustrations/lamino_beta_angle.svg +0 -97
  309. tomwer/resources/gui/illustrations/lamino_theta_angle.png +0 -0
  310. tomwer/resources/gui/illustrations/lamino_theta_angle.svg +0 -368
  311. tomwer/resources/gui/illustrations/manual_slice.png +0 -0
  312. tomwer/resources/gui/illustrations/manual_slice.svg +0 -221
  313. tomwer/resources/gui/illustrations/psi_angle.png +0 -0
  314. tomwer/resources/gui/illustrations/psi_angle.svg +0 -479
  315. tomwer/resources/gui/illustrations/rotation_center.png +0 -0
  316. tomwer/resources/gui/illustrations/rotation_center.svg +0 -276
  317. tomwer/resources/gui/illustrations/slice_stack.png +0 -0
  318. tomwer/resources/gui/illustrations/slice_stack.svg +0 -266
  319. tomwer/resources/gui/illustrations/xy_slice.png +0 -0
  320. tomwer/resources/gui/illustrations/xy_slice.svg +0 -269
  321. tomwer/resources/gui/illustrations/xz_slice.png +0 -0
  322. tomwer/resources/gui/illustrations/xz_slice.svg +0 -270
  323. tomwer/resources/gui/illustrations/yz_slice.png +0 -0
  324. tomwer/resources/gui/illustrations/yz_slice.svg +0 -270
  325. tomwer/synctools/stacks/reconstruction/lamino.py +0 -233
  326. tomwer/synctools/test/test_scanstages.py +0 -162
  327. tomwer/tests/utils/__init__.py +0 -247
  328. tomwer/tests/utils/utilstest.py +0 -220
  329. tomwer-1.2.1-py3.11-nspkg.pth +0 -1
  330. /tomwer/core/process/control/{email.py → emailnotifier.py} +0 -0
  331. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/LICENSE +0 -0
  332. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/entry_points.txt +0 -0
  333. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/namespace_packages.txt +0 -0
  334. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/top_level.txt +0 -0
@@ -32,27 +32,26 @@ __license__ = "MIT"
32
32
  __date__ = "10/02/2021"
33
33
 
34
34
 
35
- import copy
36
35
  import logging
37
36
  import os
38
37
  from typing import Optional
39
38
 
40
39
  import h5py
41
40
  import numpy
41
+ from multiprocessing import Pool
42
42
  from processview.core.manager import DatasetState, ProcessManager
43
43
  from processview.core.superviseprocess import SuperviseProcess
44
44
  from silx.io.url import DataUrl
45
- from silx.utils.deprecation import deprecated_warning
45
+ from tomwer.core.utils.deprecation import deprecated_warning
46
46
 
47
47
  from tomoscan.io import HDF5File
48
48
 
49
49
  import tomwer.version
50
50
  from tomwer.core.process.reconstruction.axis import AxisRP
51
51
  from tomwer.core.process.reconstruction.nabu.nabuscores import (
52
- run_nabu_one_slice_several_config,
52
+ run_nabu_multicor,
53
53
  )
54
54
  from tomwer.core.process.reconstruction.nabu.nabuslices import (
55
- SingleSliceRunner,
56
55
  interpret_tomwer_configuration,
57
56
  )
58
57
  from tomwer.core.process.reconstruction.scores import (
@@ -63,9 +62,7 @@ from tomwer.core.process.reconstruction.scores import (
63
62
  )
64
63
  from tomwer.core.process.reconstruction.scores.params import ScoreMethod
65
64
  from tomwer.core.process.task import Task
66
- from tomwer.core.progress import Progress
67
- from tomwer.core.scan.edfscan import EDFTomoScan
68
- from tomwer.core.scan.hdf5scan import HDF5TomoScan
65
+ from tomwer.core.scan.nxtomoscan import NXtomoScan
69
66
  from tomwer.core.scan.scanbase import TomwerScanBase
70
67
  from tomwer.core.scan.scanfactory import ScanFactory
71
68
  from tomwer.core.utils import logconfig
@@ -82,6 +79,11 @@ from tomwer.core.process.reconstruction.nabu.nabucommon import (
82
79
  )
83
80
  from tomwer.core.futureobject import FutureTomwerObject
84
81
  from tomwer.core.process.reconstruction.saaxis.params import ReconstructionMode
82
+ from tomwer.core.process.reconstruction.nabu.utils import (
83
+ get_multi_cor_recons_volume_identifiers,
84
+ get_nabu_multicor_file_prefix,
85
+ )
86
+ from tomwer.core.process.reconstruction.nabu.nabuscores import _ReconstructorMultiCor
85
87
 
86
88
  from ..nabu import utils
87
89
  from .params import SAAxisParams
@@ -89,7 +91,7 @@ from .params import SAAxisParams
89
91
  _logger = logging.getLogger(__name__)
90
92
 
91
93
 
92
- DEFAULT_RECONS_FOLDER = "saaxis_results"
94
+ DEFAULT_RECONS_FOLDER = "multi_cor_results"
93
95
 
94
96
 
95
97
  def one_slice_several_cor(
@@ -139,6 +141,8 @@ class SAAxisTask(
139
141
  "dump_roi",
140
142
  "dump_process",
141
143
  "serialize_output_data",
144
+ "compute_scores", # for GUI we want to post pone the score calculation
145
+ "pool_size",
142
146
  ),
143
147
  ):
144
148
  """
@@ -148,6 +152,8 @@ class SAAxisTask(
148
152
  As the saaxis is integrating the score calculation we will never get a future_tomo_scan as output
149
153
  """
150
154
 
155
+ DEFAULT_POOL_SIZE = 10
156
+
151
157
  def __init__(
152
158
  self, process_id=None, inputs=None, varinfo=None, node_attrs=None, execinfo=None
153
159
  ):
@@ -214,7 +220,7 @@ class SAAxisTask(
214
220
  return best_cor
215
221
 
216
222
  def _config_preprocessing(
217
- self, scan, config, cor_positions, file_format, output_dir, cluster_config
223
+ self, scan, config, file_format, output_dir, cluster_config
218
224
  ):
219
225
  """convert general configuration to nabu - single reconstruction - configuration"""
220
226
  nabu_configurations = interpret_tomwer_configuration(config, scan=None)
@@ -232,17 +238,8 @@ class SAAxisTask(
232
238
  # work on file name...
233
239
  if output_dir is None:
234
240
  output_dir = os.path.join(scan.path, DEFAULT_RECONS_FOLDER)
235
- if scan.process_file is not None:
236
- steps_file_basename, _ = os.path.splitext(scan.process_file)
237
- steps_file_basename = "_".join(
238
- ("steps_file_basename", "nabu", "sinogram", "save", "step")
239
- )
240
- steps_file_basename = steps_file_basename + ".hdf5"
241
- steps_file = os.path.join(output_dir, steps_file_basename)
242
- else:
243
- steps_file = ""
244
241
 
245
- base_config = nabu_configurations[0][0]
242
+ nabu_configuration = nabu_configurations[0][0]
246
243
  if cluster_config == {}:
247
244
  cluster_config = None
248
245
  is_cluster_job = cluster_config is not None
@@ -250,98 +247,75 @@ class SAAxisTask(
250
247
  raise ValueError(
251
248
  "job on cluster requested but no access to slurm cluster found"
252
249
  )
253
- configs = {}
254
-
255
- for i_cor, cor in enumerate(cor_positions):
256
- nabu_configuration = copy.deepcopy(base_config)
257
- nabu_configuration["pipeline"] = {
258
- "save_steps": "sinogram" if i_cor == 0 else "",
259
- "resume_from_step": "sinogram",
260
- "steps_file": steps_file,
261
- }
262
- # convert cor from tomwer ref to nabu ref
263
- if scan.dim_1 is not None:
264
- cor_nabu_ref = cor + scan.dim_1 / 2.0
265
- else:
266
- _logger.warning("enable to get image half width. Set it to 1024")
267
- cor_nabu_ref = cor + 1024
268
- # handle reconstruction section
269
- if "reconstruction" not in nabu_configuration:
270
- nabu_configuration["reconstruction"] = {}
271
- nabu_configuration["reconstruction"]["rotation_axis_position"] = str(
272
- cor_nabu_ref
273
- )
274
- # handle output section
275
- if "output" not in nabu_configuration:
276
- nabu_configuration["output"] = {}
277
- nabu_configuration["output"]["location"] = output_dir
278
- nabu_configuration["output"]["file_format"] = file_format
279
- # handle resources section
280
- nabu_configuration["resources"] = utils.get_nabu_resources_desc(
281
- scan=scan, workers=1, method="local"
282
- )
283
- configs[cor] = nabu_configuration
284
- return configs
285
250
 
286
- def _run_slice_recons_per_cor(
251
+ # handle reconstruction section
252
+ if "reconstruction" not in nabu_configuration:
253
+ nabu_configuration["reconstruction"] = {}
254
+ nabu_configuration["reconstruction"]["rotation_axis_position"] = ""
255
+ # handle output section
256
+ if "output" not in nabu_configuration:
257
+ nabu_configuration["output"] = {}
258
+ nabu_configuration["output"]["location"] = output_dir
259
+ nabu_configuration["output"]["file_format"] = file_format
260
+ # handle resources section
261
+ nabu_configuration["resources"] = utils.get_nabu_resources_desc(
262
+ scan=scan, workers=1, method="local"
263
+ )
264
+ return nabu_configuration
265
+
266
+ def _run_nabu_multicor(
287
267
  self,
288
268
  scan,
289
- configs,
269
+ nabu_config,
270
+ cors,
290
271
  slice_index,
291
272
  file_format,
292
- advancement,
293
- cluster_config,
273
+ cluster_config: Optional[dict],
294
274
  dry_run=False,
295
275
  ):
296
- runners = run_nabu_one_slice_several_config(
297
- nabu_configs=configs,
276
+ if not (cluster_config is None or isinstance(cluster_config, dict)):
277
+ raise TypeError(
278
+ f"cluster_config is expected to be a dict. Get {type(cluster_config)} instead."
279
+ )
280
+ runner = run_nabu_multicor(
281
+ nabu_config=nabu_config,
298
282
  scan=scan,
283
+ cors=cors,
299
284
  slice_index=slice_index,
300
285
  dry_run=dry_run,
301
286
  file_format=file_format,
302
- advancement=advancement,
303
- cluster_config=cluster_config.to_dict()
304
- if cluster_config is not None
305
- else None,
287
+ cluster_config=cluster_config if cluster_config is not None else None,
306
288
  process_id=self.process_id,
307
289
  instanciate_classes_only=True,
308
290
  output_file_prefix_pattern="cor_{file_name}_{value}", # as the cor is evolving, create different files to make sure the name will be unique
309
291
  )
310
292
 
311
- future_tomo_objs = {}
312
- success = True
313
- recons_urls = {}
293
+ future_tomo_obj = None
294
+ recons_urls = dict()
314
295
  std_outs = []
315
296
  std_errs = []
316
297
 
317
- for runner in runners:
318
- if self._cancelled:
319
- break
320
- self._current_processing = runner
321
- try:
322
- results = runner.run()
323
- except TimeoutError as e:
324
- _logger.error(e)
325
- else:
326
- assert isinstance(
327
- results, dict
328
- ), "results should be a dictionary with cor as key and urls as value"
329
-
330
- for cor, res in results.items():
331
- success = success and res.success
332
- if isinstance(res, ResultsWithStd):
333
- std_outs.append(res.std_out)
334
- std_errs.append(res.std_err)
335
- if isinstance(res, ResultsLocalRun):
336
- recons_urls[cor] = res.results_urls
337
- if isinstance(res, ResultSlurmRun):
338
- future_tomo_obj = FutureTomwerObject(
339
- tomo_obj=scan,
340
- process_requester_id=self.process_id,
341
- futures=res.future_slurm_jobs,
342
- )
343
- future_tomo_objs[cor] = future_tomo_obj
344
- return success, recons_urls, future_tomo_objs, std_outs, std_errs
298
+ self._current_processing = runner
299
+ try:
300
+ result = runner.run()
301
+ except TimeoutError as e:
302
+ _logger.error(e)
303
+ else:
304
+ success = result.success
305
+ if isinstance(result, ResultsWithStd):
306
+ std_outs.append(result.std_out)
307
+ std_errs.append(result.std_err)
308
+ if isinstance(result, ResultsLocalRun):
309
+ recons_urls = {
310
+ cor: recons for cor, recons in zip(cors, result.results_identifiers)
311
+ }
312
+ if isinstance(result, ResultSlurmRun):
313
+ future_tomo_obj = FutureTomwerObject(
314
+ tomo_obj=scan,
315
+ process_requester_id=self.process_id,
316
+ futures=result.future_slurm_jobs,
317
+ )
318
+ return success, recons_urls, (future_tomo_obj,), std_outs, std_errs
345
319
 
346
320
  def _resolve_futures(
347
321
  self,
@@ -349,6 +323,7 @@ class SAAxisTask(
349
323
  nabu_config,
350
324
  slice_index,
351
325
  file_format,
326
+ cors,
352
327
  cor_reconstructions,
353
328
  future_tomo_objs: dict,
354
329
  output_dir,
@@ -359,54 +334,50 @@ class SAAxisTask(
359
334
  if output_dir is None:
360
335
  output_dir = os.path.join(scan.path, DEFAULT_RECONS_FOLDER)
361
336
 
362
- db = None
363
- pag = False
364
- ctf = False
365
- if "phase" in nabu_config:
366
- phase_method = nabu_config["phase"].get("method", "").lower()
367
- if phase_method in ("pag", "paganin"):
368
- pag = True
369
- elif phase_method in ("ctf",):
370
- ctf = True
371
- if "delta_beta" in nabu_config["phase"]:
372
- db = round(float(nabu_config["phase"]["delta_beta"]))
373
-
374
- for cor, future_tomo_obj in future_tomo_objs.items():
337
+ file_prefix = get_nabu_multicor_file_prefix(scan)
338
+
339
+ for future_tomo_obj in future_tomo_objs:
375
340
  if self._cancelled:
376
341
  break
342
+
343
+ if future_tomo_obj is None:
344
+ continue
345
+
377
346
  future_tomo_obj.results()
378
- # for saaxis we need to retrieve reconstruction url
379
347
  if future_tomo_obj.cancelled() or future_tomo_obj.exceptions():
380
348
  continue
381
- else:
382
- _file_name = SingleSliceRunner.get_file_basename_reconstruction(
349
+
350
+ for cor in cors:
351
+ cor_nabu_ref = _ReconstructorMultiCor.convert_cor_from_rel_to_abs(
383
352
  scan=scan,
384
- slice_index=slice_index,
385
- pag=pag,
386
- db=db,
387
- ctf=ctf,
353
+ cor=cor,
388
354
  )
389
- file_prefix = f"cor_{_file_name}_{cor}"
390
-
391
- recons_vol_id = utils.get_recons_volume_identifier(
355
+ volume_identifiers = get_multi_cor_recons_volume_identifiers(
392
356
  scan=scan,
393
- file_format=file_format,
357
+ slice_index=slice_index,
358
+ location=nabu_config["output"]["location"],
394
359
  file_prefix=file_prefix,
395
- location=output_dir,
396
- slice_index=None,
397
- start_z=None,
398
- end_z=None,
399
- expects_single_slice=True,
360
+ file_format=file_format,
361
+ cors=(cor_nabu_ref,),
400
362
  )
401
- assert len(recons_vol_id) == 1, "only one volume reconstructed expected"
402
- cor_reconstructions[cor] = recons_vol_id
363
+ volume_identifier = volume_identifiers.get(cor_nabu_ref, None)
364
+ if volume_identifier is None:
365
+ _logger.warning(
366
+ f"failed to load volume for {cor}. Something went wrong on slurm submission job"
367
+ )
368
+ cor_reconstructions[cor] = volume_identifier
403
369
 
404
- def _post_processing(self, scan, slice_index, cor_reconstructions):
370
+ def _post_processing(self, scan, slice_index, cor_reconstructions: dict):
405
371
  """
406
372
  compute score along the different slices
373
+
374
+ :param dict cor_reconstructions: key is expected to be a float with the cor value and the value is expected to be a volume identifier (volume with a single frame)
407
375
  """
408
376
  post_processing = _PostProcessing(
409
- slice_index=slice_index, scan=scan, cor_reconstructions=cor_reconstructions
377
+ slice_index=slice_index,
378
+ scan=scan,
379
+ cor_reconstructions=cor_reconstructions,
380
+ pool_size=self.get_input_value("pool_size", self.DEFAULT_POOL_SIZE),
410
381
  )
411
382
  post_processing._cancelled = self._cancelled
412
383
  self._current_processing = post_processing
@@ -435,6 +406,16 @@ class SAAxisTask(
435
406
  else:
436
407
  return list(slice_index.values())[0]
437
408
 
409
+ def get_output_dir(self, params: SAAxisParams, scan: TomwerScanBase):
410
+ output_dir = params.output_dir or None
411
+ if output_dir is None:
412
+ output_dir = (
413
+ params.nabu_params.get("output", {}).get("location", None) or None
414
+ )
415
+ if output_dir is None:
416
+ output_dir = os.path.join(scan.path, DEFAULT_RECONS_FOLDER)
417
+ return output_dir
418
+
438
419
  def run(self):
439
420
  scan = data_identifier_to_scan(self.inputs.data)
440
421
  if scan is None:
@@ -451,10 +432,10 @@ class SAAxisTask(
451
432
  configuration = self.inputs.sa_axis_params
452
433
  params = SAAxisParams.from_dict(configuration)
453
434
  # insure output dir is created
454
- if params.output_dir in (None, ""):
455
- params.output_dir = os.path.join(scan.path, "saaxis_results")
456
- if not os.path.exists(params.output_dir):
457
- os.makedirs(params.output_dir)
435
+ params.output_dir = self.get_output_dir(params=params, scan=scan)
436
+ if not os.path.exists(params.output_dir):
437
+ os.makedirs(params.output_dir)
438
+
458
439
  # try to find an estimated cor
459
440
  # from a previously computed cor
460
441
  if params.estimated_cor is None and scan.axis_params is not None:
@@ -480,9 +461,7 @@ class SAAxisTask(
480
461
  if mode is not ReconstructionMode.VERTICAL:
481
462
  raise ValueError(f"{mode} is not handled for now")
482
463
 
483
- output_dir = params.output_dir
484
- if output_dir is None:
485
- output_dir = os.path.join(scan.path, DEFAULT_RECONS_FOLDER)
464
+ nabu_config = configuration.get("nabu_params", {})
486
465
  nabu_output_config = configuration.get("output", {})
487
466
  file_format = nabu_output_config.get("file_format", "hdf5")
488
467
  slice_index = self._preprocess_slice_index(
@@ -493,18 +472,14 @@ class SAAxisTask(
493
472
  dry_run = self._dry_run
494
473
 
495
474
  # step one: complete nabu configuration(s)
496
- configs = self._config_preprocessing(
475
+ nabu_config = self._config_preprocessing(
497
476
  scan=scan,
498
- config=configuration,
499
- cor_positions=params.cors,
477
+ config=nabu_config,
500
478
  file_format=file_format,
501
- output_dir=output_dir,
479
+ output_dir=params.output_dir,
502
480
  cluster_config=cluster_config,
503
481
  )
504
482
  # step 2: run reconstructions
505
- advancement = Progress(
506
- f"sa-axis - slice {slice_index} of {scan.get_identifier().short_description()}"
507
- )
508
483
  cors_res = {}
509
484
  rois = {}
510
485
 
@@ -515,12 +490,12 @@ class SAAxisTask(
515
490
  future_tomo_objs,
516
491
  self._std_outs,
517
492
  self._std_errs,
518
- ) = self._run_slice_recons_per_cor(
493
+ ) = self._run_nabu_multicor(
519
494
  scan=scan,
520
- configs=configs,
495
+ nabu_config=nabu_config,
496
+ cors=tuple(params.cors),
521
497
  slice_index=slice_index,
522
498
  file_format=file_format,
523
- advancement=advancement,
524
499
  cluster_config=cluster_config,
525
500
  dry_run=dry_run,
526
501
  )
@@ -532,29 +507,37 @@ class SAAxisTask(
532
507
  # step 3: wait for future if any
533
508
  self._resolve_futures(
534
509
  scan=scan,
535
- nabu_config=configuration,
510
+ nabu_config=nabu_config,
536
511
  slice_index=slice_index,
537
512
  file_format=file_format,
538
513
  cor_reconstructions=cor_reconstructions,
514
+ cors=tuple(params.cors),
539
515
  future_tomo_objs=future_tomo_objs,
540
- output_dir=output_dir,
516
+ output_dir=params.output_dir,
541
517
  )
542
518
 
543
519
  # step 4: run post processing (compute score for each slice)
544
- try:
545
- cors_res, rois = self._post_processing(
546
- scan=scan,
547
- slice_index=slice_index,
548
- cor_reconstructions=cor_reconstructions,
549
- )
550
- except Exception as e:
551
- _logger.error(e)
552
- mess = f"sa-axis -post-processing- computation for {str(scan)} failed."
553
- state = DatasetState.FAILED
554
- cors_res = {}
520
+ if self.get_input_value("compute_scores", True):
521
+ try:
522
+ cors_res, rois = self._post_processing(
523
+ scan=scan,
524
+ slice_index=slice_index,
525
+ cor_reconstructions=cor_reconstructions,
526
+ )
527
+ except Exception as e:
528
+ _logger.error(e)
529
+ mess = (
530
+ f"sa-axis -post-processing- computation for {str(scan)} failed."
531
+ )
532
+ state = DatasetState.FAILED
533
+ cors_res = {}
534
+ else:
535
+ state = DatasetState.WAIT_USER_VALIDATION
536
+ mess = "sa-axis computation succeeded"
555
537
  else:
556
- state = DatasetState.WAIT_USER_VALIDATION
557
- mess = "sa-axis computation succeeded"
538
+ cors_res = {}
539
+ state = DatasetState.FAILED
540
+ mess = "couldn't find 'compute_scores'"
558
541
 
559
542
  if self._cancelled:
560
543
  state = DatasetState.CANCELLED
@@ -671,7 +654,7 @@ class SAAxisTask(
671
654
  def process_to_tomwer_processes(scan):
672
655
  if scan.process_file is not None:
673
656
  entry = "entry"
674
- if isinstance(scan, HDF5TomoScan):
657
+ if isinstance(scan, NXtomoScan):
675
658
  entry = scan.entry
676
659
 
677
660
  cor = None
@@ -749,128 +732,119 @@ class SAAxisTask(
749
732
  class _PostProcessing:
750
733
  """class used to run SA-axis post-processing on reconstructed slices"""
751
734
 
752
- def __init__(self, cor_reconstructions, slice_index, scan) -> None:
735
+ def __init__(self, cor_reconstructions, slice_index, scan, pool_size) -> None:
753
736
  self._cor_reconstructions = cor_reconstructions
754
737
  self._slice_index = slice_index
755
738
  self._scan = scan
756
739
  self._cancelled = False
740
+ self.pool_size = pool_size
741
+
742
+ @staticmethod
743
+ def compute_score(item: tuple):
744
+ cor, (url, data), mask_disk_radius, cancelled = item
745
+ if cancelled:
746
+ return (None, None), None
747
+
748
+ if data is None:
749
+ score = None
750
+ data_roi = None
751
+ else:
752
+ if not isinstance(data, numpy.ndarray):
753
+ raise TypeError(
754
+ f"data should be a numpy array. Get {type(data)} instead"
755
+ )
756
+ assert data.ndim == 2, f"data should be 2D. Get {data.ndim} instead"
757
+ data_roi = apply_roi(data=data, radius=mask_disk_radius, url=url)
758
+
759
+ # move data_roi to [0-1] range
760
+ # preprocessing: get percentile 0 and 99 from image and
761
+ # "clean" highest and lowest pixels from it
762
+ min_p, max_p = numpy.percentile(data_roi, (1, 99))
763
+ data_roi_int = data_roi[...]
764
+ data_roi_int[data_roi_int < min_p] = min_p
765
+ data_roi_int[data_roi_int > max_p] = max_p
766
+ data_roi_int = (data_roi_int - min_p) / (max_p - min_p)
767
+
768
+ score = ComputedScore(
769
+ tv=compute_score(data=data_roi_int, method=ScoreMethod.TV),
770
+ std=compute_score(data=data_roi_int, method=ScoreMethod.STD),
771
+ tomo_consistency=None,
772
+ )
773
+ return {cor: (url, score)}, {cor: data_roi}
757
774
 
758
775
  def run(self):
759
776
  datasets = self.load_datasets()
760
-
777
+ assert isinstance(datasets, dict)
761
778
  mask_disk_radius = get_disk_mask_radius(datasets)
779
+ with Pool(self.pool_size) as pool:
780
+ res = pool.map(
781
+ self.compute_score,
782
+ [
783
+ (
784
+ *item,
785
+ mask_disk_radius,
786
+ self._cancelled,
787
+ )
788
+ for item in datasets.items()
789
+ ],
790
+ )
762
791
  scores = {}
763
792
  rois = {}
764
- for cor, (url, data) in datasets.items():
765
- if self._cancelled:
766
- break
767
-
768
- if data is None:
769
- score = None
770
- else:
771
- assert data.ndim == 2
772
- data_roi = apply_roi(data=data, radius=mask_disk_radius, url=url)
773
- rois[cor] = data_roi
774
-
775
- # move data_roi to [0-1] range
776
- # preprocessing: get percentile 0 and 99 from image and
777
- # "clean" highest and lowest pixels from it
778
- min_p, max_p = numpy.percentile(data_roi, (1, 99))
779
- data_roi_int = data_roi[...]
780
- data_roi_int[data_roi_int < min_p] = min_p
781
- data_roi_int[data_roi_int > max_p] = max_p
782
- data_roi_int = (data_roi_int - min_p) / (max_p - min_p)
783
-
784
- if isinstance(self._scan, EDFTomoScan):
785
- _logger.info("tomo consistency is not handled for EDF scan")
786
- tomo_consistency_score = None
787
- else:
788
- try:
789
- projections_with_angle = self._scan.projections_with_angle()
790
- angles_ = [
791
- frame_angle
792
- for frame_angle, frame in projections_with_angle.items()
793
- ]
794
- angles = []
795
- for angle in angles_:
796
- if not isinstance(angle, str):
797
- angles.append(angle)
798
- if self._slice_index == "middle":
799
- if self._scan.dim_2 is not None:
800
- self._slice_index = self._scan.dim_2 // 2
801
- else:
802
- _logger.warning(
803
- "scan.dim_2 returns None, unable to deduce middle "
804
- "pick 1024"
805
- )
806
- self._slice_index = 1024
807
- tomo_consistency_score = compute_score(
808
- data=data,
809
- method=ScoreMethod.TOMO_CONSISTENCY,
810
- angles=angles,
811
- original_sinogram=self._scan.get_sinogram(
812
- self._slice_index
813
- ),
814
- detector_width=self._scan.dim_1,
815
- original_axis_position=cor + self._scan.dim_1 / 2.0,
816
- )
817
- except Exception as e:
818
- _logger.error(e)
819
- tomo_consistency_score = None
820
- score = ComputedScore(
821
- tv=compute_score(data=data_roi_int, method=ScoreMethod.TV),
822
- std=compute_score(data=data_roi_int, method=ScoreMethod.STD),
823
- tomo_consistency=tomo_consistency_score,
824
- )
825
- scores[cor] = (url, score)
793
+ for mydict in res:
794
+ myscores, myrois = mydict
795
+ scores.update(myscores)
796
+ rois.update(myrois)
826
797
  return scores, rois
827
798
 
828
- def load_datasets(self):
829
- datasets_ = {}
830
- for cor, volume_identifiers in self._cor_reconstructions.items():
831
- if self._cancelled:
832
- break
833
-
834
- if len(volume_identifiers) == 0:
835
- # in the case failed to load the url
836
- continue
837
- elif len(volume_identifiers) > 1:
838
- raise ValueError("only one slice reconstructed expected per cor")
839
- volume = VolumeFactory.create_tomo_object_from_identifier(
840
- volume_identifiers[0]
799
+ @staticmethod
800
+ def _load_dataset(item: tuple):
801
+ cor, volume_identifier = item
802
+ if volume_identifier is None:
803
+ return {cor: (None, None)}
804
+
805
+ volume = VolumeFactory.create_tomo_object_from_identifier(volume_identifier)
806
+ urls = tuple(volume.browse_data_urls())
807
+ if len(urls) == 0:
808
+ _logger.error(
809
+ f"volume {volume.get_identifier().to_str()} has no url / slices. Unable to load any data."
841
810
  )
842
- urls = tuple(volume.browse_data_urls())
843
- if len(urls) != 1:
844
- raise ValueError(
845
- f"volume is expected to have at most one url (single slice volume). get {len(urls)} - most likely nabu reconstruction failed. Do you have GPU ? Are the requested COR values valid ? - Especially for Half-acquisition"
846
- )
847
- url = urls[0]
848
- if not isinstance(url, (DataUrl, str)):
849
- raise TypeError(
850
- f"url is expected to be a str or DataUrl not {type(url)}"
851
- )
811
+ return {cor: (None, None)}
812
+ if len(urls) != 1:
813
+ _logger.error(
814
+ f"volume is expected to have at most one url (single slice volume). get {len(urls)} - most likely nabu reconstruction failed. Do you have GPU ? Are the requested COR values valid ? - Especially for Half-acquisition"
815
+ )
816
+ url = urls[0]
817
+ if not isinstance(url, (DataUrl, str)):
818
+ raise TypeError(f"url is expected to be a str or DataUrl not {type(url)}")
852
819
 
853
- try:
854
- data = get_slice_data(url=url)
855
- except Exception as e:
856
- _logger.error(
857
- f"Fail to compute a score for {url.path()}. Reason is {e}"
858
- )
859
- datasets_[cor] = (url, None)
860
- else:
861
- if data.ndim == 3:
862
- if data.shape[0] == 1:
863
- data = data.reshape(data.shape[1], data.shape[2])
864
- elif data.shape[2] == 1:
865
- data = data.reshape(data.shape[0], data.shape[1])
866
- else:
867
- raise ValueError(f"Data is expected to be 2D. Not {data.ndim}D")
868
- elif data.ndim == 2:
869
- pass
820
+ try:
821
+ data = get_slice_data(url=url)
822
+ except Exception as e:
823
+ _logger.error(f"Fail to compute a score for {url.path()}. Reason is {e}")
824
+ return {cor: (url, None)}
825
+ else:
826
+ if data.ndim == 3:
827
+ if data.shape[0] == 1:
828
+ data = data.reshape(data.shape[1], data.shape[2])
829
+ elif data.shape[2] == 1:
830
+ data = data.reshape(data.shape[0], data.shape[1])
870
831
  else:
871
- raise ValueError("Data is expected to be 2D. Not {data.ndim}D")
832
+ raise ValueError(f"Data is expected to be 2D. Not {data.ndim}D")
833
+ elif data.ndim == 2:
834
+ pass
835
+ else:
836
+ raise ValueError("Data is expected to be 2D. Not {data.ndim}D")
837
+ return {cor: (url, data)}
872
838
 
873
- datasets_[cor] = (url, data)
839
+ def load_datasets(self):
840
+ with Pool(self.pool_size) as pool:
841
+ res = pool.map(
842
+ self._load_dataset,
843
+ self._cor_reconstructions.items(),
844
+ )
845
+ datasets_ = {}
846
+ for mydict in res:
847
+ datasets_.update(mydict)
874
848
  return datasets_
875
849
 
876
850
  def cancel(self):