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
@@ -1,35 +1,3 @@
1
- # coding: utf-8
2
- # /*##########################################################################
3
- #
4
- # Copyright (c) 2016-2017 European Synchrotron Radiation Facility
5
- #
6
- # Permission is hereby granted, free of charge, to any person obtaining a copy
7
- # of this software and associated documentation files (the "Software"), to deal
8
- # in the Software without restriction, including without limitation the rights
9
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- # copies of the Software, and to permit persons to whom the Software is
11
- # furnished to do so, subject to the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be included in
14
- # all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
- # THE SOFTWARE.
23
- #
24
- # ###########################################################################*/
25
- """
26
- contains gui relative to axis calculation using radios
27
- """
28
-
29
- __authors__ = ["C. Nemoz", "H. Payno"]
30
- __license__ = "MIT"
31
- __date__ = "25/02/2019"
32
-
33
1
  import enum
34
2
  import logging
35
3
  import os
@@ -56,6 +24,8 @@ from tomwer.core.scan.scanfactory import ScanFactory
56
24
  from tomwer.core.utils import image
57
25
  from tomwer.gui.utils.buttons import PadlockButton
58
26
  from tomwer.gui.utils.qt_utils import block_signals
27
+ from tomwer.gui.settings import EDITING_BACKGROUND_COLOR
28
+ from tomwer.gui.utils.step import StepSizeSelectorWidget
59
29
  from tomwer.synctools.axis import QAxisRP
60
30
 
61
31
  from .CompareImages import CompareImages
@@ -488,16 +458,10 @@ class RadioAxisWindow(qt.QMainWindow):
488
458
 
489
459
  with block_signals(self):
490
460
  try:
491
- try:
492
- self._plot.setData(
493
- image1=self._shiftedImgA,
494
- image2=self._shiftedImgB,
495
- updateColormap=False,
496
- )
497
- except TypeError:
498
- self._plot.setData(
499
- image1=self._shiftedImgA, image2=self._shiftedImgB
500
- )
461
+ self._plot.setData(
462
+ image1=self._shiftedImgA,
463
+ image2=self._shiftedImgB,
464
+ )
501
465
  except ValueError:
