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
@@ -0,0 +1,534 @@
1
+ # coding: utf-8
2
+ # /*##########################################################################
3
+ # Copyright (C) 2016 European Synchrotron Radiation Facility
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ #
23
+ #############################################################################*/
24
+
25
+
26
+ __authors__ = ["H.Payno"]
27
+ __license__ = "MIT"
28
+ __date__ = "09/08/2018"
29
+
30
+
31
+ import functools
32
+ import io
33
+ import json
34
+ import logging
35
+ import os
36
+ import pathlib
37
+ from datetime import datetime
38
+ from typing import Optional
39
+ from urllib.parse import urlparse
40
+
41
+ import h5py
42
+ from processview.core.dataset import DatasetIdentifier
43
+ from silx.io.utils import open as open_hdf5
44
+ from tomoscan.esrf.identifier.hdf5Identifier import (
45
+ NXtomoScanIdentifier as _NXtomoScanIdentifier,
46
+ )
47
+ from tomoscan.esrf.identifier.url_utils import UrlSettings, split_path, split_query
48
+ from tomoscan.esrf.scan.nxtomoscan import NXtomoScan as _tsNXtomoScan
49
+ from nxtomo.nxobject.nxdetector import ImageKey
50
+
51
+ from tomwer.utils import docstring
52
+ from tomwer.core.scan.helicalmetadata import HelicalMetadata
53
+
54
+ from .scanbase import TomwerScanBase
55
+
56
+ _logger = logging.getLogger(__name__)
57
+
58
+
59
+ class NXtomoScanIdentifier(_NXtomoScanIdentifier, DatasetIdentifier):
60
+ def __init__(self, metadata=None, *args, **kwargs):
61
+ super().__init__(*args, **kwargs)
62
+ DatasetIdentifier.__init__(
63
+ self, data_builder=NXtomoScan.from_identifier, metadata=metadata
64
+ )
65
+
66
+ @staticmethod
67
+ def from_str(identifier):
68
+ info = urlparse(identifier)
69
+ paths = split_path(info.path)
70
+ if len(paths) == 1:
71
+ hdf5_file = paths[0]
72
+ tomo_type = None
73
+ elif len(paths) == 2:
74
+ tomo_type, hdf5_file = paths
75
+ else:
76
+ raise ValueError("Failed to parse path string:", info.path)
77
+ if tomo_type is not None and tomo_type != NXtomoScanIdentifier.TOMO_TYPE:
78
+ raise TypeError(
79
+ f"provided identifier fits {tomo_type} and not {NXtomoScanIdentifier.TOMO_TYPE}"
80
+ )
81
+
82
+ queries = split_query(info.query)
83
+ entry = queries.get(UrlSettings.DATA_PATH_KEY, None)
84
+ if entry is None:
85
+ raise ValueError(f"expects to get {UrlSettings.DATA_PATH_KEY} query")
86
+
87
+ return NXtomoScanIdentifier(object=NXtomoScan, hdf5_file=hdf5_file, entry=entry)
88
+
89
+ def long_description(self) -> str:
90
+ """used for processview header tooltip for now"""
91
+ return self.to_str()
92
+
93
+ def short_description(self) -> str:
94
+ return f"scan: {self.data_path.lstrip('/')}@{os.path.basename(self._file_path)}"
95
+
96
+
97
+ class NXtomoScan(_tsNXtomoScan, TomwerScanBase):
98
+ """
99
+ This is the implementation of a TomoBase class for an acquisition stored
100
+ in a HDF5 file.
101
+
102
+ For now several property of the acquisition is accessible thought a getter
103
+ (like get_scan_range) and a property (scan_range).
104
+
105
+ This is done to be compliant with TomoBase instanciation. But his will be
106
+ replace progressively by properties at the 'TomoBase' level
107
+
108
+ :param scan: scan directory or scan masterfile.h5
109
+ :type: Union[str,None]
110
+ """
111
+
112
+ _TYPE = "hdf5"
113
+
114
+ def __init__(self, scan, entry, index=None, overwrite_proc_file=False):
115
+ TomwerScanBase.__init__(self)
116
+ _tsNXtomoScan.__init__(self, scan=scan, entry=entry, index=index)
117
+ # speed up for now, avoid to run check by default
118
+ self.set_check_behavior(run_check=False)
119
+ # register at least the 'default' working directory as a possible reconstruction path
120
+ self.add_reconstruction_path(self.path)
121
+ self._helical = HelicalMetadata()
122
+
123
+ self._reconstruction_urls = None
124
+ self._projections_with_angles = None
125
+ self._process_file = self.get_process_file_name(self)
126
+ self._init_index_process_file(overwrite_proc_file=overwrite_proc_file)
127
+ try:
128
+ reduced_darks, metadata = self.load_reduced_darks(return_info=True)
129
+ except (KeyError, OSError, ValueError):
130
+ # file or key does not exists
131
+ pass
132
+ else:
133
+ self.set_reduced_darks(reduced_darks, darks_infos=metadata)
134
+
135
+ try:
136
+ reduced_flats, metadata = self.load_reduced_flats(return_info=True)
137
+ except (KeyError, OSError, ValueError):
138
+ pass
139
+ else:
140
+ self.set_reduced_flats(reduced_flats, flats_infos=metadata)
141
+
142
+ @property
143
+ def working_directory(self):
144
+ if self.master_file is None:
145
+ return None
146
+ else:
147
+ return os.path.abspath(os.path.dirname(self.master_file))
148
+
149
+ @property
150
+ def helical(self):
151
+ return self._helical
152
+
153
+ @staticmethod
154
+ def from_identifier(identifier):
155
+ """Return the Dataset from a identifier"""
156
+ if not isinstance(identifier, NXtomoScanIdentifier):
157
+ raise TypeError(
158
+ f"identifier should be an instance of {NXtomoScanIdentifier}. Not {type(identifier)}"
159
+ )
160
+ return NXtomoScan(scan=identifier.file_path, entry=identifier.data_path)
161
+
162
+ def get_identifier(self):
163
+ try:
164
+ stat = pathlib.Path(self.master_file).stat()
165
+ except Exception:
166
+ stat = None
167
+
168
+ return NXtomoScanIdentifier(
169
+ object=self,
170
+ hdf5_file=self.master_file,
171
+ entry=self.entry,
172
+ metadata={
173
+ "name": self.master_file,
174
+ "creation_time": (
175
+ datetime.fromtimestamp(stat.st_ctime) if stat else None
176
+ ),
177
+ "modification_time": (
178
+ datetime.fromtimestamp(stat.st_ctime) if stat else None
179
+ ),
180
+ },
181
+ )
182
+
183
+ @staticmethod
184
+ def get_process_file_name(scan):
185
+ if scan.path is not None:
186
+ basename, _ = os.path.splitext(scan.master_file)
187
+ basename = os.path.basename(basename)
188
+ basename = "_".join((basename, "tomwer_processes.h5"))
189
+ return os.path.join(scan.path, basename)
190
+ else:
191
+ return None
192
+
193
+ @staticmethod
194
+ def directory_contains_scan(directory, src_pattern=None, dest_pattern=None):
195
+ """
196
+
197
+ Check if the given directory is holding an acquisition
198
+
199
+ :param str directory: directory we want to check
200
+ :param str src_pattern: buffer name pattern ('lbsram')
201
+ :param dest_pattern: output pattern (''). Needed because some
202
+ acquisition can split the file produce between
203
+ two directories. This is the case for edf,
204
+ where .info file are generated in /data/dir
205
+ instead of /lbsram/data/dir
206
+ :type: str
207
+ :return: does the given directory contains any acquisition
208
+ :rtype: bool
209
+ """
210
+ master_file = os.path.join(directory, os.path.basename(directory))
211
+ if os.path.exists("master_file.hdf5"):
212
+ return True
213
+ else:
214
+ return os.path.exists(master_file + ".h5")
215
+
216
+ def clear_caches(self):
217
+ _tsNXtomoScan.clear_caches(self)
218
+ TomwerScanBase.clear_caches(self)
219
+
220
+ def is_abort(self, src_pattern, dest_pattern):
221
+ """
222
+ Check if the acquisition have been aborted. In this case the directory
223
+ should contain a [scan].abo file
224
+
225
+ :param str src_pattern: buffer name pattern ('lbsram')
226
+ :param dest_pattern: output pattern (''). Needed because some
227
+ acquisition can split the file produce between
228
+ two directories. This is the case for edf,
229
+ where .info file are generated in /data/dir
230
+ instead of /lbsram/data/dir
231
+ :return: True if the acquisition have been abort and the directory
232
+ should be abort
233
+ """
234
+ # for now there is no abort definition in .hdf5
235
+ return False
236
+
237
+ @staticmethod
238
+ def from_dict(_dict):
239
+ path = _dict[NXtomoScan.DICT_PATH_KEY]
240
+ entry = _dict[NXtomoScan._DICT_ENTRY_KEY]
241
+
242
+ scan = NXtomoScan(scan=path, entry=entry)
243
+ scan.load_from_dict(_dict=_dict)
244
+ return scan
245
+
246
+ @docstring(TomwerScanBase)
247
+ def load_from_dict(self, _dict):
248
+ """
249
+
250
+ :param _dict:
251
+ :return:
252
+ """
253
+ if isinstance(_dict, io.TextIOWrapper):
254
+ data = json.load(_dict)
255
+ else:
256
+ data = _dict
257
+ if not (self.DICT_TYPE_KEY in data and data[self.DICT_TYPE_KEY] == self._TYPE):
258
+ raise ValueError("Description is not an EDFScan json description")
259
+
260
+ _tsNXtomoScan.load_from_dict(self, _dict)
261
+ TomwerScanBase.load_from_dict(self, _dict)
262
+ return self
263
+
264
+ @docstring(TomwerScanBase)
265
+ def to_dict(self) -> dict:
266
+ ddict = _tsNXtomoScan.to_dict(self)
267
+ ddict.update(TomwerScanBase.to_dict(self))
268
+ return ddict
269
+
270
+ def update(self):
271
+ """update list of radio and reconstruction by parsing the scan folder"""
272
+ if self.master_file is None:
273
+ return
274
+ if not os.path.exists(self.master_file):
275
+ return
276
+ _tsNXtomoScan.update(self)
277
+ self.reconstructions = self.get_reconstructions_urls()
278
+
279
+ def _get_scheme(self):
280
+ """
281
+
282
+ :return: scheme to read url
283
+ :rtype: str
284
+ """
285
+ return "silx"
286
+
287
+ def is_finish(self):
288
+ return len(self.projections) >= self.tomo_n
289
+
290
+ @docstring(TomwerScanBase.get_sinogram)
291
+ @functools.lru_cache(maxsize=16, typed=True)
292
+ def get_sinogram(self, line, subsampling=1, norm_method=None, **kwargs):
293
+ """
294
+
295
+ extract the sinogram from projections
296
+
297
+ :param line: which sinogram we want
298
+ :type: int
299
+ :param subsampling: subsampling to apply if any. Allows to skip some io
300
+ :type: int
301
+ :return: sinogram from the radio lines
302
+ :rtype: numpy.array
303
+ """
304
+ return _tsNXtomoScan.get_sinogram(
305
+ self,
306
+ line=line,
307
+ subsampling=subsampling,
308
+ norm_method=norm_method,
309
+ **kwargs,
310
+ )
311
+
312
+ @docstring(TomwerScanBase.get_proj_angle_url)
313
+ def get_proj_angle_url(self, use_cache: bool = True, with_alignment=True):
314
+ if not use_cache:
315
+ self._cache_proj_urls = None
316
+
317
+ if self._cache_proj_urls is None:
318
+ frames = self.frames
319
+ if frames is None:
320
+ return {}
321
+
322
+ self._cache_proj_urls = {}
323
+ for frame in frames:
324
+ if frame.image_key is ImageKey.PROJECTION:
325
+ if frame.is_control and with_alignment:
326
+ self._cache_proj_urls[f"{frame.rotation_angle} (1)"] = frame.url
327
+ elif frame.is_control:
328
+ continue
329
+ else:
330
+ self._cache_proj_urls[str(frame.rotation_angle)] = frame.url
331
+ return self._cache_proj_urls
332
+
333
+ @docstring(TomwerScanBase._deduce_transfert_scan)
334
+ def _deduce_transfert_scan(self, output_dir):
335
+ new_master_file_path = os.path.join(
336
+ output_dir, os.path.basename(self.master_file)
337
+ )
338
+ return NXtomoScan(scan=new_master_file_path, entry=self.entry)
339
+
340
+ def data_flat_field_correction(self, data, index=None):
341
+ flats = self.reduced_flats
342
+ flat1 = flat2 = None
343
+ index_flat1 = index_flat2 = None
344
+ if flats is not None:
345
+ flat_indexes = sorted(list(flats.keys()))
346
+ if len(flats) > 0:
347
+ index_flat1 = flat_indexes[0]
348
+ flat1 = flats[index_flat1]
349
+ if len(flats) > 1:
350
+ index_flat2 = flat_indexes[-1]
351
+ flat2 = flats[index_flat2]
352
+ darks = self.reduced_darks
353
+ dark = None
354
+ if darks is not None and len(darks) > 0:
355
+ # take only one dark into account for now
356
+ dark = list(darks.values())[0]
357
+ return self._flat_field_correction(
358
+ data=data,
359
+ dark=dark,
360
+ flat1=flat1,
361
+ flat2=flat2,
362
+ index_flat1=index_flat1,
363
+ index_flat2=index_flat2,
364
+ index_proj=index,
365
+ )
366
+
367
+ @docstring(_tsNXtomoScan.ff_interval)
368
+ @property
369
+ def ff_interval(self):
370
+ """
371
+ Make some assumption to compute the flat field interval:
372
+ """
373
+
374
+ def get_first_two_ff_indexes():
375
+ if self.flats is None:
376
+ return None, None
377
+ else:
378
+ self._last_flat_index = None
379
+ self._first_serie_flat_index = None
380
+ for flat_index in self.flats:
381
+ if self._last_flat_index is None:
382
+ self._last_flat_index = flat_index
383
+ elif flat_index == self._last_flat_index + 1:
384
+ self._last_flat_index = flat_index
385
+ continue
386
+ else:
387
+ return self._last_flat_index, flat_index
388
+ return None, None
389
+
390
+ first_serie_index, second_serie_index = get_first_two_ff_indexes()
391
+ if first_serie_index is None:
392
+ return 0
393
+ elif second_serie_index is not None:
394
+ return second_serie_index - first_serie_index - 1
395
+ else:
396
+ return 0
397
+
398
+ def projections_with_angle(self):
399
+ """projections / radio, does not include the return projections"""
400
+ if self._projections_with_angles is None:
401
+ if self.frames:
402
+ proj_frames = tuple(
403
+ filter(
404
+ lambda x: x.image_key == ImageKey.PROJECTION
405
+ and x.is_control is False,
406
+ self.frames,
407
+ )
408
+ )
409
+ self._projections_with_angles = {}
410
+ for proj_frame in proj_frames:
411
+ self._projections_with_angles[proj_frame.rotation_angle] = (
412
+ proj_frame.url
413
+ )
414
+ return self._projections_with_angles
415
+
416
+ @staticmethod
417
+ def is_nexus_nxtomo_file(file_path: str) -> bool:
418
+ if h5py.is_hdf5(file_path):
419
+ return len(NXtomoScan.get_nxtomo_entries(file_path)) > 0
420
+
421
+ @staticmethod
422
+ def get_nxtomo_entries(file_path: str) -> tuple:
423
+ if not h5py.is_hdf5(file_path):
424
+ return tuple()
425
+ else:
426
+ res = []
427
+ with open_hdf5(file_path) as h5s:
428
+ for entry_name, node in h5s.items():
429
+ if isinstance(node, h5py.Group):
430
+ if NXtomoScan.entry_is_nx_tomo(node):
431
+ res.append(entry_name)
432
+ return tuple(res)
433
+
434
+ @staticmethod
435
+ def entry_is_nx_tomo(entry: h5py.Group):
436
+ return ("beam" in entry and "instrument" in entry and "sample" in entry) or (
437
+ hasattr(entry, "attrs")
438
+ and "definition" in entry.attrs
439
+ and entry.attrs["definition"] == "NXtomo"
440
+ )
441
+
442
+ @staticmethod
443
+ def is_nxdetector(grp: h5py.Group):
444
+ """
445
+ Check if the grp is an nx detector
446
+
447
+ :param h5py.Group grp:
448
+ :return: True if this is the definition of a group
449
+ :rtype: bool
450
+ """
451
+ if hasattr(grp, "attrs"):
452
+ if "NX_class" in grp.attrs and grp.attrs["NX_class"] == "NXdetector":
453
+ return True
454
+ return False
455
+
456
+ # Dataset implementation
457
+
458
+ @docstring(TomwerScanBase)
459
+ def get_nabu_dataset_info(self, binning=1, binning_z=1, proj_subsampling=1):
460
+ if not isinstance(binning, int):
461
+ raise TypeError(f"binning should be an int. Not {type(binning)}")
462
+ if not isinstance(binning_z, int):
463
+ raise TypeError(f"binning_z should be an int. Not {type(binning_z)}")
464
+ if not isinstance(proj_subsampling, int):
465
+ raise TypeError(
466
+ f"proj_subsampling should be an int. Not {type(proj_subsampling)}"
467
+ )
468
+ return {
469
+ "hdf5_entry": self.entry,
470
+ "location": os.path.basename(self.master_file),
471
+ "binning": binning,
472
+ "binning_z": binning_z,
473
+ "projections_subsampling": proj_subsampling,
474
+ }
475
+
476
+ @docstring(TomwerScanBase)
477
+ def to_nabu_dataset_analyser(self):
478
+ from nabu.resources.dataset_analyzer import HDF5DatasetAnalyzer
479
+
480
+ return HDF5DatasetAnalyzer(
481
+ location=self.master_file, extra_options={"hdf5_entry": self.entry}
482
+ )
483
+
484
+ @docstring(TomwerScanBase)
485
+ def scan_dir_name(self) -> Optional[str]:
486
+ """for 'this/is/my/file.h5' returns 'my'"""
487
+ if self.master_file is not None:
488
+ return os.path.dirname(self.master_file).split(os.sep)[-1]
489
+ else:
490
+ return None
491
+
492
+ @docstring(TomwerScanBase)
493
+ def scan_basename(self):
494
+ if self.master_file is not None:
495
+ try:
496
+ return os.path.dirname(self.master_file)
497
+ except Exception:
498
+ return None
499
+ else:
500
+ return None
501
+
502
+ @docstring(TomwerScanBase)
503
+ def scan_parent_dir_basename(self):
504
+ if self.master_file is not None:
505
+ try:
506
+ return os.path.dirname(os.path.dirname(self.master_file))
507
+ except Exception:
508
+ return None
509
+ else:
510
+ return None
511
+
512
+ def get_proposal_name(self) -> Optional[str]:
513
+ if self._proposal_name is None and self.master_file is not None:
514
+ bliss_raw_data_files = self.get_bliss_orginal_files() or ()
515
+ bliss_raw_data_file = (
516
+ bliss_raw_data_files[0] if len(bliss_raw_data_files) > 0 else None
517
+ )
518
+ if bliss_raw_data_file is not None:
519
+ strips = bliss_raw_data_file.lstrip("/").split("/")
520
+ if len(strips) > 2 and bliss_raw_data_file.startswith(
521
+ ("/data/visitor", "/data/visitor")
522
+ ):
523
+ self._proposal_name = strips[2]
524
+ elif (
525
+ bliss_raw_data_file.startswith(("/data", "data"))
526
+ and len(strips) > 3
527
+ and strips[2] == "inhouse"
528
+ ):
529
+ self._proposal_name = strips[3]
530
+ else:
531
+ _logger.warning(
532
+ "this doesn't looks like a bliss file aquired at the ESRF. Unable to find proposal name"
533
+ )
534
+ return self._proposal_name