tomwer 1.2.0a1__py3-none-any.whl → 1.2.0a3__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 (219) hide show
  1. orangecontrib/tomwer/tutorials/append_raw_darks_and_flats_frames_to_NXtomos.ows +44 -0
  2. orangecontrib/tomwer/tutorials/copy_reduced_darks_and_flats_meth1.ows +55 -0
  3. orangecontrib/tomwer/tutorials/copy_reduced_darks_and_flats_meth2.ows +48 -0
  4. orangecontrib/tomwer/tutorials/default_cor_search.ows +40 -0
  5. orangecontrib/tomwer/tutorials/hello_world_python_script.ows +50 -0
  6. orangecontrib/tomwer/tutorials/simple_slice_reconstruction_on_slurm.ows +50 -0
  7. orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +8 -8
  8. orangecontrib/tomwer/widgets/__init__.py +1 -1
  9. orangecontrib/tomwer/widgets/cluster/FutureSupervisorOW.py +0 -1
  10. orangecontrib/tomwer/widgets/cluster/SlurmClusterOW.py +8 -6
  11. orangecontrib/tomwer/widgets/control/AdvancementOW.py +0 -1
  12. orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +1 -6
  13. orangecontrib/tomwer/widgets/control/DataListOW.py +0 -1
  14. orangecontrib/tomwer/widgets/control/DataListenerOW.py +4 -4
  15. orangecontrib/tomwer/widgets/control/DataSelectorOW.py +0 -1
  16. orangecontrib/tomwer/widgets/control/DataTransfertOW.py +7 -7
  17. orangecontrib/tomwer/widgets/control/DataValidatorOW.py +0 -1
  18. orangecontrib/tomwer/widgets/control/DataWatcherOW.py +0 -3
  19. orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +3 -2
  20. orangecontrib/tomwer/widgets/control/EmailOW.py +82 -0
  21. orangecontrib/tomwer/widgets/control/FilterOW.py +3 -3
  22. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +1 -1
  23. orangecontrib/tomwer/widgets/control/NotifierOW.py +0 -1
  24. orangecontrib/tomwer/widgets/control/ReduceDarkFlatSelectorOW.py +93 -0
  25. orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +29 -5
  26. orangecontrib/tomwer/widgets/control/TimerOW.py +1 -2
  27. orangecontrib/tomwer/widgets/control/TomoObjSerieOW.py +0 -1
  28. orangecontrib/tomwer/widgets/control/VolumeSelector.py +0 -1
  29. orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +4 -10
  30. orangecontrib/tomwer/widgets/control/icons/email.png +0 -0
  31. orangecontrib/tomwer/widgets/control/icons/email.svg +58 -0
  32. orangecontrib/tomwer/widgets/control/icons/reduced_darkflat_selector.png +0 -0
  33. orangecontrib/tomwer/widgets/control/icons/reduced_darkflat_selector.svg +199 -0
  34. orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +0 -1
  35. orangecontrib/tomwer/widgets/debugtools/ObjectInspectorOW.py +0 -1
  36. orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +1 -2
  37. orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +1 -2
  38. orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +0 -1
  39. orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +0 -1
  40. orangecontrib/tomwer/widgets/other/PythonScriptOW.py +29 -1
  41. orangecontrib/tomwer/widgets/other/TomoObjsHub.py +28 -0
  42. orangecontrib/tomwer/widgets/other/icons/hub.png +0 -0
  43. orangecontrib/tomwer/widgets/other/icons/hub.svg +113 -0
  44. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +18 -12
  45. orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +0 -2
  46. orangecontrib/tomwer/widgets/reconstruction/DarkRefAndCopyOW.py +21 -6
  47. orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +29 -7
  48. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +18 -5
  49. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +40 -13
  50. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +37 -10
  51. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +2 -3
  52. orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +5 -4
  53. orangecontrib/tomwer/widgets/stitching/StitcherOW.py +0 -1
  54. orangecontrib/tomwer/widgets/stitching/ZStitchingConfigOW.py +0 -1
  55. orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +10 -4
  56. orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
  57. orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +0 -1
  58. orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +0 -1
  59. orangecontrib/tomwer/widgets/visualization/RadioStackOW.py +7 -5
  60. orangecontrib/tomwer/widgets/visualization/SampleMovedOW.py +1 -1
  61. orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +0 -3
  62. orangecontrib/tomwer/widgets/visualization/SliceStackOW.py +7 -5
  63. orangecontrib/tomwer/widgets/visualization/VolumeViewerOW.py +4 -4
  64. tomwer/__main__.py +139 -5
  65. tomwer/app/axis.py +16 -5
  66. tomwer/app/canvas_launcher/config.py +1 -1
  67. tomwer/app/canvas_launcher/mainwindow.py +164 -6
  68. tomwer/app/darkref.py +10 -181
  69. tomwer/app/darkrefpatch.py +10 -131
  70. tomwer/app/diffframe.py +11 -0
  71. tomwer/app/imagekeyeditor.py +12 -19
  72. tomwer/app/intensitynormalization.py +1 -0
  73. tomwer/app/lamino.py +7 -2
  74. tomwer/app/patchrawdarkflat.py +131 -0
  75. tomwer/app/radiostack.py +10 -0
  76. tomwer/app/reducedarkflat.py +205 -0
  77. tomwer/app/saaxis.py +27 -8
  78. tomwer/app/sadeltabeta.py +29 -8
  79. tomwer/app/samplemoved.py +11 -0
  80. tomwer/app/scanviewer.py +12 -0
  81. tomwer/app/sinogramviewer.py +11 -0
  82. tomwer/app/slicestack.py +11 -0
  83. tomwer/app/zstitching.py +12 -0
  84. tomwer/core/futureobject.py +4 -2
  85. tomwer/core/process/conditions/filters.py +26 -4
  86. tomwer/core/process/control/datadiscovery.py +4 -0
  87. tomwer/core/process/control/datawatcher/datawatcher.py +5 -1
  88. tomwer/core/process/control/email.py +148 -0
  89. tomwer/core/process/control/nxtomoconcatenate.py +9 -2
  90. tomwer/core/process/control/nxtomomill.py +58 -16
  91. tomwer/core/process/control/scanselector.py +4 -0
  92. tomwer/core/process/control/scantransfer.py +52 -23
  93. tomwer/core/process/control/test/test_concatenate_nxtomos.py +1 -0
  94. tomwer/core/process/control/test/test_email.py +52 -0
  95. tomwer/core/process/control/test/test_h52nx_process.py +106 -0
  96. tomwer/core/process/control/test/test_volume_link.py +5 -4
  97. tomwer/core/process/control/timer.py +27 -6
  98. tomwer/core/process/control/tomoobjserie.py +4 -0
  99. tomwer/core/process/control/volumeselector.py +4 -0
  100. tomwer/core/process/control/volumesymlink.py +47 -8
  101. tomwer/core/process/edit/darkflatpatch.py +49 -8
  102. tomwer/core/process/edit/imagekeyeditor.py +63 -13
  103. tomwer/core/process/reconstruction/axis/__init__.py +1 -1
  104. tomwer/core/process/reconstruction/axis/axis.py +61 -41
  105. tomwer/core/process/reconstruction/axis/params.py +4 -6
  106. tomwer/core/process/reconstruction/darkref/darkrefs.py +53 -16
  107. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +12 -2
  108. tomwer/core/process/reconstruction/lamino/__init__.py +1 -1
  109. tomwer/core/process/reconstruction/lamino/tofu.py +22 -2
  110. tomwer/core/process/reconstruction/nabu/nabucommon.py +93 -14
  111. tomwer/core/process/reconstruction/nabu/nabuscores.py +70 -33
  112. tomwer/core/process/reconstruction/nabu/nabuslices.py +219 -41
  113. tomwer/core/process/reconstruction/nabu/nabuvolume.py +240 -108
  114. tomwer/core/process/reconstruction/nabu/utils.py +10 -36
  115. tomwer/core/process/reconstruction/normalization/normalization.py +10 -3
  116. tomwer/core/process/reconstruction/saaxis/__init__.py +1 -0
  117. tomwer/core/process/reconstruction/saaxis/saaxis.py +564 -376
  118. tomwer/core/process/reconstruction/sadeltabeta/__init__.py +1 -0
  119. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +481 -268
  120. tomwer/core/process/reconstruction/scores/params.py +21 -8
  121. tomwer/core/process/reconstruction/test/test_darkref_copy.py +2 -0
  122. tomwer/core/process/reconstruction/test/test_saaxis.py +21 -8
  123. tomwer/core/process/reconstruction/test/test_sadeltabeta.py +8 -5
  124. tomwer/core/process/script/python.py +7 -2
  125. tomwer/core/process/stitching/nabustitcher.py +10 -3
  126. tomwer/core/process/task.py +2 -9
  127. tomwer/core/process/test/test_axis.py +25 -15
  128. tomwer/core/process/test/test_conditions.py +6 -6
  129. tomwer/core/process/test/test_dark_and_flat.py +20 -15
  130. tomwer/core/process/test/test_data_transfer.py +8 -8
  131. tomwer/core/process/test/test_data_watcher.py +1 -1
  132. tomwer/core/process/test/test_lamino.py +6 -6
  133. tomwer/core/process/test/test_nabu.py +13 -8
  134. tomwer/core/process/test/test_normalization.py +1 -0
  135. tomwer/core/process/test/test_timer.py +6 -6
  136. tomwer/core/process/visualization/dataviewer.py +4 -0
  137. tomwer/core/process/visualization/diffviewer.py +4 -0
  138. tomwer/core/process/visualization/imagestackviewer.py +4 -0
  139. tomwer/core/process/visualization/radiostack.py +4 -0
  140. tomwer/core/process/visualization/samplemoved.py +4 -0
  141. tomwer/core/process/visualization/sinogramviewer.py +4 -0
  142. tomwer/core/process/visualization/slicestack.py +4 -0
  143. tomwer/core/process/visualization/volumeviewer.py +4 -0
  144. tomwer/core/scan/hdf5scan.py +4 -4
  145. tomwer/core/scan/scanbase.py +5 -1
  146. tomwer/core/scan/test/test_process_registration.py +9 -9
  147. tomwer/core/settings.py +59 -1
  148. tomwer/core/test/test_lamino.py +2 -1
  149. tomwer/core/utils/__init__.py +16 -0
  150. tomwer/core/utils/locker.py +0 -1
  151. tomwer/core/utils/resource.py +6 -11
  152. tomwer/core/utils/scanutils.py +2 -0
  153. tomwer/gui/cluster/slurm.py +91 -7
  154. tomwer/gui/cluster/supervisor.py +16 -11
  155. tomwer/gui/cluster/test/test_cluster.py +16 -1
  156. tomwer/gui/conditions/filter.py +3 -3
  157. tomwer/gui/control/datalist.py +24 -11
  158. tomwer/gui/control/email.py +183 -0
  159. tomwer/gui/control/reducedarkflatselector.py +545 -0
  160. tomwer/gui/control/singletomoobj.py +23 -1
  161. tomwer/gui/control/test/test_email.py +35 -0
  162. tomwer/gui/control/test/test_reducedarkflat_selector.py +280 -0
  163. tomwer/gui/reconstruction/axis/CompareImages.py +1 -1
  164. tomwer/gui/reconstruction/axis/axis.py +10 -6
  165. tomwer/gui/reconstruction/axis/radioaxis.py +14 -6
  166. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +2 -0
  167. tomwer/gui/reconstruction/darkref/darkrefwidget.py +4 -4
  168. tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +3 -1
  169. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +34 -33
  170. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +1 -1
  171. tomwer/gui/reconstruction/normalization/intensity.py +5 -5
  172. tomwer/gui/reconstruction/saaxis/corrangeselector.py +1 -0
  173. tomwer/gui/reconstruction/saaxis/saaxis.py +6 -6
  174. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +6 -6
  175. tomwer/gui/reconstruction/scores/scoreplot.py +6 -4
  176. tomwer/gui/samplemoved/__init__.py +2 -2
  177. tomwer/gui/stackplot.py +18 -7
  178. tomwer/gui/stacks.py +2 -2
  179. tomwer/gui/stitching/stitchandbackground.py +2 -2
  180. tomwer/gui/stitching/stitching.py +1 -1
  181. tomwer/gui/stitching/stitching_raw.py +1 -1
  182. tomwer/gui/utils/__init__.py +1 -85
  183. tomwer/gui/utils/illustrations.py +1 -1
  184. tomwer/gui/utils/inputwidget.py +41 -36
  185. tomwer/gui/utils/slider.py +2 -2
  186. tomwer/gui/utils/utils.py +93 -0
  187. tomwer/gui/visualization/dataviewer.py +8 -5
  188. tomwer/gui/visualization/diffviewer/diffviewer.py +4 -4
  189. tomwer/gui/visualization/reconstructionparameters.py +26 -6
  190. tomwer/gui/visualization/sinogramviewer.py +7 -1
  191. tomwer/gui/visualization/test/test_reconstruction_parameters.py +2 -4
  192. tomwer/gui/visualization/volumeviewer.py +2 -0
  193. tomwer/resources/__init__.py +55 -43
  194. tomwer/resources/gui/icons/compose.png +0 -0
  195. tomwer/resources/gui/icons/compose.svg +75 -0
  196. tomwer/synctools/datatransfert.py +3 -1
  197. tomwer/synctools/stacks/edit/darkflatpatch.py +39 -34
  198. tomwer/synctools/stacks/edit/imagekeyeditor.py +8 -27
  199. tomwer/synctools/stacks/processingstack.py +45 -9
  200. tomwer/synctools/stacks/reconstruction/axis.py +6 -5
  201. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +1 -0
  202. tomwer/synctools/stacks/reconstruction/lamino.py +3 -3
  203. tomwer/synctools/stacks/reconstruction/nabu.py +49 -140
  204. tomwer/synctools/stacks/reconstruction/normalization.py +1 -0
  205. tomwer/synctools/stacks/reconstruction/saaxis.py +19 -33
  206. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +16 -32
  207. tomwer/synctools/test/test_darkRefs.py +19 -10
  208. tomwer/synctools/test/test_foldertransfer.py +7 -7
  209. tomwer/third_party/nabu/preproc/phase.py +6 -8
  210. tomwer/third_party/nabu/utils.py +2 -3
  211. tomwer/version.py +1 -1
  212. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/METADATA +15 -54
  213. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/RECORD +219 -192
  214. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/WHEEL +1 -1
  215. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/entry_points.txt +3 -3
  216. /tomwer-1.2.0a1-py3.9-nspkg.pth → /tomwer-1.2.0a3-py3.11-nspkg.pth +0 -0
  217. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/LICENSE +0 -0
  218. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/namespace_packages.txt +0 -0
  219. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/top_level.txt +0 -0
