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.
- orangecontrib/tomwer/tutorials/append_raw_darks_and_flats_frames_to_NXtomos.ows +44 -0
- orangecontrib/tomwer/tutorials/copy_reduced_darks_and_flats_meth1.ows +55 -0
- orangecontrib/tomwer/tutorials/copy_reduced_darks_and_flats_meth2.ows +48 -0
- orangecontrib/tomwer/tutorials/default_cor_search.ows +40 -0
- orangecontrib/tomwer/tutorials/hello_world_python_script.ows +50 -0
- orangecontrib/tomwer/tutorials/simple_slice_reconstruction_on_slurm.ows +50 -0
- orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +8 -8
- orangecontrib/tomwer/widgets/__init__.py +1 -1
- orangecontrib/tomwer/widgets/cluster/FutureSupervisorOW.py +0 -1
- orangecontrib/tomwer/widgets/cluster/SlurmClusterOW.py +8 -6
- orangecontrib/tomwer/widgets/control/AdvancementOW.py +0 -1
- orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +1 -6
- orangecontrib/tomwer/widgets/control/DataListOW.py +0 -1
- orangecontrib/tomwer/widgets/control/DataListenerOW.py +4 -4
- orangecontrib/tomwer/widgets/control/DataSelectorOW.py +0 -1
- orangecontrib/tomwer/widgets/control/DataTransfertOW.py +7 -7
- orangecontrib/tomwer/widgets/control/DataValidatorOW.py +0 -1
- orangecontrib/tomwer/widgets/control/DataWatcherOW.py +0 -3
- orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +3 -2
- orangecontrib/tomwer/widgets/control/EmailOW.py +82 -0
- orangecontrib/tomwer/widgets/control/FilterOW.py +3 -3
- orangecontrib/tomwer/widgets/control/NXTomomillOW.py +1 -1
- orangecontrib/tomwer/widgets/control/NotifierOW.py +0 -1
- orangecontrib/tomwer/widgets/control/ReduceDarkFlatSelectorOW.py +93 -0
- orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +29 -5
- orangecontrib/tomwer/widgets/control/TimerOW.py +1 -2
- orangecontrib/tomwer/widgets/control/TomoObjSerieOW.py +0 -1
- orangecontrib/tomwer/widgets/control/VolumeSelector.py +0 -1
- orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +4 -10
- orangecontrib/tomwer/widgets/control/icons/email.png +0 -0
- orangecontrib/tomwer/widgets/control/icons/email.svg +58 -0
- orangecontrib/tomwer/widgets/control/icons/reduced_darkflat_selector.png +0 -0
- orangecontrib/tomwer/widgets/control/icons/reduced_darkflat_selector.svg +199 -0
- orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +0 -1
- orangecontrib/tomwer/widgets/debugtools/ObjectInspectorOW.py +0 -1
- orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +1 -2
- orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +1 -2
- orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +0 -1
- orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +0 -1
- orangecontrib/tomwer/widgets/other/PythonScriptOW.py +29 -1
- orangecontrib/tomwer/widgets/other/TomoObjsHub.py +28 -0
- orangecontrib/tomwer/widgets/other/icons/hub.png +0 -0
- orangecontrib/tomwer/widgets/other/icons/hub.svg +113 -0
- orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +18 -12
- orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +0 -2
- orangecontrib/tomwer/widgets/reconstruction/DarkRefAndCopyOW.py +21 -6
- orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +29 -7
- orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +18 -5
- orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +40 -13
- orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +37 -10
- orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +2 -3
- orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +5 -4
- orangecontrib/tomwer/widgets/stitching/StitcherOW.py +0 -1
- orangecontrib/tomwer/widgets/stitching/ZStitchingConfigOW.py +0 -1
- orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +10 -4
- orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
- orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +0 -1
- orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +0 -1
- orangecontrib/tomwer/widgets/visualization/RadioStackOW.py +7 -5
- orangecontrib/tomwer/widgets/visualization/SampleMovedOW.py +1 -1
- orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +0 -3
- orangecontrib/tomwer/widgets/visualization/SliceStackOW.py +7 -5
- orangecontrib/tomwer/widgets/visualization/VolumeViewerOW.py +4 -4
- tomwer/__main__.py +139 -5
- tomwer/app/axis.py +16 -5
- tomwer/app/canvas_launcher/config.py +1 -1
- tomwer/app/canvas_launcher/mainwindow.py +164 -6
- tomwer/app/darkref.py +10 -181
- tomwer/app/darkrefpatch.py +10 -131
- tomwer/app/diffframe.py +11 -0
- tomwer/app/imagekeyeditor.py +12 -19
- tomwer/app/intensitynormalization.py +1 -0
- tomwer/app/lamino.py +7 -2
- tomwer/app/patchrawdarkflat.py +131 -0
- tomwer/app/radiostack.py +10 -0
- tomwer/app/reducedarkflat.py +205 -0
- tomwer/app/saaxis.py +27 -8
- tomwer/app/sadeltabeta.py +29 -8
- tomwer/app/samplemoved.py +11 -0
- tomwer/app/scanviewer.py +12 -0
- tomwer/app/sinogramviewer.py +11 -0
- tomwer/app/slicestack.py +11 -0
- tomwer/app/zstitching.py +12 -0
- tomwer/core/futureobject.py +4 -2
- tomwer/core/process/conditions/filters.py +26 -4
- tomwer/core/process/control/datadiscovery.py +4 -0
- tomwer/core/process/control/datawatcher/datawatcher.py +5 -1
- tomwer/core/process/control/email.py +148 -0
- tomwer/core/process/control/nxtomoconcatenate.py +9 -2
- tomwer/core/process/control/nxtomomill.py +58 -16
- tomwer/core/process/control/scanselector.py +4 -0
- tomwer/core/process/control/scantransfer.py +52 -23
- tomwer/core/process/control/test/test_concatenate_nxtomos.py +1 -0
- tomwer/core/process/control/test/test_email.py +52 -0
- tomwer/core/process/control/test/test_h52nx_process.py +106 -0
- tomwer/core/process/control/test/test_volume_link.py +5 -4
- tomwer/core/process/control/timer.py +27 -6
- tomwer/core/process/control/tomoobjserie.py +4 -0
- tomwer/core/process/control/volumeselector.py +4 -0
- tomwer/core/process/control/volumesymlink.py +47 -8
- tomwer/core/process/edit/darkflatpatch.py +49 -8
- tomwer/core/process/edit/imagekeyeditor.py +63 -13
- tomwer/core/process/reconstruction/axis/__init__.py +1 -1
- tomwer/core/process/reconstruction/axis/axis.py +61 -41
- tomwer/core/process/reconstruction/axis/params.py +4 -6
- tomwer/core/process/reconstruction/darkref/darkrefs.py +53 -16
- tomwer/core/process/reconstruction/darkref/darkrefscopy.py +12 -2
- tomwer/core/process/reconstruction/lamino/__init__.py +1 -1
- tomwer/core/process/reconstruction/lamino/tofu.py +22 -2
- tomwer/core/process/reconstruction/nabu/nabucommon.py +93 -14
- tomwer/core/process/reconstruction/nabu/nabuscores.py +70 -33
- tomwer/core/process/reconstruction/nabu/nabuslices.py +219 -41
- tomwer/core/process/reconstruction/nabu/nabuvolume.py +240 -108
- tomwer/core/process/reconstruction/nabu/utils.py +10 -36
- tomwer/core/process/reconstruction/normalization/normalization.py +10 -3
- tomwer/core/process/reconstruction/saaxis/__init__.py +1 -0
- tomwer/core/process/reconstruction/saaxis/saaxis.py +564 -376
- tomwer/core/process/reconstruction/sadeltabeta/__init__.py +1 -0
- tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +481 -268
- tomwer/core/process/reconstruction/scores/params.py +21 -8
- tomwer/core/process/reconstruction/test/test_darkref_copy.py +2 -0
- tomwer/core/process/reconstruction/test/test_saaxis.py +21 -8
- tomwer/core/process/reconstruction/test/test_sadeltabeta.py +8 -5
- tomwer/core/process/script/python.py +7 -2
- tomwer/core/process/stitching/nabustitcher.py +10 -3
- tomwer/core/process/task.py +2 -9
- tomwer/core/process/test/test_axis.py +25 -15
- tomwer/core/process/test/test_conditions.py +6 -6
- tomwer/core/process/test/test_dark_and_flat.py +20 -15
- tomwer/core/process/test/test_data_transfer.py +8 -8
- tomwer/core/process/test/test_data_watcher.py +1 -1
- tomwer/core/process/test/test_lamino.py +6 -6
- tomwer/core/process/test/test_nabu.py +13 -8
- tomwer/core/process/test/test_normalization.py +1 -0
- tomwer/core/process/test/test_timer.py +6 -6
- tomwer/core/process/visualization/dataviewer.py +4 -0
- tomwer/core/process/visualization/diffviewer.py +4 -0
- tomwer/core/process/visualization/imagestackviewer.py +4 -0
- tomwer/core/process/visualization/radiostack.py +4 -0
- tomwer/core/process/visualization/samplemoved.py +4 -0
- tomwer/core/process/visualization/sinogramviewer.py +4 -0
- tomwer/core/process/visualization/slicestack.py +4 -0
- tomwer/core/process/visualization/volumeviewer.py +4 -0
- tomwer/core/scan/hdf5scan.py +4 -4
- tomwer/core/scan/scanbase.py +5 -1
- tomwer/core/scan/test/test_process_registration.py +9 -9
- tomwer/core/settings.py +59 -1
- tomwer/core/test/test_lamino.py +2 -1
- tomwer/core/utils/__init__.py +16 -0
- tomwer/core/utils/locker.py +0 -1
- tomwer/core/utils/resource.py +6 -11
- tomwer/core/utils/scanutils.py +2 -0
- tomwer/gui/cluster/slurm.py +91 -7
- tomwer/gui/cluster/supervisor.py +16 -11
- tomwer/gui/cluster/test/test_cluster.py +16 -1
- tomwer/gui/conditions/filter.py +3 -3
- tomwer/gui/control/datalist.py +24 -11
- tomwer/gui/control/email.py +183 -0
- tomwer/gui/control/reducedarkflatselector.py +545 -0
- tomwer/gui/control/singletomoobj.py +23 -1
- tomwer/gui/control/test/test_email.py +35 -0
- tomwer/gui/control/test/test_reducedarkflat_selector.py +280 -0
- tomwer/gui/reconstruction/axis/CompareImages.py +1 -1
- tomwer/gui/reconstruction/axis/axis.py +10 -6
- tomwer/gui/reconstruction/axis/radioaxis.py +14 -6
- tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +2 -0
- tomwer/gui/reconstruction/darkref/darkrefwidget.py +4 -4
- tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +3 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +34 -33
- tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +1 -1
- tomwer/gui/reconstruction/normalization/intensity.py +5 -5
- tomwer/gui/reconstruction/saaxis/corrangeselector.py +1 -0
- tomwer/gui/reconstruction/saaxis/saaxis.py +6 -6
- tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +6 -6
- tomwer/gui/reconstruction/scores/scoreplot.py +6 -4
- tomwer/gui/samplemoved/__init__.py +2 -2
- tomwer/gui/stackplot.py +18 -7
- tomwer/gui/stacks.py +2 -2
- tomwer/gui/stitching/stitchandbackground.py +2 -2
- tomwer/gui/stitching/stitching.py +1 -1
- tomwer/gui/stitching/stitching_raw.py +1 -1
- tomwer/gui/utils/__init__.py +1 -85
- tomwer/gui/utils/illustrations.py +1 -1
- tomwer/gui/utils/inputwidget.py +41 -36
- tomwer/gui/utils/slider.py +2 -2
- tomwer/gui/utils/utils.py +93 -0
- tomwer/gui/visualization/dataviewer.py +8 -5
- tomwer/gui/visualization/diffviewer/diffviewer.py +4 -4
- tomwer/gui/visualization/reconstructionparameters.py +26 -6
- tomwer/gui/visualization/sinogramviewer.py +7 -1
- tomwer/gui/visualization/test/test_reconstruction_parameters.py +2 -4
- tomwer/gui/visualization/volumeviewer.py +2 -0
- tomwer/resources/__init__.py +55 -43
- tomwer/resources/gui/icons/compose.png +0 -0
- tomwer/resources/gui/icons/compose.svg +75 -0
- tomwer/synctools/datatransfert.py +3 -1
- tomwer/synctools/stacks/edit/darkflatpatch.py +39 -34
- tomwer/synctools/stacks/edit/imagekeyeditor.py +8 -27
- tomwer/synctools/stacks/processingstack.py +45 -9
- tomwer/synctools/stacks/reconstruction/axis.py +6 -5
- tomwer/synctools/stacks/reconstruction/dkrefcopy.py +1 -0
- tomwer/synctools/stacks/reconstruction/lamino.py +3 -3
- tomwer/synctools/stacks/reconstruction/nabu.py +49 -140
- tomwer/synctools/stacks/reconstruction/normalization.py +1 -0
- tomwer/synctools/stacks/reconstruction/saaxis.py +19 -33
- tomwer/synctools/stacks/reconstruction/sadeltabeta.py +16 -32
- tomwer/synctools/test/test_darkRefs.py +19 -10
- tomwer/synctools/test/test_foldertransfer.py +7 -7
- tomwer/third_party/nabu/preproc/phase.py +6 -8
- tomwer/third_party/nabu/utils.py +2 -3
- tomwer/version.py +1 -1
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/METADATA +15 -54
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/RECORD +219 -192
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/WHEEL +1 -1
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/entry_points.txt +3 -3
- /tomwer-1.2.0a1-py3.9-nspkg.pth → /tomwer-1.2.0a3-py3.11-nspkg.pth +0 -0
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/LICENSE +0 -0
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/namespace_packages.txt +0 -0
- {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,
|
105
|
-
configuration =
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
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
|
320
|
-
Task,
|
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 =
|
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
|
-
|
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
|
-
|
431
|
-
|
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
|
-
|
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
|
-
|
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(
|
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.
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
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
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
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
|
-
|
476
|
-
|
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
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
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=
|
655
|
+
process=SADeltaBetaTask,
|
550
656
|
)
|
551
|
-
|
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)
|