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
@@ -34,7 +34,7 @@ __date__ = "28/10/2021"
34
34
 
35
35
  import logging
36
36
  import os
37
- from copy import copy
37
+ from copy import copy, deepcopy
38
38
  from typing import Optional, Union
39
39
 
40
40
  import h5py
@@ -52,13 +52,9 @@ import tomwer.version
52
52
  from tomwer.core.process.reconstruction.nabu.nabucommon import (
53
53
  ResultsLocalRun,
54
54
  ResultSlurmRun,
55
- ResultsRun,
56
55
  ResultsWithStd,
57
56
  )
58
- from tomwer.core.process.reconstruction.nabu.nabuslices import (
59
- SingleSliceRunner,
60
- run_single_slice_reconstruction,
61
- )
57
+ from tomwer.core.process.reconstruction.nabu.nabuslices import SingleSliceRunner
62
58
  from tomwer.core.process.reconstruction.scores import (
63
59
  ComputedScore,
64
60
  ScoreMethod,
@@ -75,6 +71,14 @@ from tomwer.core.scan.scanfactory import ScanFactory
75
71
  from tomwer.core.utils import logconfig
76
72
  from tomwer.core.utils.scanutils import data_identifier_to_scan
77
73
  from tomwer.core.volume.volumefactory import VolumeFactory
74
+ from tomwer.io.utils import format_stderr_stdout
75
+ from tomwer.core.process.reconstruction.nabu.nabuscores import (
76
+ run_nabu_one_slice_several_config,
77
+ )
78
+ from tomwer.core.futureobject import FutureTomwerObject
79
+
80
+
81
+ from silx.utils.deprecation import deprecated, deprecated_warning
78
82
 
79
83
  from ..nabu import utils as nabu_utils
80
84
  from .params import SADeltaBetaParams
@@ -101,223 +105,37 @@ def one_slice_several_db(
101
105
  (url, score) as value
102
106
  :rtype: tuple
103
107
  """
104
- if isinstance(configuration, dict):
105
- configuration = SADeltaBetaParams.from_dict(configuration)
106
- elif not isinstance(configuration, SADeltaBetaParams):
107
- raise TypeError(
108
- "configuration should be a dictionary or an instance of SAAxisParams"
109
- )
110
-
111
- if scan.axis_params is None:
112
- from tomwer.core.process.reconstruction.axis import AxisRP
113
-
114
- scan.axis_params = AxisRP()
115
-
116
- configuration.check_configuration()
117
- slice_index = configuration.slice_indexes
118
- delta_beta_s = configuration.delta_beta_values
119
- output_dir = configuration.output_dir
120
- dry_run = configuration.dry_run
121
- cluster_config = configuration.cluster_config
122
- _logger.info(
123
- f"launch reconstruction of slice {slice_index} and delta / beta: {delta_beta_s}"
108
+ if isinstance(configuration, SADeltaBetaParams):
109
+ configuration = configuration.to_dict()
110
+
111
+ task = SADeltaBetaTask(
112
+ process_id=process_id,
113
+ inputs={
114
+ "data": scan,
115
+ "sa_axis_params": configuration,
116
+ "serialize_output_data": False,
117
+ },
118
+ )
119
+ task.run()
120
+ return (
121
+ task.outputs.scores,
122
+ task.outputs.std_out,
123
+ task.outputs.std_err,
124
+ task.outputs.rois,
124
125
  )
125
- if isinstance(slice_index, str):
126
- if not slice_index == "middle":
127
- raise ValueError(f"slice index {slice_index} not recognized")
128
- elif not len(slice_index) == 1:
129
- raise ValueError("only manage one slice")
130
- else:
131
- slice_index = list(slice_index.values())[0]
132
- advancement = Progress(f"sa-delta-beta - slice {slice_index} of {scan}")
133
-
134
- config = configuration.nabu_params.copy()
135
-
136
- _logger.info(f"start reconstruction of {scan}")
137
- # if scan contains some center of position copy it to nabu
138
- if scan.axis_params is not None and scan.axis_params.relative_cor_value is not None:
139
- if "reconstruction" in config:
140
- # move the cor value to the nabu reference
141
- cor_nabu_ref = scan.axis_params.relative_cor_value + scan.dim_1 / 2.0
142
- config["reconstruction"]["rotation_axis_position"] = str(cor_nabu_ref)
143
-
144
- _logger.info(f"set nabu reconstruction parameters to {scan}")
145
- scan.nabu_recons_params = config
146
-
147
- db_reconstructions = {}
148
- # key is delta / beta, value is url
149
- stderrs = []
150
- stdouts = []
151
- all_succeed = True
152
- future_tomo_objs = {}
153
- # key is delta / beta, value is future
154
- if advancement is not None:
155
- advancement.setMaxAdvancement(len(delta_beta_s))
156
- for db in delta_beta_s:
157
- if "output" not in config:
158
- config["output"] = {}
159
- if output_dir is None:
160
- config["output"]["location"] = os.path.join(
161
- scan.path, DEFAULT_RECONS_FOLDER
162
- )
163
- else:
164
- config["output"]["location"] = output_dir
165
- # TODO: allow file format modifications
166
- config["output"]["file_format"] = "hdf5"
167
- if "phase" not in config:
168
- config["phase"] = {}
169
- config["phase"]["delta_beta"] = (
170
- db,
171
- ) # warning: at this tage delta_beta expects a list of value
172
- config["phase"]["method"] = "Paganin"
173
- res = run_single_slice_reconstruction(
174
- nabu_config=config,
175
- scan=scan,
176
- slice_index=slice_index,
177
- dry_run=dry_run,
178
- ask_sinogram_registration=False,
179
- ask_sinogram_load=False,
180
- cluster_config=cluster_config,
181
- add_to_latest_reconstructions=False,
182
- process_id=process_id,
183
- )
184
- if isinstance(res, ResultsRun):
185
- all_succeed = all_succeed and res.success
186
- if isinstance(res, ResultSlurmRun):
187
- future_tomo_objs[db] = res.future_slurm_jobs
188
- if isinstance(res, ResultsWithStd):
189
- if slice_index is not None:
190
- stderrs.append(res.std_err)
191
- stdouts.append(res.std_out)
192
- if isinstance(res, ResultsLocalRun) and len(res.results_urls) > 0:
193
- assert len(res.results_urls) == 1, "only one slice expected"
194
- db_reconstructions[db] = res.results_urls[0]
195
-
196
- if advancement is not None:
197
- advancement.increaseAdvancement(1)
198
-
199
- pag = False
200
- ctf = False
201
- if "phase" in config:
202
- phase_method = config["phase"].get("method", "").lower()
203
- if phase_method in ("pag", "paganin"):
204
- pag = True
205
- elif phase_method in ("ctf",):
206
- ctf = True
207
-
208
- # treat future.
209
- for db, future_tomo_obj_list in future_tomo_objs.items():
210
- assert (
211
- len(future_tomo_obj_list) == 1
212
- ), "only one future should be created for one slice / db couple"
213
- future = future_tomo_obj_list[0]
214
- future.result()
215
- if future.cancelled() or future.exception():
216
- continue
217
- file_prefix = SingleSliceRunner.get_file_basename_reconstruction(
218
- scan=scan,
219
- slice_index=slice_index,
220
- pag=pag,
221
- db=int(db) if db is not None else None,
222
- ctf=ctf,
223
- )
224
- # retrieve url
225
- volume_identifier = nabu_utils.get_recons_volume_identifier(
226
- file_prefix=file_prefix,
227
- location=config["output"]["location"],
228
- file_format=config.get("file_format", "hdf5"),
229
- scan=scan,
230
- slice_index=None,
231
- start_z=None,
232
- end_z=None,
233
- expects_single_slice=True,
234
- )
235
-
236
- assert len(volume_identifier) <= 1, "only one slice expected"
237
- if len(volume_identifier) == 1:
238
- db_reconstructions[db] = volume_identifier[0]
239
- else:
240
- _logger.warning(
241
- f"something went wrong with reconstruction of {db} from {str(scan)}"
242
- )
243
-
244
- class PostProcessing:
245
- def run(self):
246
- datasets = self.load_datasets()
247
-
248
- mask_disk_radius = get_disk_mask_radius(datasets)
249
- scores = {}
250
- rois = {}
251
- for db, (url, data) in datasets.items():
252
- if data is None:
253
- score = None
254
- else:
255
- assert data.ndim == 2
256
- data_roi = apply_roi(data=data, radius=mask_disk_radius, url=url)
257
- rois[db] = data_roi
258
-
259
- # move data_roi to [0-1] range
260
- # preprocessing: get percentile 0 and 99 from image and
261
- # "clean" highest and lowest pixels from it
262
- min_p, max_p = numpy.percentile(data_roi, (1, 99))
263
- data_roi_int = data_roi[...]
264
- data_roi_int[data_roi_int < min_p] = min_p
265
- data_roi_int[data_roi_int > max_p] = max_p
266
- data_roi_int = (data_roi_int - min_p) / (max_p - min_p)
267
-
268
- score = ComputedScore(
269
- tv=compute_score(data=data_roi_int, method=ScoreMethod.TV),
270
- std=compute_score(data=data_roi_int, method=ScoreMethod.STD),
271
- )
272
- scores[db] = (url, score)
273
- return scores, rois
274
-
275
- def load_datasets(self):
276
- datasets_ = {}
277
- for db, volume_identifier in db_reconstructions.items():
278
- slice_url = None
279
- # in case the try processing fails
280
- try:
281
- volume = VolumeFactory.create_tomo_object_from_identifier(
282
- volume_identifier
283
- )
284
- volumes_urls = tuple(volume.browse_data_urls())
285
- if len(volumes_urls) > 1:
286
- _logger.warning(
287
- f"found a volume with mode that one url ({volumes_urls})"
288
- )
289
- slice_url = volumes_urls[0]
290
- data = get_data(slice_url)
291
- except Exception as e:
292
- _logger.error(
293
- f"Fail to compute a score for {volume_identifier}. Reason is {e}"
294
- )
295
- datasets_[db] = (slice_url, None)
296
- else:
297
- if data.ndim == 3:
298
- if data.shape[0] == 1:
299
- data = data.reshape(data.shape[1], data.shape[2])
300
- elif data.shape[2] == 1:
301
- data = data.reshape(data.shape[0], data.shape[1])
302
- else:
303
- raise ValueError(
304
- f"Data is expected to be 2D. Not {data.ndim}D"
305
- )
306
- elif data.ndim == 2:
307
- pass
308
- else:
309
- raise ValueError(f"Data is expected to be 2D. Not {data.ndim}D")
310
-
311
- datasets_[db] = (slice_url, data)
312
- return datasets_
313
-
314
- post_processing = PostProcessing()
315
- scores, rois = post_processing.run()
316
- return scores, stdouts, stderrs, rois
317
126
 
318
127
 
319
- class SADeltaBetaProcess(
320
- Task, SuperviseProcess, input_names=("data",), output_names=("data",)
128
+ class SADeltaBetaTask(
129
+ Task,
130
+ SuperviseProcess,
131
+ input_names=("data", "sa_delta_beta_params"),
132
+ output_names=("data", "best_db"),
133
+ optional_input_names=(
134
+ "dry_run",
135
+ "dump_roi",
136
+ "dump_process",
137
+ "serialize_output_data",
138
+ ),
321
139
  ):
322
140
  """
323
141
  Main process to launch several reconstruction of a single slice with
@@ -346,10 +164,9 @@ class SADeltaBetaProcess(
346
164
  self._dump_process = inputs.get("dump_process", True)
347
165
  self._dump_roi = inputs.get("dump_roi", False)
348
166
  self._sa_delta_beta_params = inputs.get("sa_delta_beta_params", None)
349
- if self._sa_delta_beta_params is not None:
350
- self.set_configuration(self._sa_delta_beta_params)
351
167
  self._std_outs = tuple()
352
168
  self._std_errs = tuple()
169
+ self._cancelled = False
353
170
 
354
171
  @property
355
172
  def dump_roi(self):
@@ -374,6 +191,7 @@ class SADeltaBetaProcess(
374
191
  def dry_run(self):
375
192
  return self._dry_run
376
193
 
194
+ @deprecated(replacement="ewoks task inputs.sa_delta_beta_params")
377
195
  def set_configuration(self, configuration: dict) -> None:
378
196
  if isinstance(configuration, SADeltaBetaParams):
379
197
  self._settings = configuration.to_dict()
@@ -414,75 +232,363 @@ class SADeltaBetaProcess(
414
232
  scan = ScanFactory.create_scan_object_frm_dict(scan)
415
233
  else:
416
234
  raise ValueError(f"input type of {scan}: {type(scan)} is not managed")
235
+
236
+ config = copy(self.inputs.sa_delta_beta_params)
237
+ params = SADeltaBetaParams.from_dict(config)
238
+
417
239
  # insure scan contains some parameter regarding sa delta / beta
418
240
  if scan.sa_delta_beta_params is None:
419
- scan.sa_delta_beta_params = SADeltaBetaParams()
241
+ scan.sa_delta_beta_params = params
242
+
243
+ # insure it also contains some axis_params
244
+ if scan.axis_params is None:
245
+ from tomwer.core.process.reconstruction.axis import AxisRP
246
+
247
+ scan.axis_params = AxisRP()
420
248
 
421
249
  # create dir if does not exists
422
- config = copy(self.get_configuration())
423
- params = SADeltaBetaParams.from_dict(config)
424
250
  if params.output_dir in (None, ""):
425
251
  params.output_dir = os.path.join(scan.path, DEFAULT_RECONS_FOLDER)
426
252
  if not os.path.exists(params.output_dir):
427
253
  os.makedirs(params.output_dir)
428
- db_res, self._std_outs, self._std_errs, rois = one_slice_several_db(
254
+
255
+ slice_index = self._preprocess_slice_index(params.slice_indexes)
256
+ delta_beta_s = params.delta_beta_values
257
+ output_dir = params.output_dir
258
+ # TODO: check: dry run should only be settable at one location
259
+ dry_run = self._dry_run or params.dry_run
260
+ cluster_config = params.cluster_config
261
+ nabu_config = params.nabu_recons_params
262
+
263
+ # step one: complete nabu configuration(s)
264
+ configs = self._config_preprocessing(
429
265
  scan=scan,
430
- configuration=params.to_dict(),
431
- process_id=self.process_id,
266
+ config=nabu_config,
267
+ delta_beta_s=delta_beta_s,
268
+ output_dir=output_dir,
269
+ )
270
+ # step 2: run reconstructions
271
+ advancement = Progress(
272
+ f"sa-delta-beta - slice {slice_index} of {scan.get_identifier().short_description()}"
432
273
  )
433
- scan.sa_delta_beta_params.scores = db_res
274
+
275
+ dbs_res = {}
276
+ rois = {}
277
+
278
+ try:
279
+ (
280
+ _,
281
+ dbs_res,
282
+ future_tomo_objs,
283
+ self._std_outs,
284
+ self._std_errs,
285
+ ) = self._run_one_slice_several_db(
286
+ scan=scan,
287
+ configs=configs,
288
+ advancement=advancement,
289
+ slice_index=slice_index,
290
+ dry_run=dry_run,
291
+ cluster_config=cluster_config,
292
+ )
293
+ except Exception as e:
294
+ _logger.error(e)
295
+ mess = f"sa-delta-beta -nabu- computation for {str(scan)} failed."
296
+ state = DatasetState.FAILED
297
+ else:
298
+ # step 3: wait for future if any
299
+ self._resolve_futures(
300
+ scan=scan,
301
+ nabu_config=next(iter(configs.items()))[
302
+ 1
303
+ ], # db is not used but paganin and other parameters are. Take the first nabu configuration available
304
+ slice_index=slice_index,
305
+ db_reconstructions=dbs_res,
306
+ future_tomo_objs=future_tomo_objs,
307
+ )
308
+
309
+ # step 4: run post processing (compute score for each slice)
310
+ try:
311
+ dbs_res, rois = self._post_processing(
312
+ scan=scan,
313
+ db_reconstructions=dbs_res,
314
+ )
315
+ except Exception as e:
316
+ _logger.error(e)
317
+ mess = f"sa-delta-beta -post-processing- computation for {str(scan)} failed."
318
+ state = DatasetState.FAILED
319
+ dbs_res = {}
320
+ else:
321
+ state = DatasetState.WAIT_USER_VALIDATION
322
+ self.delta_beta_s = scan.sa_delta_beta_params.autofocus
323
+ mess = "sa-delta-beta computation succeeded"
324
+
325
+ if self._cancelled:
326
+ state = DatasetState.CANCELLED
327
+ mess = "scan cancelled by the user"
328
+
329
+ ProcessManager().notify_dataset_state(
330
+ dataset=scan,
331
+ process=self,
332
+ state=state,
333
+ details=self._compute_mess_details(mess),
334
+ )
335
+
336
+ scan.sa_delta_beta_params.scores = dbs_res
434
337
  best_db = self.autofocus(scan=scan)
435
338
  # store nabu recons parameters to be used within the nabu volume for example.
436
- config = self.get_configuration()["nabu_params"]
437
- # beam shape is not directly used by nabu (uses ctf_geometry directly)
438
- config.get("phase", {}).pop("beam_shape", None)
339
+
439
340
  sc_config = get_default_nabu_config(nabu_fullfield_default_config)
440
- sc_config.update(config)
341
+ sc_config.update(nabu_config)
441
342
  if best_db is not None:
442
343
  sc_config["phase"]["delta_beta"] = (
443
344
  best_db,
444
345
  ) # warning: at this tage delta_beta expects a list of value
346
+ # store used reconstruction parameters - to be used later on
445
347
  scan.nabu_recons_params = sc_config
446
348
 
447
349
  # end processing
448
- self._process_end(scan=scan, db_res=db_res, score_rois=rois)
449
- self.outputs.data = scan
450
-
451
- def _process_end(self, scan, db_res, score_rois):
452
- assert isinstance(scan, TomwerScanBase)
453
- try:
454
- extra = {
455
- logconfig.DOC_TITLE: self._scheme_title,
456
- logconfig.SCAN_ID: str(scan),
457
- }
458
- slice_index = self.get_configuration().get("slice_index", None)
459
-
460
- if db_res is None:
461
- info = f"fail to compute delta/beta scores of slice {slice_index} for scan {scan}."
462
- _logger.processFailed(info, extra=extra)
463
- ProcessManager().notify_dataset_state(
464
- dataset=scan, process=self, state=DatasetState.FAILED, details=info
350
+ if self.get_input_value("serialize_output_data", True):
351
+ self.outputs.data = scan.to_dict()
352
+ else:
353
+ self.outputs.data = scan
354
+ self.outputs.best_db = best_db
355
+
356
+ self._process_end(scan=scan, db_res=dbs_res, score_rois=rois)
357
+
358
+ def _compute_mess_details(self, mess=""):
359
+ """
360
+ util to join a message and nabu std err and std out
361
+ """
362
+ nabu_logs = []
363
+ for std_err, std_out in zip(self._std_errs, self.std_outs):
364
+ nabu_logs.append(format_stderr_stdout(stdout=std_out, stderr=std_err))
365
+ self._nabu_log = nabu_logs
366
+ nabu_logs.insert(0, mess)
367
+ return "\n".join(nabu_logs)
368
+
369
+ def _config_preprocessing(self, scan, config, delta_beta_s, output_dir) -> dict:
370
+ config.get("phase", {}).pop("beam_shape", None)
371
+ # if scan contains some center of position copy it to nabu
372
+ if (
373
+ scan.axis_params is not None
374
+ and scan.axis_params.relative_cor_value is not None
375
+ ):
376
+ if "reconstruction" in config:
377
+ # move the cor value to the nabu reference
378
+ cor_nabu_ref = scan.axis_params.relative_cor_value + scan.dim_1 / 2.0
379
+ config["reconstruction"]["rotation_axis_position"] = str(cor_nabu_ref)
380
+
381
+ _logger.info(f"set nabu reconstruction parameters to {scan}")
382
+ scan.nabu_recons_params = config
383
+ res = {}
384
+ for db in delta_beta_s:
385
+ l_config = deepcopy(config)
386
+ if "output" not in config:
387
+ l_config["output"] = {}
388
+ if output_dir is None:
389
+ l_config["output"]["location"] = os.path.join(
390
+ scan.path, DEFAULT_RECONS_FOLDER
465
391
  )
466
392
  else:
467
- info = f"delta/beta scores of slice {slice_index} for scan {scan} computed."
468
- _logger.processSucceed(info, extra=extra)
469
- ProcessManager().notify_dataset_state(
470
- dataset=scan,
471
- process=self,
472
- state=DatasetState.WAIT_USER_VALIDATION,
473
- details=info,
393
+ l_config["output"]["location"] = output_dir
394
+ # TODO: allow file format modifications
395
+ l_config["output"]["file_format"] = "hdf5"
396
+ if "phase" not in config:
397
+ l_config["phase"] = {}
398
+ l_config["phase"]["delta_beta"] = db
399
+ l_config["phase"]["method"] = "Paganin"
400
+ res[db] = l_config
401
+ return res
402
+
403
+ def _run_one_slice_several_db(
404
+ self,
405
+ scan,
406
+ configs,
407
+ slice_index,
408
+ advancement,
409
+ dry_run,
410
+ cluster_config,
411
+ ):
412
+ future_tomo_objs = {}
413
+ success = True
414
+ recons_urls = {}
415
+ std_outs = []
416
+ std_errs = []
417
+
418
+ runners = run_nabu_one_slice_several_config(
419
+ nabu_configs=configs,
420
+ scan=scan,
421
+ slice_index=slice_index,
422
+ dry_run=dry_run,
423
+ file_format="hdf5",
424
+ advancement=advancement,
425
+ cluster_config=cluster_config.to_dict()
426
+ if cluster_config is not None
427
+ else None,
428
+ process_id=self.process_id,
429
+ instanciate_classes_only=True,
430
+ output_file_prefix_pattern=None,
431
+ )
432
+
433
+ for runner in runners:
434
+ if self._cancelled:
435
+ break
436
+
437
+ self._current_processing = runner
438
+ try:
439
+ results = runner.run()
440
+ except TimeoutError as e:
441
+ _logger.error(e)
442
+ else:
443
+ assert isinstance(
444
+ results, dict
445
+ ), "results should be a dictionary with delta-beta as key and urls as value"
446
+
447
+ for db, res in results.items():
448
+ success = success and res.success
449
+ if isinstance(res, ResultsWithStd):
450
+ std_outs.append(res.std_out)
451
+ std_errs.append(res.std_err)
452
+ if isinstance(res, ResultsLocalRun) and len(res.results_urls) > 0:
453
+ assert len(res.results_urls) == 1, "only one slice expected"
454
+ recons_urls[db] = res.results_urls[0]
455
+ if isinstance(res, ResultSlurmRun):
456
+ future_tomo_obj = FutureTomwerObject(
457
+ tomo_obj=scan,
458
+ process_requester_id=self.process_id,
459
+ futures=res.future_slurm_jobs,
460
+ )
461
+ future_tomo_objs[db] = future_tomo_obj
462
+
463
+ if advancement is not None:
464
+ advancement.increaseAdvancement(1)
465
+
466
+ return success, recons_urls, future_tomo_objs, std_outs, std_errs
467
+
468
+ def _post_processing(
469
+ self,
470
+ scan,
471
+ db_reconstructions,
472
+ ):
473
+ post_processing = _PostProcessing(
474
+ scan=scan,
475
+ db_reconstructions=db_reconstructions,
476
+ )
477
+ post_processing._cancelled = self._cancelled
478
+ self._current_processing = post_processing
479
+ return post_processing.run()
480
+
481
+ def _resolve_futures(
482
+ self,
483
+ scan,
484
+ nabu_config: dict,
485
+ db_reconstructions,
486
+ slice_index,
487
+ future_tomo_objs: dict,
488
+ ):
489
+ assert isinstance(nabu_config, dict)
490
+ pag = False
491
+ ctf = False
492
+ if "phase" in nabu_config:
493
+ phase_method = nabu_config["phase"].get("method", "").lower()
494
+ if phase_method in ("pag", "paganin"):
495
+ pag = True
496
+ elif phase_method in ("ctf",):
497
+ ctf = True
498
+
499
+ # treat future.
500
+ for db, future_tomo_obj in future_tomo_objs.items():
501
+ if self._cancelled:
502
+ break
503
+
504
+ future_tomo_obj.results()
505
+ if future_tomo_obj.cancelled() or future_tomo_obj.exceptions():
506
+ continue
507
+ file_prefix = SingleSliceRunner.get_file_basename_reconstruction(
508
+ scan=scan,
509
+ slice_index=slice_index,
510
+ pag=pag,
511
+ db=int(db) if db is not None else None,
512
+ ctf=ctf,
513
+ )
514
+ # retrieve url
515
+ volume_identifier = nabu_utils.get_recons_volume_identifier(
516
+ file_prefix=file_prefix,
517
+ location=nabu_config["output"]["location"],
518
+ file_format=nabu_config.get("file_format", "hdf5"),
519
+ scan=scan,
520
+ slice_index=None,
521
+ start_z=None,
522
+ end_z=None,
523
+ expects_single_slice=True,
524
+ )
525
+
526
+ assert len(volume_identifier) <= 1, "only one slice expected"
527
+ if len(volume_identifier) == 1:
528
+ db_reconstructions[db] = volume_identifier[0]
529
+ else:
530
+ _logger.warning(
531
+ f"something went wrong with reconstruction of {db} from {str(scan)}"
474
532
  )
475
- except Exception as e:
476
- _logger.error(e)
533
+
534
+ @staticmethod
535
+ def _preprocess_slice_index(slice_index):
536
+ if isinstance(slice_index, str):
537
+ if not slice_index == "middle":
538
+ raise ValueError(f"slice index {slice_index} not recognized")
539
+ else:
540
+ return slice_index
541
+ elif not len(slice_index) == 1:
542
+ raise ValueError("only manage one slice")
477
543
  else:
478
- if self._dump_process:
479
- process_idx = SADeltaBetaProcess.process_to_tomwer_processes(
480
- scan=scan,
481
- )
482
- if self.dump_roi and process_idx is not None:
483
- self.dump_rois(
484
- scan, score_rois=score_rois, process_index=process_idx
544
+ return list(slice_index.values())[0]
545
+
546
+ def _process_end(self, scan, db_res, score_rois):
547
+ assert isinstance(scan, TomwerScanBase)
548
+ state = ProcessManager().get_dataset_state(
549
+ dataset_id=scan.get_identifier(), process=self
550
+ )
551
+ if state not in (
552
+ DatasetState.CANCELLED,
553
+ DatasetState.FAILED,
554
+ DatasetState.SKIPPED,
555
+ ):
556
+ try:
557
+ extra = {
558
+ logconfig.DOC_TITLE: self._scheme_title,
559
+ logconfig.SCAN_ID: str(scan),
560
+ }
561
+ slice_index = self.inputs.sa_delta_beta_params.get("slice_index", None)
562
+
563
+ if db_res is None:
564
+ info = f"fail to compute delta/beta scores of slice {slice_index} for scan {scan}."
565
+ _logger.processFailed(info, extra=extra)
566
+ ProcessManager().notify_dataset_state(
567
+ dataset=scan,
568
+ process=self,
569
+ state=DatasetState.FAILED,
570
+ details=info,
485
571
  )
572
+ else:
573
+ info = f"delta/beta scores of slice {slice_index} for scan {scan} computed."
574
+ _logger.processSucceed(info, extra=extra)
575
+ ProcessManager().notify_dataset_state(
576
+ dataset=scan,
577
+ process=self,
578
+ state=DatasetState.WAIT_USER_VALIDATION,
579
+ details=info,
580
+ )
581
+ except Exception as e:
582
+ _logger.error(e)
583
+ else:
584
+ if self._dump_process:
585
+ process_idx = SADeltaBetaTask.process_to_tomwer_processes(
586
+ scan=scan,
587
+ )
588
+ if self.dump_roi and process_idx is not None:
589
+ self.dump_rois(
590
+ scan, score_rois=score_rois, process_index=process_idx
591
+ )
486
592
 
487
593
  @staticmethod
488
594
  def dump_rois(scan, score_rois: dict, process_index: int):
@@ -546,9 +652,9 @@ class SADeltaBetaProcess(
546
652
  configuration=scan.sa_delta_beta_params.to_dict(),
547
653
  process_index=process_index,
548
654
  overwrite=True,
549
- process=SADeltaBetaProcess,
655
+ process=SADeltaBetaTask,
550
656
  )
551
- SADeltaBetaProcess._extends_results(
657
+ SADeltaBetaTask._extends_results(
552
658
  scan=scan, entry=entry, process_index=process_index
553
659
  )
554
660
  except Exception as e:
@@ -593,3 +699,110 @@ class SADeltaBetaProcess(
593
699
  results_db["reconstructed_slice"] = h5py.ExternalLink(
594
700
  link_path, url.data_path()
595
701
  )
702
+
703
+ def cancel(self):
704
+ """
705
+ stop current processing
706
+ """
707
+ if self._current_processing is not None:
708
+ self._cancelled = True
709
+ self._current_processing.cancel()
710
+
711
+
712
+ class _PostProcessing:
713
+ """class used to run SA-delta-beta post-processing on reconstructed slices"""
714
+
715
+ def __init__(self, db_reconstructions, scan) -> None:
716
+ self._db_reconstructions = db_reconstructions
717
+ self._scan = scan
718
+ self._cancelled = False
719
+
720
+ def run(self):
721
+ datasets = self.load_datasets()
722
+
723
+ mask_disk_radius = get_disk_mask_radius(datasets)
724
+ scores = {}
725
+ rois = {}
726
+ for db, (url, data) in datasets.items():
727
+ if data is None:
728
+ score = None
729
+ else:
730
+ assert data.ndim == 2
731
+ data_roi = apply_roi(data=data, radius=mask_disk_radius, url=url)
732
+ rois[db] = data_roi
733
+
734
+ # move data_roi to [0-1] range
735
+ # preprocessing: get percentile 0 and 99 from image and
736
+ # "clean" highest and lowest pixels from it
737
+ min_p, max_p = numpy.percentile(data_roi, (1, 99))
738
+ data_roi_int = data_roi[...]
739
+ data_roi_int[data_roi_int < min_p] = min_p
740
+ data_roi_int[data_roi_int > max_p] = max_p
741
+ data_roi_int = (data_roi_int - min_p) / (max_p - min_p)
742
+
743
+ score = ComputedScore(
744
+ tv=compute_score(data=data_roi_int, method=ScoreMethod.TV),
745
+ std=compute_score(data=data_roi_int, method=ScoreMethod.STD),
746
+ )
747
+ scores[db] = (url, score)
748
+ return scores, rois
749
+
750
+ def load_datasets(self):
751
+ datasets_ = {}
752
+ for db, volume_identifier in self._db_reconstructions.items():
753
+ slice_url = None
754
+ # in case the try processing fails
755
+ try:
756
+ volume = VolumeFactory.create_tomo_object_from_identifier(
757
+ volume_identifier
758
+ )
759
+ volumes_urls = tuple(volume.browse_data_urls())
760
+ if len(volumes_urls) > 1:
761
+ _logger.warning(
762
+ f"found a volume with mode that one url ({volumes_urls})"
763
+ )
764
+ slice_url = volumes_urls[0]
765
+ data = get_data(slice_url)
766
+ except Exception as e:
767
+ _logger.error(
768
+ f"Fail to compute a score for {volume_identifier}. Reason is {e}"
769
+ )
770
+ datasets_[db] = (slice_url, None)
771
+ else:
772
+ if data.ndim == 3:
773
+ if data.shape[0] == 1:
774
+ data = data.reshape(data.shape[1], data.shape[2])
775
+ elif data.shape[2] == 1:
776
+ data = data.reshape(data.shape[0], data.shape[1])
777
+ else:
778
+ raise ValueError(f"Data is expected to be 2D. Not {data.ndim}D")
779
+ elif data.ndim == 2:
780
+ pass
781
+ else:
782
+ raise ValueError(f"Data is expected to be 2D. Not {data.ndim}D")
783
+
784
+ datasets_[db] = (slice_url, data)
785
+ return datasets_
786
+
787
+ def cancel(self):
788
+ self._cancelled = True
789
+
790
+
791
+ class SADeltaBetaProcess(SADeltaBetaTask):
792
+ def __init__(
793
+ self,
794
+ process_id=None,
795
+ varinfo=None,
796
+ inputs=None,
797
+ node_id=None,
798
+ node_attrs=None,
799
+ execinfo=None,
800
+ ):
801
+ deprecated_warning(
802
+ name="tomwer.core.process.reconstruction.sadeltabeta.sadeltabeta.SADeltaBetaProcess",
803
+ type_="class",
804
+ reason="improve readibility",
805
+ since_version="1.2",
806
+ replacement="SADeltaBetaTask",
807
+ )
808
+ super().__init__(process_id, varinfo, inputs, node_id, node_attrs, execinfo)