@@ -127,7 +127,7 @@ class TestNabuIni(unittest.TestCase):
127
127
  # check volume and slice .cfg files for nabu reconstruction are here
128
128
  for file_name in (
129
129
  os.path.basename(self.scan.path) + ".cfg",
130
- os.path.basename(self.scan.path) + "slice_0001" + ".cfg",
130
+ os.path.basename(self.scan.path) + "slice_000001" + ".cfg",
131
131
  ):
132
132
  with self.subTest(file_name=file_name):
133
133
  self.assertTrue(
@@ -151,7 +151,7 @@ class TestNabuIni(unittest.TestCase):
151
151
  # check volume and slice .cfg files for nabu reconstruction are here
152
152
  for file_name in (
153
153
  os.path.basename(self.scan.path) + "pag_db0100.cfg",
154
- os.path.basename(self.scan.path) + "slice_pag_0001_db0100" + ".cfg",
154
+ os.path.basename(self.scan.path) + "slice_pag_000001_db0100" + ".cfg",
155
155
  ):
156
156
  with self.subTest(file_name=file_name):
157
157
  self.assertTrue(
@@ -178,7 +178,7 @@ class TestNabuIni(unittest.TestCase):
178
178
  ini_files.append(
179
179
  os.path.basename(self.scan.path)
180
180
  + "slice_"
181
- + str(slice_index).zfill(4)
181
+ + str(slice_index).zfill(6)
182
182
  + ".cfg"
183
183
  )
184
184
 
@@ -222,7 +222,7 @@ class TestNabuIni(unittest.TestCase):
222
222
  # add slice ini file
223
223
  ini_files.append(
224
224
  os.path.basename(self.scan.path)
225
- + "slice_pag_0001_db"
225
+ + "slice_pag_000001_db"
226
226
  + str(int(pag_db)).zfill(4)
227
227
  + ".cfg"
228
228
  )
@@ -265,7 +265,7 @@ class TestNabuIni(unittest.TestCase):
265
265
  ini_files.append(
266
266
  os.path.basename(self.scan.path)
267
267
  + "slice_pag_"
268
- + str(slice_index).zfill(4)
268
+ + str(slice_index).zfill(6)
269
269
  + "_db"
270
270
  + str(pag_db).zfill(4)
271
271
  + ".cfg"
@@ -365,9 +365,14 @@ class TestNabuAndAxis(unittest.TestCase):
365
365
  # initial configuration
366
366
  self.conf = get_nabu_default_config(output_dir=self.scan.path)
367
367
 
368
- self.nabu_process = nabu.NabuSlices(inputs={"data": self.scan})
369
- self.nabu_process.set_dry_run(True)
370
- self.nabu_process.set_configuration(self.conf)
368
+ self.nabu_process = nabu.NabuSlicesTask(
369
+ inputs={
370
+ "data": self.scan,
371
+ "nabu_params": self.conf,
372
+ "dry_run": True,
373
+ "serialize_output_data": False,
374
+ },
375
+ )
371
376
  self.scan._axis_params = AxisRP()
372
377
  self.nabu_cfg_folder = os.path.join(
373
378
  self.scan.path, nabu_settings.NABU_CFG_FILE_FOLDER
@@ -93,6 +93,7 @@ class TestNormalization(unittest.TestCase):
93
93
  inputs={
94
94
  "data": self.scan,
95
95
  "configuration": process_params,
96
+ "serialize_output_data": False,
96
97
  }
97
98
  )
98
99
  process.run()
@@ -32,7 +32,7 @@ import shutil
32
32
  import tempfile
33
33
  import unittest
34
34
 
35
- from tomwer.core.process.control.timer import Timer
35
+ from tomwer.core.process.control.timer import TimerTask
36
36
  from tomwer.core.scan.scanbase import TomwerScanBase
37
37
  from tomwer.core.utils.scanutils import MockEDF
38
38
 
@@ -53,25 +53,25 @@ class TestTimerIO(unittest.TestCase):
53
53
  def testInputOutput(self):
54
54
  """Test that io using TomoBase instance work"""
55
55
  for input_type in (dict, TomwerScanBase):
56
- for return_dict in (True, False):
56
+ for serialize_output_data in (True, False):
57
57
  with self.subTest(
58
- return_dict=return_dict,
58
+ return_dict=serialize_output_data,
59
59
  input_type=input_type,
60
60
  ):
61
61
  input_obj = self.scan
62
62
  if input_obj is dict:
63
63
  input_obj = input_obj.to_dict()
64
64
 
65
- timer_process = Timer(
65
+ timer_process = TimerTask(
66
66
  inputs={
67
67
  "wait": 0.1,
68
- "return_dict": return_dict,
68
+ "serialize_output_data": serialize_output_data,
69
69
  "data": input_obj,
70
70
  }
71
71
  )
72
72
  timer_process.run()
73
73
  out = timer_process.outputs.data
74
- if return_dict:
74
+ if serialize_output_data:
75
75
  self.assertTrue(isinstance(out, dict))
76
76
  else:
77
77
  self.assertTrue(isinstance(out, TomwerScanBase))
@@ -31,5 +31,9 @@ from ewokscore.task import Task as EwoksTask
31
31
 
32
32
 
33
33
  class _DataViewerPlaceHolder(EwoksTask, input_names=("data",)):
34
+ """
35
+ Task to browse a scan and associated processing (display raw frames, normalized projections, recosntructed slices...)
36
+ """
37
+
34
38
  def run(self):
35
39
  pass
@@ -31,5 +31,9 @@ from ewokscore.task import Task as EwoksTask
31
31
 
32
32
 
33
33
  class _DiffViewerPlaceHolder(EwoksTask, input_names=("data",)):
34
+ """
35
+ task to compare frames (between one or several dataset)
36
+ """
37
+
34
38
  def run(self):
35
39
  pass
@@ -31,5 +31,9 @@ from ewokscore.task import Task as EwoksTask
31
31
 
32
32
 
33
33
  class _ImageStackViewerPlaceHolder(EwoksTask, input_names=("data",)):
34
+ """
35
+ Task to aggregate several images
36
+ """
37
+
34
38
  def run(self):
35
39
  pass
@@ -31,5 +31,9 @@ from ewokscore.task import Task as EwoksTask
31
31
 
32
32
 
33
33
  class _RadioStackPlaceHolder(EwoksTask, input_names=("data",)):
34
+ """
35
+ Task to aggregate radios of several scans and allow to browse along them all
36
+ """
37
+
34
38
  def run(self):
35
39
  pass
@@ -32,5 +32,9 @@ from ewokscore.task import Task as EwoksTask
32
32
 
33
33
 
34
34
  class _SampleMovedPlaceHolder(EwoksTask, input_names=("data",)):
35
+ """
36
+ Task to check if a sample has moved along time / projections
37
+ """
38
+
35
39
  def run(self):
36
40
  pass
@@ -31,5 +31,9 @@ from ewokscore.task import Task as EwoksTask
31
31
 
32
32
 
33
33
  class _SinogramViewerPlaceHolder(EwoksTask, input_names=("data",)):
34
+ """
35
+ Task to display a sinogram
36
+ """
37
+
34
38
  def run(self):
35
39
  pass
@@ -32,5 +32,9 @@ from ewokscore.task import Task as EwoksTask
32
32
 
33
33
 
34
34
  class _SliceStackPlaceHolder(EwoksTask, input_names=("data",)):
35
+ """
36
+ Task to aggregate reconstructed slices of several scans and allow users to along them
37
+ """
38
+
35
39
  def run(self):
36
40
  pass
@@ -32,5 +32,9 @@ from ewokscore.task import Task as EwoksTask
32
32
 
33
33
 
34
34
  class _VolumeViewerPlaceHolder(EwoksTask, input_names=("data",)):
35
+ """
36
+ Task to plot a (reconstructed) volume
37
+ """
38
+
35
39
  def run(self):
36
40
  pass
@@ -311,10 +311,10 @@ class HDF5TomoScan(_tsHDF5TomoScan, TomwerScanBase):
311
311
  if self._reduced_darks is None:
312
312
  if self.process_file is not None and os.path.exists(self.process_file):
313
313
  from tomwer.core.process.reconstruction.darkref.darkrefs import (
314
- DarkRefs,
314
+ DarkRefsTask,
315
315
  ) # avoid cyclic import
316
316
 
317
- reduced_darks = DarkRefs.get_darks_frm_process_file(
317
+ reduced_darks = DarkRefsTask.get_darks_frm_process_file(
318
318
  process_file=self.process_file, entry=self.entry
319
319
  )
320
320
  if reduced_darks is not None:
@@ -326,10 +326,10 @@ class HDF5TomoScan(_tsHDF5TomoScan, TomwerScanBase):
326
326
  if self._reduced_flats is None:
327
327
  if self.process_file is not None and os.path.exists(self.process_file):
328
328
  from tomwer.core.process.reconstruction.darkref.darkrefs import (
329
- DarkRefs,
329
+ DarkRefsTask,
330
330
  ) # avoid cyclic import
331
331
 
332
- reduced_flats = DarkRefs.get_flats_frm_process_file(
332
+ reduced_flats = DarkRefsTask.get_flats_frm_process_file(
333
333
  process_file=self.process_file, entry=self.entry
334
334
  )
335
335
  if reduced_flats is not None:
@@ -411,7 +411,11 @@ class TomwerScanBase(TomwerObject):
411
411
  res = {}
412
412
  # nabu reconstruction parameters
413
413
  if self._nabu_params:
414
- res[self._DICT_NABU_RP_KEY] = self.nabu_recons_params.to_dict()
414
+ res[self._DICT_NABU_RP_KEY] = (
415
+ self.nabu_recons_params
416
+ if isinstance(self.nabu_recons_params, dict)
417
+ else self.nabu_recons_params.to_dict()
418
+ )
415
419
  else:
416
420
  res[self._DICT_NABU_RP_KEY] = None
417
421
  # axis reconstruction parameters
@@ -68,55 +68,55 @@ class TestProcessRegistration(unittest.TestCase):
68
68
  shutil.rmtree(self.tmp_dir)
69
69
 
70
70
  def testGetCorValues(self):
71
- from tomwer.core.process.reconstruction.axis import AxisProcess
71
+ from tomwer.core.process.reconstruction.axis import AxisTask
72
72
 
73
73
  for i in range(20):
74
74
  results = {"center_of_rotation": i}
75
75
  Task._register_process(
76
76
  self.scan.process_file,
77
- process=AxisProcess,
77
+ process=AxisTask,
78
78
  entry=self.scan.entry,
79
79
  configuration=None,
80
80
  results=results,
81
81
  process_index=i,
82
82
  )
83
- cor_value = AxisProcess.get_cor_frm_process_file(
83
+ cor_value = AxisTask.get_cor_frm_process_file(
84
84
  self.scan.process_file, entry=self.scan.entry
85
85
  )
86
86
  self.assertEqual(cor_value, 19)
87
87
 
88
88
  def testGetDarks(self):
89
- from tomwer.core.process.reconstruction.darkref.darkrefs import DarkRefs
89
+ from tomwer.core.process.reconstruction.darkref.darkrefs import DarkRefsTask
90
90
 
91
91
  for i in range(20):
92
92
  results = {"darks": {"0": i * 2}, "flats": {"1": i}}
93
93
  Task._register_process(
94
94
  self.scan.process_file,
95
- process=DarkRefs,
95
+ process=DarkRefsTask,
96
96
  entry=self.scan.entry,
97
97
  configuration=None,
98
98
  results=results,
99
99
  process_index=i,
100
100
  )
101
- flats = DarkRefs.get_darks_frm_process_file(
101
+ flats = DarkRefsTask.get_darks_frm_process_file(
102
102
  self.scan.process_file, entry=self.scan.entry
103
103
  )
104
104
  self.assertEqual(flats[list(flats.keys())[0]], 19 * 2)
105
105
 
106
106
  def testGetFlats(self):
107
- from tomwer.core.process.reconstruction.darkref.darkrefs import DarkRefs
107
+ from tomwer.core.process.reconstruction.darkref.darkrefs import DarkRefsTask
108
108
 
109
109
  for i in range(20):
110
110
  results = {"darks": {"0": i}, "flats": {"1": i}}
111
111
  Task._register_process(
112
112
  self.scan.process_file,
113
- process=DarkRefs,
113
+ process=DarkRefsTask,
114
114
  entry=self.scan.entry,
115
115
  configuration=None,
116
116
  results=results,
117
117
  process_index=i,
118
118
  )
119
- flats = DarkRefs.get_flats_frm_process_file(
119
+ flats = DarkRefsTask.get_flats_frm_process_file(
120
120
  self.scan.process_file, entry=self.scan.entry
121
121
  )
122
122
  self.assertEqual(flats[list(flats.keys())[0]], 19)
tomwer/core/settings.py CHANGED
@@ -29,6 +29,8 @@ __date__ = "02/06/2017"
29
29
 
30
30
 
31
31
  import os
32
+ from silx.utils.enum import Enum as _Enum
33
+
32
34
 
33
35
  __LBSRAM_PATH = '/lbsram'
34
36
 
@@ -84,8 +86,33 @@ def _set_dest_path(path):
84
86
  __DEST_PATH = path
85
87
 
86
88
 
89
+ class SlurmSettingsMode(_Enum):
90
+ MANUAL = "manual"
91
+ GENERIC = "generic"
92
+ CAST_VOLUME = "cast_volume"
93
+ SLICE_RECONSTRUCTION = "slice_reconstruction"
94
+ VOLUME_RECONSTRUCTION = "volume_reconstruction"
95
+
96
+ @staticmethod
97
+ def get_settings_class(mode):
98
+ assert isinstance(mode, SlurmSettingsMode)
99
+ if mode is SlurmSettingsMode.MANUAL:
100
+ return None
101
+ elif mode is SlurmSettingsMode.GENERIC:
102
+ return SlurmSettings
103
+ elif mode is SlurmSettingsMode.CAST_VOLUME:
104
+ return DefaultSlurmSettingsCastVolume
105
+ elif mode is SlurmSettingsMode.SLICE_RECONSTRUCTION:
106
+ return DefaultSlurmSettingsSliceReconstruction
107
+ elif mode is SlurmSettingsMode.VOLUME_RECONSTRUCTION:
108
+ return DefaultSlurmSettingsVolumeReconstruction
109
+ else:
110
+ raise ValueError(f"{mode} not handled")
111
+
112
+
87
113
  class SlurmSettings:
88
114
  # Default slurm cluster configuration
115
+
89
116
  N_CORES_PER_TASK = 4
90
117
  """Number of CPU per worker"""
91
118
 
@@ -95,7 +122,7 @@ class SlurmSettings:
95
122
  N_JOBS = 1
96
123
  """on how many job we want to split the EwoksTask"""
97
124
 
98
- MEMORY_PER_WORKER = 50 # memory in GB
125
+ MEMORY_PER_WORKER = 64 # memory in GB
99
126
  """Amount of memory per worker"""
100
127
 
101
128
  PARTITION = "p9gpu"
@@ -113,3 +140,34 @@ class SlurmSettings:
113
140
  PROJECT_NAME = "tomwer_{scan}_-_{process}_-_{info}"
114
141
  """Slurm cluster project name. `scan`, `process` and `info` will be format.
115
142
  """
143
+
144
+
145
+ class DefaultSlurmSettingsCastVolume(SlurmSettings):
146
+ """
147
+ default proposed configuration for casting a volume remotly
148
+ """
149
+ N_GPUS_PER_WORKER = 0
150
+
151
+ N_CORES_PER_TASK = 8
152
+
153
+ MEMORY_PER_WORKER = 128 # memory in GB
154
+
155
+ PARTITION = "nice*"
156
+
157
+
158
+ class DefaultSlurmSettingsSliceReconstruction(SlurmSettings):
159
+ """
160
+ default proposed configuration for reconstructing a single slice remotly
161
+ """
162
+ MEMORY_PER_WORKER = 256 # memory in GB
163
+
164
+ PARTITION = None
165
+
166
+
167
+ class DefaultSlurmSettingsVolumeReconstruction(SlurmSettings):
168
+ """
169
+ default proposed configuration for reconstructing a full volume remotly
170
+ """
171
+ MEMORY_PER_WORKER = 256 # memory in GB
172
+
173
+ PARTITION = None
@@ -44,7 +44,7 @@ class TestTofuReconstruction(unittest.TestCase):
44
44
  def setUp(self):
45
45
  self._scan_path = tempfile.mkdtemp()
46
46
  self.scan = EDFTomoScan(self._scan_path)
47
- self.reconstruction = tofu.LaminoReconstruction(
47
+ self.reconstruction = tofu.LaminoReconstructionTask(
48
48
  inputs={
49
49
  "dry_run": True,
50
50
  "data": self.scan,
@@ -53,6 +53,7 @@ class TestTofuReconstruction(unittest.TestCase):
53
53
  "projections": "tata-yoyo",
54
54
  "output": "output_dir",
55
55
  },
56
+ "serialize_output_data": False,
56
57
  }
57
58
  )
58
59
 
@@ -448,3 +448,19 @@ def DownloadDataset(dataset, output_folder, timeout, unpack=False):
448
448
  if unpack is True:
449
449
  shutil.unpack_archive(archive_folder, extract_dir=output_folder, format="bztar")
450
450
  os.remove(archive_folder)
451
+
452
+
453
+ def concatenate_dict(dict_1, dict_2) -> dict:
454
+ """update dict which has dict as values. And we want concatenate those values to"""
455
+ res = dict_1.copy()
456
+ for key in dict_2:
457
+ if key in dict_1:
458
+ if key in [f"axis_{axis}_params" for axis in (0, 1, 2)]:
459
+ res[key] = ";".join((dict_1[key], dict_2[key]))
460
+ elif isinstance(dict_1[key], dict):
461
+ res[key] = concatenate_dict(dict_1=dict_1[key], dict_2=dict_2[key])
462
+ else:
463
+ res.update({key: dict_2[key]})
464
+ else:
465
+ res[key] = dict_2[key]
466
+ return res
@@ -81,6 +81,5 @@ class FileLockerManager:
81
81
  # from pathlib import Path
82
82
  # Path(lock_file_path).touch()
83
83
  if lock_file_path not in _FILE_LOCKERS:
84
- print("create lock to", lock_file_path)
85
84
  _FILE_LOCKERS[lock_file_path] = Lock(lock_file_path, default_timeout=3)
86
85
  return _FILE_LOCKERS[lock_file_path]
@@ -27,6 +27,7 @@ __license__ = "MIT"
27
27
  __date__ = "25/11/2021"
28
28
 
29
29
  import logging
30
+ import resource
30
31
 
31
32
  _logger = logging.getLogger(__name__)
32
33
 
@@ -34,15 +35,9 @@ _logger = logging.getLogger(__name__)
34
35
  def increase_max_number_file():
35
36
  """increase the maximal number of file the software can open within respect of the hard limit"""
36
37
  try:
37
- import resource
38
- except ImportError:
39
- _logger.debug("No resource module available")
38
+ hard_nofile = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
39
+ resource.setrlimit(resource.RLIMIT_NOFILE, (hard_nofile, hard_nofile))
40
+ except (ValueError, OSError):
41
+ _logger.warning("Failed to retrieve and set the max opened files limit")
40
42
  else:
41
- if hasattr(resource, "RLIMIT_NOFILE"):
42
- try:
43
- hard_nofile = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
44
- resource.setrlimit(resource.RLIMIT_NOFILE, (hard_nofile, hard_nofile))
45
- except (ValueError, OSError):
46
- _logger.warning("Failed to retrieve and set the max opened files limit")
47
- else:
48
- _logger.debug("Set max opened files to %d", hard_nofile)
43
+ _logger.debug("Set max opened files to %d", hard_nofile)
@@ -407,6 +407,8 @@ def data_identifier_to_scan(data_identifier: Any):
407
407
  """
408
408
  if isinstance(data_identifier, str):
409
409
  return ScanFactory.create_tomo_object_from_identifier(data_identifier)
410
+ elif isinstance(data_identifier, dict):
411
+ return ScanFactory.create_scan_object_frm_dict(data_identifier)
410
412
  else:
411
413
  return data_identifier
412
414
 
@@ -33,7 +33,8 @@ from typing import Optional
33
33
  from silx.gui import qt
34
34
  from sluurp.utils import get_partitions
35
35
 
36
- from tomwer.core.settings import SlurmSettings
36
+ from tomwer.core.settings import SlurmSettings, SlurmSettingsMode
37
+ from tomwer.gui.utils.qt_utils import block_signals
37
38
 
38
39
 
39
40
  class SlurmSettingsDialog(qt.QDialog):
@@ -44,7 +45,8 @@ class SlurmSettingsDialog(qt.QDialog):
44
45
  super().__init__(parent=parent)
45
46
 
46
47
  self.setLayout(qt.QVBoxLayout())
47
- self._mainWidget = SlurmSettingsWidget(parent=self)
48
+ self._mainWidget = SlurmSettingsWindow(parent=self)
49
+ self._mainWidget.setWindowFlags(qt.Qt.Widget)
48
50
  self.layout().addWidget(self._mainWidget)
49
51
 
50
52
  # buttons for validation
@@ -71,6 +73,88 @@ class SlurmSettingsDialog(qt.QDialog):
71
73
  self._mainWidget.setConfiguration(config=config)
72
74
 
73
75
 
76
+ class SlurmSettingsWindow(qt.QMainWindow):
77
+ """
78
+ Main window to define slurm settings.
79
+ Composed of the SlurmSettingsWidget and a combobox with some predefined settings
80
+ """
81
+
82
+ sigConfigChanged = qt.Signal()
83
+ """Signal emit when the SlurmSetting changed"""
84
+
85
+ def __init__(self, parent: Optional[qt.QWidget] = None) -> None:
86
+ super().__init__(parent)
87
+ self._mainWidget = qt.QWidget(self)
88
+ self._mainWidget.setLayout(qt.QFormLayout())
89
+
90
+ self._modeCombox = qt.QComboBox(self)
91
+ self._mainWidget.layout().addRow("configuration: ", self._modeCombox)
92
+ self._modeCombox.addItems(SlurmSettingsMode.values())
93
+ self._modeCombox.setCurrentText(SlurmSettingsMode.GENERIC.value)
94
+
95
+ self._settingsWidget = SlurmSettingsWidget(self)
96
+ self._mainWidget.layout().addRow(self._settingsWidget)
97
+
98
+ self.setCentralWidget(self._mainWidget)
99
+
100
+ # set up
101
+ self._reloadPredefinedSettings()
102
+
103
+ # connect signal / slot
104
+ self._modeCombox.currentIndexChanged.connect(self._reloadPredefinedSettings)
105
+ self._settingsWidget.sigConfigChanged.connect(self._configChanged)
106
+ # when the settings widget is edited them we automatically move to 'manual' settings. To notify visually the user
107
+ self._settingsWidget.sigConfigChanged.connect(self._switchToManual)
108
+
109
+ def _reloadPredefinedSettings(self, *args, **kkwargs):
110
+ """
111
+ reload settings from some predefined configuration
112
+ """
113
+ mode = self.getCurrentSettingsMode()
114
+ settingsClass = SlurmSettingsMode.get_settings_class(mode)
115
+ if settingsClass:
116
+ with block_signals(self._settingsWidget):
117
+ self.setConfiguration(
118
+ {
119
+ "cpu-per-task": settingsClass.N_CORES_PER_TASK,
120
+ "n_tasks": settingsClass.N_TASKS,
121
+ "n_jobs": settingsClass.N_JOBS,
122
+ "memory": settingsClass.MEMORY_PER_WORKER,
123
+ "partition": settingsClass.PARTITION,
124
+ "n_gpus": settingsClass.N_GPUS_PER_WORKER,
125
+ "job_name": settingsClass.PROJECT_NAME,
126
+ "walltime": settingsClass.DEFAULT_WALLTIME,
127
+ "python_venv": settingsClass.PYTHON_VENV,
128
+ }
129
+ )
130
+
131
+ def _configChanged(self, *args, **kwargs):
132
+ self.sigConfigChanged.emit()
133
+
134
+ def _switchToManual(self):
135
+ self._modeCombox.setCurrentText(SlurmSettingsMode.MANUAL.value)
136
+
137
+ def getCurrentSettingsMode(self) -> SlurmSettingsMode:
138
+ return SlurmSettingsMode.from_value(self._modeCombox.currentText())
139
+
140
+ def setCurrentSettingsMode(self, mode: SlurmSettingsMode) -> SlurmSettingsMode:
141
+ mode = SlurmSettingsMode.from_value(mode)
142
+ self._modeCombox.setCurrentText(mode.value)
143
+
144
+ # expose API
145
+ def getConfiguration(self) -> dict:
146
+ return self._settingsWidget.getConfiguration()
147
+
148
+ def getSlurmClusterConfiguration(self) -> dict:
149
+ return self._settingsWidget.getSlurmClusterConfiguration()
150
+
151
+ def setConfiguration(self, config: dict) -> None:
152
+ self._settingsWidget.setConfiguration(config=config)
153
+
154
+ def isSlurmActive(self):
155
+ return self._settingsWidget.isSlurmActive()
156
+
157
+
74
158
  class SlurmSettingsWidget(qt.QWidget):
75
159
  """Widget used to define Slurm configuration to be used"""
76
160
 
@@ -212,19 +296,19 @@ class SlurmSettingsWidget(qt.QWidget):
212
296
  return self._nCores.value()
213
297
 
214
298
  def setNCores(self, n: int) -> None:
215
- self._nCores.setValue(n)
299
+ self._nCores.setValue(int(n))
216
300
 
217
301
  def getNWorkers(self) -> int:
218
302
  return self._nWorkers.value()
219
303
 
220
304
  def setNWorkers(self, n) -> None:
221
- self._nWorkers.setValue(n)
305
+ self._nWorkers.setValue(int(n))
222
306
 
223
307
  def getMemory(self) -> int:
224
308
  return self._memory.value()
225
309
 
226
310
  def setMemory(self, memory: int) -> None:
227
- self._memory.setValue(memory)
311
+ self._memory.setValue(int(memory))
228
312
 
229
313
  def getQueue(self) -> str:
230
314
  return self._queue.currentText()
@@ -236,13 +320,13 @@ class SlurmSettingsWidget(qt.QWidget):
236
320
  return self._nGpu.value()
237
321
 
238
322
  def setNGPU(self, n: int) -> None:
239
- self._nGpu.setValue(n)
323
+ self._nGpu.setValue(int(n))
240
324
 
241
325
  def getNJobs(self) -> int:
242
326
  return self._nJobs.value()
243
327
 
244
328
  def setNJobs(self, value: int):
245
- self._nJobs.setValue(value)
329
+ self._nJobs.setValue(int(value))
246
330
 
247
331
  def getProjectName(self):
248
332
  return self._jobName.text()