502
466
  _logger.warning(
503
467
  "Unable to set images. Maybe there is some "
@@ -671,12 +635,12 @@ class _AxisManual(qt.QWidget):
671
635
  self._manualSelectionWidget.sigResetZoomRequested.connect(
672
636
  self._requestZoomReset
673
637
  )
674
- self._imgOpts.sigSubsamplingChanged.connect(self._subsamplingChanged)
675
- self._mainWidget.sigUrlChanged.connect(self._urlChanged)
638
+ self._imgOpts.sigSubsamplingChanged.connect(self.sigSubsamplingChanged)
639
+ self._mainWidget.sigUrlChanged.connect(self.sigUrlChanged)
676
640
 
677
641
  # expose API
678
- self.getShiftStep = self._displacementSelector.getShiftStep
679
- self.setShiftStep = self._displacementSelector.setShiftStep
642
+ self.getShiftStep = self._displacementSelector.getStepSize
643
+ self.setShiftStep = self._displacementSelector.setStepSize
680
644
  self.sigRoiChanged = self._roiControl.sigRoiChanged
681
645
  self.sigAuto = self._shiftControl.sigAuto
682
646
  self.getROIOrigin = self._roiControl.getROIOrigin
@@ -696,12 +660,6 @@ class _AxisManual(qt.QWidget):
696
660
  def manual_uses_full_image(self, value):
697
661
  self._roiControl.manual_uses_full_image(value)
698
662
 
699
- def _urlChanged(self):
700
- self.sigUrlChanged.emit()
701
-
702
- def _subsamplingChanged(self):
703
- self.sigSubsamplingChanged.emit()
704
-
705
663
  def _incrementLeftShift(self):
706
664
  self._incrementShift("left")
707
665
 
@@ -843,7 +801,13 @@ class _AxisManualSelection(qt.QWidget):
843
801
  def __init__(self, parent, shift_mode):
844
802
  qt.QWidget.__init__(self, parent)
845
803
  self.setLayout(qt.QVBoxLayout())
846
- self._displacementSelector = _DisplacementSelector(parent=self)
804
+ self._displacementSelector = StepSizeSelectorWidget(
805
+ parent=self,
806
+ fine_value=0.1,
807
+ medium_value=1.0,
808
+ rough_value=None,
809
+ dtype=float,
810
+ )
847
811
  self.layout().addWidget(self._displacementSelector)
848
812
 
849
813
  self._shiftControl = _ShiftControl(parent=self, shift_mode=shift_mode)
@@ -856,10 +820,7 @@ class _AxisManualSelection(qt.QWidget):
856
820
  self.layout().addWidget(self._imgOpts)
857
821
 
858
822
  # connect signal / slot
859
- self._roiControl.sigResetZoomRequested.connect(self._requestZoomReset)
860
-
861
- def _requestZoomReset(self):
862
- self.sigResetZoomRequested.emit()
823
+ self._roiControl.sigResetZoomRequested.connect(self.sigResetZoomRequested)
863
824
 
864
825
 
865
826
  class _ROIControl(qt.QGroupBox):
@@ -895,8 +856,8 @@ class _ROIControl(qt.QGroupBox):
895
856
 
896
857
  # connect signal / Slot
897
858
  self._roiButton.toggled.connect(self._roiDefinition.setEnabled)
898
- self._fullImgButton.toggled.connect(self._requestZoomReset)
899
- self._roiButton.toggled.connect(self._requestZoomReset)
859
+ self._fullImgButton.toggled.connect(self.sigResetZoomRequested)
860
+ self._roiButton.toggled.connect(self.sigResetZoomRequested)
900
861
 
901
862
  # expose API
902
863
  self.sigRoiChanged = self._roiDefinition.sigRoiChanged
@@ -919,9 +880,6 @@ class _ROIControl(qt.QGroupBox):
919
880
  else:
920
881
  self._roiButton.setChecked(True)
921
882
 
922
- def _requestZoomReset(self):
923
- self.sigResetZoomRequested.emit()
924
-
925
883
 
926
884
  class _ROIDefinition(qt.QWidget):
927
885
  """
@@ -1165,12 +1123,39 @@ class _ShiftInformation(qt.QWidget):
1165
1123
  class _ShiftLineEdit(qt.QLineEdit):
1166
1124
  def __init__(self, *args, **kwargs):
1167
1125
  qt.QLineEdit.__init__(self, *args, **kwargs)
1126
+ self._defaultBackgroundColor = None
1127
+ # validator
1168
1128
  validator = qt.QDoubleValidator(parent=self, decimals=2)
1169
1129
  self.setValidator(validator)
1130
+ self._getDefaultBackgroundColor()
1131
+ # connect signal / slot
1132
+ self.textEdited.connect(self._userEditing)
1133
+ self.editingFinished.connect(self._userEndEditing)
1170
1134
 
1171
1135
  def sizeHint(self):
1172
1136
  return qt.QSize(40, 10)
1173
1137
 
1138
+ def _getDefaultBackgroundColor(self):
1139
+ if self._defaultBackgroundColor is None:
1140
+ self._defaultBackgroundColor = self.palette().color(
1141
+ self.backgroundRole()
1142
+ )
1143
+ return self._defaultBackgroundColor
1144
+
1145
+ def _userEditing(self, *args, **kwargs):
1146
+ palette = self.palette()
1147
+ palette.setColor(self.backgroundRole(), EDITING_BACKGROUND_COLOR)
1148
+ self.setPalette(palette)
1149
+
1150
+ def _userEndEditing(self, *args, **kwargs):
1151
+ print("user end editing")
1152
+ palette = self.palette()
1153
+ palette.setColor(
1154
+ self.backgroundRole(),
1155
+ self._getDefaultBackgroundColor(),
1156
+ )
1157
+ self.setPalette(palette)
1158
+
1174
1159
  sigShiftChanged = qt.Signal(float, float)
1175
1160
  """Signal emitted ony when xLE and yLE edition is finished"""
1176
1161
 
@@ -1213,69 +1198,6 @@ class _ShiftInformation(qt.QWidget):
1213
1198
  self.sigShiftChanged.emit(float(self._xLE.text()), float(self._yLE.text()))
1214
1199
 
1215
1200
 
1216
- class _DisplacementSelector(qt.QGroupBox):
1217
- """
1218
- Group box to define the displacement step value
1219
- """
1220
-
1221
- def __init__(self, parent):
1222
- qt.QGroupBox.__init__(self, "shift step", parent)
1223
- self.setLayout(qt.QVBoxLayout())
1224
- self._buttonGrp = qt.QButtonGroup(parent=self)
1225
- self._buttonGrp.setExclusive(True)
1226
-
1227
- self._rawButton = qt.QRadioButton("Rough (1 pixel)", parent=self)
1228
- self.layout().addWidget(self._rawButton)
1229
- self._buttonGrp.addButton(self._rawButton)
1230
-
1231
- self._fineButton = qt.QRadioButton("Fine (0.1 pixel)", parent=self)
1232
- self.layout().addWidget(self._fineButton)
1233
- self._buttonGrp.addButton(self._fineButton)
1234
-
1235
- self._manualWidget = qt.QWidget(parent=self)
1236
- self._manualWidget.setLayout(qt.QHBoxLayout())
1237
- self._manualWidget.layout().setContentsMargins(0, 0, 0, 0)
1238
- self._manualWidget.layout().setSpacing(0)
1239
- self._manualButton = qt.QRadioButton("Manual", parent=self._manualWidget)
1240
- self._manualWidget.layout().addWidget(self._manualButton)
1241
- self._manualLE = qt.QLineEdit("0.5", parent=self._manualWidget)
1242
- validator = qt.QDoubleValidator(parent=self._manualLE, decimals=2)
1243
- validator.setBottom(0.0)
1244
- self._manualLE.setValidator(validator)
1245
- self._manualWidget.layout().addWidget(self._manualLE)
1246
-
1247
- self.layout().addWidget(self._manualWidget)
1248
- self._manualLE.setEnabled(False)
1249
- self._buttonGrp.addButton(self._manualButton)
1250
-
1251
- self._rawButton.setChecked(True)
1252
-
1253
- # signal / slot connection
1254
- self._manualButton.toggled.connect(self._manualLE.setEnabled)
1255
-
1256
- def getShiftStep(self):
1257
- """
1258
-
1259
- :return: displacement shift defined
1260
- :rtype: float
1261
- """
1262
- if self._rawButton.isChecked():
1263
- return 1.0
1264
- elif self._fineButton.isChecked():
1265
- return 0.1
1266
- else:
1267
- return float(self._manualLE.text())
1268
-
1269
- def setShiftStep(self, value):
1270
- """
1271
-
1272
- :param float value: shift step
1273
- """
1274
- assert type(value) is float
1275
- self._manualButton.setChecked(True)
1276
- self._manualLE.setText(str(value))
1277
-
1278
-
1279
1201
  class _AxisOptionsWidget(qt.QWidget):
1280
1202
  """GUI to tune the axis algorithm"""
1281
1203
 
@@ -1501,9 +1423,7 @@ class AxisTabWidget(qt.QTabWidget):
1501
1423
  self.getEstimatedCor = self._calculationWidget.getEstimatedCor
1502
1424
 
1503
1425
  # connect signal / slot
1504
- self._calculationWidget.sigLockModeChanged.connect(
1505
- self._propagateSigLockModeChanged
1506
- )
1426
+ self._calculationWidget.sigLockModeChanged.connect(self.sigLockModeChanged)
1507
1427
  self.sigModeChanged.connect(self._updatePossibleInput)
1508
1428
  self._inputWidget._sigUrlChanged.connect(self._urlChanged)
1509
1429
  # not very nice but very convenient to have the setting near at the same level
@@ -1526,9 +1446,6 @@ class AxisTabWidget(qt.QTabWidget):
1526
1446
  def _urlChanged(self):
1527
1447
  self.sigUrlChanged.emit()
1528
1448
 
1529
- def _propagateSigLockModeChanged(self, lock):
1530
- self.sigLockModeChanged.emit(lock)
1531
-
1532
1449
  def getMode(self):
1533
1450
  """Return algorithm to use for axis calculation"""
1534
1451
  return self._calculationWidget.getMode()
@@ -1546,17 +1463,12 @@ class AxisTabWidget(qt.QTabWidget):
1546
1463
  def _updatePossibleInput(self):
1547
1464
  """Update Input tab according to the current mode"""
1548
1465
  current_mode = self.getMode()
1549
- if current_mode not in axis_mode._VALID_INPUTS:
1550
- raise ValueError(
1551
- f"valid input should have been defined for the mode {current_mode.value}"
1552
- )
1466
+ valid_inputs = axis_mode.AXIS_MODE_METADATAS[current_mode].valid_inputs
1467
+ if valid_inputs is None:
1468
+ self._inputWidget.setEnabled(False)
1553
1469
  else:
1554
- valid_inputs = axis_mode._VALID_INPUTS[current_mode]
1555
- if valid_inputs is None:
1556
- self._inputWidget.setEnabled(False)
1557
- else:
1558
- self._inputWidget.setEnabled(True)
1559
- self._inputWidget.setValidInputs(valid_inputs)
1470
+ self._inputWidget.setEnabled(True)
1471
+ self._inputWidget.setValidInputs(valid_inputs)
1560
1472
 
1561
1473
 
1562
1474
  class _CalculationWidget(qt.QWidget):
@@ -1582,45 +1494,46 @@ class _CalculationWidget(qt.QWidget):
1582
1494
  self._modeWidget.layout().addWidget(self.__rotAxisSelLabel)
1583
1495
  self._qcbPosition = qt.QComboBox(self)
1584
1496
 
1585
- algorithm_tooltips = (
1497
+ algorithm_groups = (
1498
+ # radio group
1586
1499
  (
1587
1500
  axis_mode.AxisMode.centered,
1588
- "Dedicated to fullfield. Previously named 'accurate'",
1589
- ),
1590
- (
1591
1501
  axis_mode.AxisMode.global_,
1592
- "Algorithm which can work for both half acquisition and standard ('full field') acquisition",
1593
- ),
1594
- (axis_mode.AxisMode.growing_window_radios, "A auto-Cor method"),
1595
- (
1502
+ axis_mode.AxisMode.growing_window_radios,
1596
1503
  axis_mode.AxisMode.sliding_window_radios,
1597
- "A method for estimating semi-automatically the CoR position. You have to provide a hint on where the CoR is (left, center, right).",
1504
+ axis_mode.AxisMode.octave_accurate_radios,
1598
1505
  ),
1599
- ("separator", None),
1600
- (axis_mode.AxisMode.growing_window_sinogram, "A auto-Cor method"),
1506
+ # sino group
1601
1507
  (
1508
+ axis_mode.AxisMode.growing_window_sinogram,
1602
1509
  axis_mode.AxisMode.sino_coarse_to_fine,
1603
- "Estimate CoR from sinogram. Only works for 360 degrees scans.",
1510
+ axis_mode.AxisMode.sliding_window_sinogram,
1511
+ axis_mode.AxisMode.sino_fourier_angles,
1604
1512
  ),
1513
+ # composite corase to fine
1605
1514
  (
1606
- axis_mode.AxisMode.sliding_window_sinogram,
1607
- "A method for estimating semi-automatically the CoR position. You have to provide a hint on where the CoR is (left, center, right).",
1515
+ axis_mode.AxisMode.composite_coarse_to_fine,
1516
+ axis_mode.AxisMode.near,
1608
1517
  ),
1609
- ("separator", None),
1610
- (axis_mode.AxisMode.composite_coarse_to_fine, "A auto-Cor method"),
1611
- ("separator", None),
1612
- (axis_mode.AxisMode.manual, "Enter or find manually the COR value"),
1613
- ("separator", None),
1614
- (axis_mode.AxisMode.read, "Read COR value from a file"),
1518
+ # manual
1519
+ (axis_mode.AxisMode.manual,),
1520
+ # read
1521
+ (axis_mode.AxisMode.read,),
1615
1522
  )
1616
-
1617
- for i_elmt, (method, tooltip) in enumerate(algorithm_tooltips):
1618
- if method == "separator":
1619
- self._qcbPosition.insertSeparator(i_elmt)
1620
- else:
1621
- self._qcbPosition.addItem(method.value)
1622
- idx = self._qcbPosition.findText(method.value)
1623
- self._qcbPosition.setItemData(idx, tooltip, qt.Qt.ToolTipRole)
1523
+ current_pos = 0
1524
+ for i_grp, algorithm_group in enumerate(algorithm_groups):
1525
+ if i_grp != 0:
1526
+ self._qcbPosition.insertSeparator(current_pos)
1527
+ current_pos += 1
1528
+ for cor_algorithm in algorithm_group:
1529
+ self._qcbPosition.addItem(cor_algorithm.value)
1530
+ idx = self._qcbPosition.findText(cor_algorithm.value)
1531
+ self._qcbPosition.setItemData(
1532
+ idx,
1533
+ axis_mode.AXIS_MODE_METADATAS[cor_algorithm].tooltip,
1534
+ qt.Qt.ToolTipRole,
1535
+ )
1536
+ current_pos += 1
1624
1537
 
1625
1538
  self._modeWidget.layout().addWidget(self._qcbPosition)
1626
1539
 
@@ -1734,6 +1647,9 @@ class _CalculationWidget(qt.QWidget):
1734
1647
  def setEstimatedCorValue(self, value):
1735
1648
  if value is not None:
1736
1649
  self._qleNearPosQLE.setText(str(value))
1650
+ # note: keep self._axis_params up to date.
1651
+ if self._axis_params:
1652
+ self._axis_params.estimated_cor = value
1737
1653
 
1738
1654
  def getEstimatedCor(self):
1739
1655
  try:
@@ -1760,11 +1676,6 @@ class _CalculationWidget(qt.QWidget):
1760
1676
  mode = self.getMode()
1761
1677
  with block_signals(self._qcbPosition):
1762
1678
  with block_signals(self._axis_params):
1763
- side = self.getSide()
1764
- self._nearOptsWidget.setVisible(
1765
- mode == axis_mode.AxisMode.composite_coarse_to_fine
1766
- and side == "near"
1767
- )
1768
1679
  self._corOptsWidget.setVisible(
1769
1680
  mode
1770
1681
  not in (
@@ -1774,74 +1685,38 @@ class _CalculationWidget(qt.QWidget):
1774
1685
  )
1775
1686
 
1776
1687
  self._padding_widget.setVisible(
1777
- mode
1778
- in (
1779
- axis_mode.AxisMode.centered,
1780
- axis_mode.AxisMode.global_,
1781
- axis_mode.AxisMode.growing_window_sinogram,
1782
- axis_mode.AxisMode.growing_window_radios,
1783
- axis_mode.AxisMode.sliding_window_sinogram,
1784
- axis_mode.AxisMode.sliding_window_radios,
1785
- axis_mode.AxisMode.sino_coarse_to_fine,
1786
- axis_mode.AxisMode.composite_coarse_to_fine,
1787
- )
1688
+ axis_mode.AXIS_MODE_METADATAS[mode].allows_padding
1788
1689
  )
1789
- if mode in (
1790
- axis_mode.AxisMode.centered,
1791
- axis_mode.AxisMode.global_,
1792
- axis_mode.AxisMode.growing_window_sinogram,
1793
- axis_mode.AxisMode.growing_window_radios,
1794
- axis_mode.AxisMode.sliding_window_sinogram,
1795
- axis_mode.AxisMode.sliding_window_radios,
1796
- axis_mode.AxisMode.sino_coarse_to_fine,
1797
- axis_mode.AxisMode.composite_coarse_to_fine,
1798
- ):
1690
+ if axis_mode.AXIS_MODE_METADATAS[mode].is_lockable:
1799
1691
  self._lockMethodPB.setVisible(True)
1800
1692
  else:
1801
1693
  self._lockMethodPB.setVisible(False)
1802
1694
  self.lockMode(False)
1803
1695
 
1804
- side_visible = mode in (
1805
- axis_mode.AxisMode.growing_window_sinogram,
1806
- axis_mode.AxisMode.growing_window_radios,
1807
- axis_mode.AxisMode.sliding_window_sinogram,
1808
- axis_mode.AxisMode.sliding_window_radios,
1809
- axis_mode.AxisMode.composite_coarse_to_fine,
1810
- )
1811
- self._sideWidget.setVisible(side_visible)
1812
- if side_visible is True:
1696
+ sides_visible = len(axis_mode.AXIS_MODE_METADATAS[mode].valid_sides) > 0
1697
+ self._sideWidget.setVisible(sides_visible)
1698
+ if sides_visible is True:
1813
1699
  self._updateSideVisible(mode)
1814
-
1700
+ self._nearOptsWidget.setVisible(self.getSide() == "near")
1815
1701
  self._axis_params.mode = mode.value
1816
1702
  self._axis_params.changed()
1817
1703
  self.sigModeChanged.emit(mode.value)
1818
1704
 
1819
1705
  def _updateSideVisible(self, mode: axis_mode.AxisMode):
1820
- if mode not in (
1821
- axis_mode.AxisMode.growing_window_sinogram,
1822
- axis_mode.AxisMode.growing_window_radios,
1823
- axis_mode.AxisMode.sliding_window_sinogram,
1824
- axis_mode.AxisMode.sliding_window_radios,
1825
- axis_mode.AxisMode.composite_coarse_to_fine,
1826
- ):
1706
+ mode = axis_mode.AxisMode.from_value(mode)
1707
+ if len(axis_mode.AXIS_MODE_METADATAS[mode].valid_sides) == 0:
1827
1708
  return
1828
1709
  else:
1829
1710
  current_value = self._axis_params.side
1830
1711
  with block_signals(self._sideCB):
1831
1712
  self._sideCB.clear()
1832
- values = ["left", "right", "center"]
1833
- if mode in (
1834
- axis_mode.AxisMode.growing_window_radios,
1835
- axis_mode.AxisMode.growing_window_sinogram,
1836
- ):
1837
- values.append("all")
1838
-
1839
- if mode in (axis_mode.AxisMode.composite_coarse_to_fine,):
1840
- values.append("near")
1841
-
1713
+ values = axis_mode.AXIS_MODE_METADATAS[mode].valid_sides
1842
1714
  for value in values:
1843
1715
  self._sideCB.addItem(value)
1844
1716
  idx = self._sideCB.findText(current_value)
1717
+ if idx == -1:
1718
+ # if side doesn't exists, propose right as default when possible
1719
+ idx = self._sideCB.findText("right")
1845
1720
  if idx >= 0:
1846
1721
  self._sideCB.setCurrentIndex(idx)
1847
1722
  self._axis_params.side = self.getSide()
@@ -1856,28 +1731,12 @@ class _CalculationWidget(qt.QWidget):
1856
1731
  """
1857
1732
  if mode is not None:
1858
1733
  mode = axis_mode.AxisMode.from_value(mode)
1859
- if mode is None and self.getMode() not in (
1860
- axis_mode.AxisMode.centered,
1861
- axis_mode.AxisMode.global_,
1862
- axis_mode.AxisMode.growing_window_sinogram,
1863
- axis_mode.AxisMode.growing_window_radios,
1864
- axis_mode.AxisMode.sliding_window_sinogram,
1865
- axis_mode.AxisMode.sliding_window_radios,
1866
- axis_mode.AxisMode.sino_coarse_to_fine,
1867
- axis_mode.AxisMode.composite_coarse_to_fine,
1868
- ):
1734
+ if mode is None and axis_mode.AXIS_MODE_METADATAS[self.getMode()].is_lockable():
1869
1735
  raise ValueError(
1870
1736
  "Unable to lock the current mode is not an automatic algorithm"
1871
1737
  )
1872
- elif mode != self.getMode() and mode not in (
1873
- axis_mode.AxisMode.centered,
1874
- axis_mode.AxisMode.global_,
1875
- axis_mode.AxisMode.growing_window_sinogram,
1876
- axis_mode.AxisMode.growing_window_radios,
1877
- axis_mode.AxisMode.sliding_window_sinogram,
1878
- axis_mode.AxisMode.sliding_window_radios,
1879
- axis_mode.AxisMode.sino_coarse_to_fine,
1880
- axis_mode.AxisMode.composite_coarse_to_fine,
1738
+ elif (
1739
+ mode != self.getMode() and axis_mode.AXIS_MODE_METADATAS[mode].is_lockable()
1881
1740
  ):
1882
1741
  raise ValueError("Unable to lock %s this is not a lockable mode")
1883
1742
 
@@ -1929,11 +1788,9 @@ class _CalculationWidget(qt.QWidget):
1929
1788
 
1930
1789
  def _sideChanged(self, *args, **kwargs):
1931
1790
  side = self.getSide()
1932
- self._axis_params.side = side
1933
- mode = self.getMode()
1934
- self._nearOptsWidget.setVisible(
1935
- mode == axis_mode.AxisMode.composite_coarse_to_fine and side == "near"
1936
- )
1791
+ if side not in ("", None):
1792
+ self._axis_params.side = side
1793
+ self._nearOptsWidget.setVisible(side == "near")
1937
1794
 
1938
1795
  def getCorOptions(self):
1939
1796
  return self._corOpts.text()
@@ -1970,21 +1827,16 @@ class _CalculationWidget(qt.QWidget):
1970
1827
  self._axis_params.mode = axis_mode.AxisMode.growing_window_radios
1971
1828
  self._axis_params.sigChanged.connect(self._axis_params_changed)
1972
1829
  self._axis_params_changed()
1830
+ self._sideChanged()
1973
1831
 
1974
1832
  def _axis_params_changed(self, *args, **kwargs):
1975
1833
  self.setMode(self._axis_params.mode)
1976
1834
  self.setEstimatedCorValue(self._axis_params.estimated_cor)
1977
1835
  self.setSide(self._axis_params.side)
1978
- if self._axis_params.mode in (
1979
- axis_mode.AxisMode.growing_window_sinogram,
1980
- axis_mode.AxisMode.growing_window_radios,
1981
- axis_mode.AxisMode.sliding_window_sinogram,
1982
- axis_mode.AxisMode.sliding_window_radios,
1983
- axis_mode.AxisMode.composite_coarse_to_fine,
1984
- ):
1985
- self._sideWidget.setVisible(True)
1986
- else:
1987
- self._sideWidget.setVisible(False)
1836
+ sides_visible = (
1837
+ len(axis_mode.AXIS_MODE_METADATAS[self._axis_params.mode].valid_sides) > 0
1838
+ )
1839
+ self._sideWidget.setVisible(sides_visible)
1988
1840
  self._updateSideVisible(mode=self._axis_params.mode)
1989
1841
  self.setPaddingMode(self._axis_params.padding_mode)
1990
1842
  self.setCorOptions(self._axis_params.extra_cor_options)
@@ -2502,9 +2354,22 @@ class _ManualFramesSelection(qt.QWidget):
2502
2354
  _logger.warning("no angles available, unable to get '+180°' frame")
2503
2355
  else:
2504
2356
  angle = float(self._frame1CB.currentText())
2505
- closest_180_angle = self._getClosestAssociatedAngle(
2357
+ # look for the closest 'associated' angle.
2358
+ # as the angles are not limited to [0-360] we need to check for any value.
2359
+ # if the angle is on the first part of the acquisition we expect to find it near angle +180
2360
+ # if it is on the second part (for 360 degree) we expect to find it on the first part (0-180)
2361
+ closest_pls_180_angle = self._getClosestAssociatedAngle(
2506
2362
  angle + 180.0, self._anglesAvailable
2507
2363
  )
2364
+ score_add = abs(closest_pls_180_angle - angle)
2365
+ closest_minus_180_angle = self._getClosestAssociatedAngle(
2366
+ angle - 180.0, self._anglesAvailable
2367
+ )
2368
+ score_sub = abs(closest_minus_180_angle - angle)
2369
+ if score_add >= score_sub:
2370
+ closest_180_angle = closest_pls_180_angle
2371
+ else:
2372
+ closest_180_angle = closest_minus_180_angle
2508
2373
  item_idx = self._frame2CB.findText(self._angleToStr(closest_180_angle))
2509
2374
  if item_idx < 0:
2510
2375
  _logger.error(f"Unable to find item for angle {closest_180_angle}")
@@ -36,7 +36,8 @@ from silx.gui import qt
36
36
  from silx.gui.dialog.DataFileDialog import DataFileDialog
37
37
  from silx.io.url import DataUrl
38
38
 
39
- from tomwer.core import settings, utils
39
+ from tomwer.core import settings
40
+ from tomwer.core.utils.lbsram import is_low_on_memory
40
41
  from tomwer.core.process.reconstruction.darkref.darkrefscopy import DarkRefsCopy
41
42
  from tomwer.gui.reconstruction.darkref.darkrefwidget import DarkRefWidget
42
43
  from tomwer.io.utils import get_default_directory
@@ -117,7 +118,7 @@ class DarkRefAndCopyWidget(DarkRefWidget):
117
118
  # Security: if lbs is full, skip requesting fir user ref
118
119
  if (
119
120
  settings.isOnLbsram(scanID)
120
- and utils.isLowOnMemory(settings.get_lbsram_path()) is True
121
+ and is_low_on_memory(settings.get_lbsram_path()) is True
121
122
  ):
122
123
  # if computer is running into low memory on lbsram skip it
123
124
  mess = (
@@ -198,7 +198,8 @@ class _TabGeneral(qt.QWidget):
198
198
  self._grpOptions = qt.QGroupBox("options", parent=self)
199
199
  self._grpOptions.setLayout(qt.QVBoxLayout())
200
200
  self._rmOptionCB = qt.QCheckBox(
201
- parent=self._grpOptions, text="remove raw files when done"
201
+ parent=self._grpOptions,
202
+ text="remove raw EDF files when done (for spec only)",
202
203
  )
203
204
  self.sigRmToggled = self._rmOptionCB.toggled
204
205
  self._skipOptionCB = qt.QCheckBox(
@@ -39,7 +39,7 @@ from tomwer.core.process.reconstruction.nabu.castvolume import (
39
39
  RESCALE_MAX_PERCENTILE,
40
40
  RESCALE_MIN_PERCENTILE,
41
41
  )
42
- from tomwer.core.process.reconstruction.nabu.nabucommon import NabuOutputFileFormat
42
+ from tomwer.core.process.reconstruction.output import NabuOutputFileFormat
43
43
  from tomwer.gui.qlefilesystem import QLFileSystem
44
44
  from tomwer.gui.reconstruction.nabu.nabuconfig.output import QNabuFileFormatComboBox
45
45
  from nxtomomill.io.utils import convert_str_to_tuple
@@ -51,6 +51,12 @@ class CastVolumeWidget(qt.QWidget):
51
51
  sigConfigChanged = qt.Signal()
52
52
  """Signal emit when the configuration changed"""
53
53
 
54
+ DEFAULT_OUTPUT_DATA_TYPE = "uint16"
55
+
56
+ AVAILABLE_OUTPUT_DATA_TYPE = ("uint8", "uint16", "float32", "float64")
57
+
58
+ assert DEFAULT_OUTPUT_DATA_TYPE in AVAILABLE_OUTPUT_DATA_TYPE
59
+
54
60
  def __init__(self, parent) -> None:
55
61
  super().__init__(parent=parent)
56
62
 
@@ -61,13 +67,17 @@ class CastVolumeWidget(qt.QWidget):
61
67
  self._castToLabel.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Minimum)
62
68
  self.layout().addWidget(self._castToLabel, 0, 0, 1, 1)
63
69
  self._outputDataTypeCB = qt.QComboBox(self)
64
- for data_type in ("uint8", "uint16", "float32", "float64"):
70
+ for data_type in self.AVAILABLE_OUTPUT_DATA_TYPE:
65
71
  self._outputDataTypeCB.addItem(data_type)
66
72
  self.layout().addWidget(self._outputDataTypeCB, 0, 1, 1, 3)
67
73
  # output file format
68
74
  self._outputFileformatLabel = qt.QLabel("output file format", self)
69
75
  self.layout().addWidget(self._outputFileformatLabel, 1, 0, 1, 1)
70
- self._outputFileformatCB = QNabuFileFormatComboBox(self)
76
+ # for now cast to vol is not handle to better remove it from the list
77
+ self._outputFileformatCB = QNabuFileFormatComboBox(
78
+ self, filter_formats=("vol",)
79
+ )
80
+
71
81
  self.layout().addWidget(self._outputFileformatCB, 1, 1, 1, 3)
72
82
 
73
83
  # let the user provide min and max manually
@@ -158,6 +168,7 @@ class CastVolumeWidget(qt.QWidget):
158
168
  self.layout().addWidget(self._spacer, 99, 0, 1, 3)
159
169
 
160
170
  # set up
171
+ self._outputDataTypeCB.setCurrentText(self.DEFAULT_OUTPUT_DATA_TYPE)
161
172
  self._updateCRatiosVis()
162
173
 
163
174
  # connect signal / slot