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
@@ -48,10 +48,8 @@ from .anglemode import CorAngleMode
|
|
48
48
|
from .mode import AxisMode
|
49
49
|
from .projectiontype import ProjectionType
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
except ImportError:
|
54
|
-
from tomwer.third_party.nabu.preproc.phase import PaganinPhaseRetrieval
|
51
|
+
from nabu.preproc.phase import PaganinPhaseRetrieval
|
52
|
+
|
55
53
|
|
56
54
|
_logger = logging.getLogger(__name__)
|
57
55
|
|
@@ -734,10 +732,10 @@ class AxisRP:
|
|
734
732
|
:return: center of rotation or none
|
735
733
|
:rtype: Union[None, float]
|
736
734
|
"""
|
737
|
-
from .axis import
|
735
|
+
from .axis import AxisTask # avoid cyclic import
|
738
736
|
|
739
737
|
processes = Task.get_processes_frm_type(
|
740
|
-
process_file=file_path, process_type=
|
738
|
+
process_file=file_path, process_type=AxisTask, entry=entry
|
741
739
|
)
|
742
740
|
if len(processes) == 0:
|
743
741
|
_logger.warning("failed to find any information on center " "of rotation")
|
@@ -39,6 +39,8 @@ from processview.core.manager import DatasetState, ProcessManager
|
|
39
39
|
from processview.core.superviseprocess import SuperviseProcess
|
40
40
|
from silx.io.url import DataUrl
|
41
41
|
from silx.io.utils import h5py_read_dataset
|
42
|
+
from silx.utils.deprecation import deprecated_warning
|
43
|
+
|
42
44
|
from tomoscan.framereducerbase import REDUCER_TARGET, ReduceMethod
|
43
45
|
from tomoscan.io import HDF5File
|
44
46
|
|
@@ -56,8 +58,13 @@ from . import params as dkrf_reconsparams
|
|
56
58
|
logger = logging.getLogger(__name__)
|
57
59
|
|
58
60
|
|
59
|
-
class
|
60
|
-
Task,
|
61
|
+
class DarkRefsTask(
|
62
|
+
Task,
|
63
|
+
SuperviseProcess,
|
64
|
+
Queue, # TODO: fixme: this does not make much sense for a task
|
65
|
+
input_names=("data",),
|
66
|
+
output_names=("data",),
|
67
|
+
optional_input_names=("serialize_output_data",),
|
61
68
|
):
|
62
69
|
"""Compute median/mean dark and ref from originals (dark and ref files)"""
|
63
70
|
|
@@ -236,7 +243,9 @@ class DarkRefs(
|
|
236
243
|
"""
|
237
244
|
if entry is None:
|
238
245
|
with HDF5File(process_file, "r", swmr=True) as h5f:
|
239
|
-
entries =
|
246
|
+
entries = DarkRefsTask._get_process_nodes(
|
247
|
+
root_node=h5f, process=DarkRefsTask
|
248
|
+
)
|
240
249
|
if len(entries) == 0:
|
241
250
|
logger.info("unable to find a DarkRef process in %s" % process_file)
|
242
251
|
return None
|
@@ -250,8 +259,8 @@ class DarkRefs(
|
|
250
259
|
if entry not in h5f.keys():
|
251
260
|
logger.info(f"no dark found for {entry}")
|
252
261
|
return {}
|
253
|
-
dark_nodes =
|
254
|
-
root_node=h5f[entry], process=
|
262
|
+
dark_nodes = DarkRefsTask._get_process_nodes(
|
263
|
+
root_node=h5f[entry], process=DarkRefsTask
|
255
264
|
)
|
256
265
|
index_to_path = {}
|
257
266
|
for key, index in dark_nodes.items():
|
@@ -298,7 +307,9 @@ class DarkRefs(
|
|
298
307
|
"""
|
299
308
|
if entry is None:
|
300
309
|
with HDF5File(process_file, "r", swmr=True) as h5f:
|
301
|
-
entries =
|
310
|
+
entries = DarkRefsTask._get_process_nodes(
|
311
|
+
root_node=h5f, process=DarkRefsTask
|
312
|
+
)
|
302
313
|
if len(entries) == 0:
|
303
314
|
logger.info("unable to find a DarkRef process in %s" % process_file)
|
304
315
|
return None
|
@@ -312,8 +323,8 @@ class DarkRefs(
|
|
312
323
|
if entry not in h5f.keys():
|
313
324
|
logger.info(f"no flats found for {entry}")
|
314
325
|
return {}
|
315
|
-
dkref_nodes =
|
316
|
-
root_node=h5f[entry], process=
|
326
|
+
dkref_nodes = DarkRefsTask._get_process_nodes(
|
327
|
+
root_node=h5f[entry], process=DarkRefsTask
|
317
328
|
)
|
318
329
|
index_to_path = {}
|
319
330
|
for key, index in dkref_nodes.items():
|
@@ -407,7 +418,7 @@ class DarkRefs(
|
|
407
418
|
|
408
419
|
self.outputs.data = None
|
409
420
|
return
|
410
|
-
whats = (
|
421
|
+
whats = (DarkRefsTask.WHAT_REF, DarkRefsTask.WHAT_DARK)
|
411
422
|
overwrites = (
|
412
423
|
self.recons_params.overwrite_flat,
|
413
424
|
self.recons_params.overwrite_dark,
|
@@ -451,7 +462,7 @@ class DarkRefs(
|
|
451
462
|
interpretations["/".join(("darks", str(index)))] = "image"
|
452
463
|
results["darks"] = f_darks
|
453
464
|
|
454
|
-
scan.save_reduced_darks(f_darks)
|
465
|
+
scan.save_reduced_darks(f_darks, overwrite=True)
|
455
466
|
if (
|
456
467
|
self.recons_params.flat_calc_method
|
457
468
|
is not dkrf_reconsparams.ReduceMethod.NONE
|
@@ -465,7 +476,7 @@ class DarkRefs(
|
|
465
476
|
interpretations["/".join(("flats", str(index)))] = "image"
|
466
477
|
results["flats"] = f_flats
|
467
478
|
|
468
|
-
scan.save_reduced_flats(f_flats)
|
479
|
+
scan.save_reduced_flats(f_flats, overwrite=True)
|
469
480
|
|
470
481
|
if len(results) > 0:
|
471
482
|
# if some processing to be registered
|
@@ -490,7 +501,7 @@ class DarkRefs(
|
|
490
501
|
dataset=scan, state=DatasetState.SUCCEED, details=None
|
491
502
|
)
|
492
503
|
|
493
|
-
if self.
|
504
|
+
if self.get_input_value("serialize_output_data", True):
|
494
505
|
self.outputs.data = scan.to_dict()
|
495
506
|
else:
|
496
507
|
self.outputs.data = scan
|
@@ -519,7 +530,9 @@ class DarkRefs(
|
|
519
530
|
)
|
520
531
|
scan.set_reduced_darks(darks=reduced_darks, darks_infos=metadata)
|
521
532
|
try:
|
522
|
-
scan.save_reduced_darks(
|
533
|
+
scan.save_reduced_darks(
|
534
|
+
darks=reduced_darks, darks_infos=metadata, overwrite=True
|
535
|
+
)
|
523
536
|
except Exception as e:
|
524
537
|
logger.error(f"Fail to save reduced darks. Error is {e}")
|
525
538
|
elif target is REDUCER_TARGET.FLATS:
|
@@ -530,7 +543,9 @@ class DarkRefs(
|
|
530
543
|
)
|
531
544
|
scan.set_reduced_flats(flats=reduced_flats, flats_infos=metadata)
|
532
545
|
try:
|
533
|
-
scan.save_reduced_flats(
|
546
|
+
scan.save_reduced_flats(
|
547
|
+
flats=reduced_flats, flats_infos=metadata, overwrite=True
|
548
|
+
)
|
534
549
|
except Exception as e:
|
535
550
|
logger.error(f"Fail to save reduced flats. Error is {e}")
|
536
551
|
else:
|
@@ -572,10 +587,11 @@ def requires_reduced_dark_and_flat(scan: TomwerScanBase, logger_=None) -> tuple:
|
|
572
587
|
recons_params.dark_calc_method = dkrf_reconsparams.ReduceMethod.NONE
|
573
588
|
recons_params.flat_calc_method = dkrf_reconsparams.ReduceMethod.FIRST
|
574
589
|
|
575
|
-
drp =
|
590
|
+
drp = DarkRefsTask(
|
576
591
|
inputs={
|
577
592
|
"data": scan,
|
578
593
|
"dark_ref_params": recons_params,
|
594
|
+
"serialize_output_data": False,
|
579
595
|
}
|
580
596
|
)
|
581
597
|
if logger_ is not None:
|
@@ -593,10 +609,11 @@ def requires_reduced_dark_and_flat(scan: TomwerScanBase, logger_=None) -> tuple:
|
|
593
609
|
recons_params.dark_calc_method = dkrf_reconsparams.ReduceMethod.FIRST
|
594
610
|
recons_params.flat_calc_method = dkrf_reconsparams.ReduceMethod.NONE
|
595
611
|
|
596
|
-
drp =
|
612
|
+
drp = DarkRefsTask(
|
597
613
|
inputs={
|
598
614
|
"data": scan,
|
599
615
|
"dark_ref_params": recons_params,
|
616
|
+
"serialize_output_data": False,
|
600
617
|
}
|
601
618
|
)
|
602
619
|
if logger_ is not None:
|
@@ -607,3 +624,23 @@ def requires_reduced_dark_and_flat(scan: TomwerScanBase, logger_=None) -> tuple:
|
|
607
624
|
computed.append("dark")
|
608
625
|
|
609
626
|
return tuple(computed)
|
627
|
+
|
628
|
+
|
629
|
+
class DarkRefs(DarkRefsTask):
|
630
|
+
def __init__(
|
631
|
+
self,
|
632
|
+
process_id=None,
|
633
|
+
varinfo=None,
|
634
|
+
inputs=None,
|
635
|
+
node_id=None,
|
636
|
+
node_attrs=None,
|
637
|
+
execinfo=None,
|
638
|
+
):
|
639
|
+
deprecated_warning(
|
640
|
+
name="tomwer.core.process.reconstruction.darkref.darkref.DarkRefs",
|
641
|
+
type_="class",
|
642
|
+
reason="improve readibility",
|
643
|
+
since_version="1.2",
|
644
|
+
replacement="DarkRefsTask",
|
645
|
+
)
|
646
|
+
super().__init__(process_id, varinfo, inputs, node_id, node_attrs, execinfo)
|
@@ -47,14 +47,14 @@ from tomoscan.esrf.scan.utils import (
|
|
47
47
|
from tomoscan.framereducerbase import REDUCER_TARGET
|
48
48
|
from tomoscan.io import HDF5File
|
49
49
|
|
50
|
-
from tomwer.core.process.reconstruction.darkref.darkrefs import
|
50
|
+
from tomwer.core.process.reconstruction.darkref.darkrefs import DarkRefsTask
|
51
51
|
from tomwer.core.scan.scanbase import TomwerScanBase
|
52
52
|
from tomwer.core.utils.scanutils import data_identifier_to_scan
|
53
53
|
|
54
54
|
logger = logging.getLogger(__name__)
|
55
55
|
|
56
56
|
|
57
|
-
class DarkRefsCopy(
|
57
|
+
class DarkRefsCopy(DarkRefsTask):
|
58
58
|
"""
|
59
59
|
Reimplement Dark ref to deal with copy when there is no median/mean files
|
60
60
|
"""
|
@@ -166,6 +166,10 @@ class DarkRefsCopy(DarkRefs):
|
|
166
166
|
if data is None:
|
167
167
|
return
|
168
168
|
flat_url = DarkRefsCopy.get_flats_url(save_dir)
|
169
|
+
# remove group if already exists: else can end up by copying several dark / flat from different datasets
|
170
|
+
with HDF5File(flat_url.file_path(), mode="a") as h5f:
|
171
|
+
if flat_url.data_path() in h5f:
|
172
|
+
del h5f[flat_url.data_path()]
|
169
173
|
dicttoh5(
|
170
174
|
data,
|
171
175
|
h5file=flat_url.file_path(),
|
@@ -181,6 +185,10 @@ class DarkRefsCopy(DarkRefs):
|
|
181
185
|
if data is None:
|
182
186
|
return
|
183
187
|
dark_url = DarkRefsCopy.get_darks_url(save_dir)
|
188
|
+
# remove group if already exists: else can end up by copying several dark / flat from different datasets
|
189
|
+
with HDF5File(dark_url.file_path(), mode="a") as h5f:
|
190
|
+
if dark_url.data_path() in h5f:
|
191
|
+
del h5f[dark_url.data_path()]
|
184
192
|
dicttoh5(
|
185
193
|
data,
|
186
194
|
h5file=dark_url.file_path(),
|
@@ -227,6 +235,7 @@ class DarkRefsCopy(DarkRefs):
|
|
227
235
|
darks_url=self._darks_url,
|
228
236
|
save=True,
|
229
237
|
raise_error_if_url_empty=True,
|
238
|
+
overwrite=True,
|
230
239
|
)
|
231
240
|
if self.has_flat_stored():
|
232
241
|
copy_h5_dict_flats_to(
|
@@ -234,6 +243,7 @@ class DarkRefsCopy(DarkRefs):
|
|
234
243
|
flats_url=self._flats_url,
|
235
244
|
save=True,
|
236
245
|
raise_error_if_url_empty=True,
|
246
|
+
overwrite=True,
|
237
247
|
)
|
238
248
|
|
239
249
|
def clean_save_files(self):
|
@@ -1 +1 @@
|
|
1
|
-
from .tofu import
|
1
|
+
from .tofu import LaminoReconstructionTask # noqa F401
|
@@ -49,6 +49,7 @@ from tomwer.core.scan.scanbase import TomwerScanBase
|
|
49
49
|
from tomwer.core.scan.scanfactory import ScanFactory
|
50
50
|
from tomwer.core.utils import getDim1Dim2
|
51
51
|
from tomwer.core.utils.char import PSI_CHAR
|
52
|
+
from silx.utils.deprecation import deprecated_warning
|
52
53
|
|
53
54
|
logger = logging.getLogger(__name__)
|
54
55
|
|
@@ -462,7 +463,12 @@ def has_tofu():
|
|
462
463
|
return False
|
463
464
|
|
464
465
|
|
465
|
-
class
|
466
|
+
class LaminoReconstructionTask(
|
467
|
+
Task,
|
468
|
+
input_names=("data",),
|
469
|
+
optional_input_names=("serialize_output_data",),
|
470
|
+
output_names=("data",),
|
471
|
+
):
|
466
472
|
"""
|
467
473
|
Process to launch the lamino reconstruction
|
468
474
|
|
@@ -879,7 +885,7 @@ class LaminoReconstruction(Task, input_names=("data",), output_names=("data",)):
|
|
879
885
|
|
880
886
|
if res is False:
|
881
887
|
logger.error(f"Reconstruction of {_scan.path} failed")
|
882
|
-
if self.
|
888
|
+
if self.get_input_value("serialize_output_data", True):
|
883
889
|
self.outputs.data = _scan.to_dict()
|
884
890
|
else:
|
885
891
|
self.outputs.data = _scan
|
@@ -978,3 +984,17 @@ def getFlats(scan):
|
|
978
984
|
else:
|
979
985
|
logger.warning("Found more than two refHST files")
|
980
986
|
return (os.path.join(scan, refHSTFiles[0]), os.path.join(scan, refHSTFiles[-1]))
|
987
|
+
|
988
|
+
|
989
|
+
class LaminoReconstruction(LaminoReconstructionTask):
|
990
|
+
def __init__(
|
991
|
+
self, varinfo=None, inputs=None, node_id=None, node_attrs=None, execinfo=None
|
992
|
+
):
|
993
|
+
deprecated_warning(
|
994
|
+
name="tomwer.core.process.reconstruction.lamino.tofu.LaminoReconstruction",
|
995
|
+
type_="class",
|
996
|
+
reason="improve readibility",
|
997
|
+
since_version="1.2",
|
998
|
+
replacement="LaminoReconstructionTask",
|
999
|
+
)
|
1000
|
+
super().__init__(varinfo, inputs, node_id, node_attrs, execinfo)
|
@@ -37,6 +37,8 @@ import os
|
|
37
37
|
import subprocess
|
38
38
|
import uuid
|
39
39
|
from typing import Iterable, Optional, Union
|
40
|
+
import signal
|
41
|
+
import psutil
|
40
42
|
|
41
43
|
import numpy
|
42
44
|
from silx.io.url import DataUrl
|
@@ -234,6 +236,9 @@ class _NabuBaseReconstructor:
|
|
234
236
|
self._target = Target.from_value(target)
|
235
237
|
self._dry_run = dry_run
|
236
238
|
self._process_name = process_name
|
239
|
+
self._process = None
|
240
|
+
self._cancelled = False
|
241
|
+
# nabu subprocess if run locally
|
237
242
|
if isinstance(cluster_config, SlurmClusterConfiguration):
|
238
243
|
self._cluster_config = cluster_config
|
239
244
|
elif isinstance(cluster_config, dict):
|
@@ -322,6 +327,18 @@ class _NabuBaseReconstructor:
|
|
322
327
|
else:
|
323
328
|
raise ValueError(f"{self.target} is not recognized as a valid target")
|
324
329
|
|
330
|
+
@staticmethod
|
331
|
+
def _get_gpu_and_cpu_mem_fraction(config_to_dump: dict):
|
332
|
+
gpu_mem_fraction = config_to_dump.get("resources", {}).get(
|
333
|
+
"gpu_mem_fraction", config_to_dump.get("gpu_mem_fraction", 0.9)
|
334
|
+
)
|
335
|
+
assert gpu_mem_fraction <= 1
|
336
|
+
cpu_mem_fraction = config_to_dump.get("resources", {}).get(
|
337
|
+
"cpu_mem_fraction", config_to_dump.get("cpu_mem_fraction", 0.9)
|
338
|
+
)
|
339
|
+
assert cpu_mem_fraction <= 1
|
340
|
+
return gpu_mem_fraction, cpu_mem_fraction
|
341
|
+
|
325
342
|
def _run_nabu_locally(
|
326
343
|
self,
|
327
344
|
conf_file: str,
|
@@ -341,18 +358,37 @@ class _NabuBaseReconstructor:
|
|
341
358
|
"""
|
342
359
|
if not has_nabu:
|
343
360
|
raise ImportError("Fail to import nabu")
|
361
|
+
assert isinstance(config_to_dump, dict)
|
362
|
+
gpu_mem_fraction, cpu_mem_fraction = self._get_gpu_and_cpu_mem_fraction(
|
363
|
+
config_to_dump
|
364
|
+
)
|
365
|
+
|
344
366
|
command = " ".join(
|
345
|
-
(
|
367
|
+
(
|
368
|
+
"python3",
|
369
|
+
"-m",
|
370
|
+
settings.NABU_FULL_FIELD_APP_PATH,
|
371
|
+
conf_file,
|
372
|
+
"--gpu_mem_fraction",
|
373
|
+
str(gpu_mem_fraction),
|
374
|
+
"--cpu_mem_fraction",
|
375
|
+
str(cpu_mem_fraction),
|
376
|
+
)
|
346
377
|
)
|
347
378
|
_logger.info(f'call nabu from "{command}"')
|
348
|
-
|
379
|
+
|
380
|
+
self._process = subprocess.Popen(
|
349
381
|
command,
|
350
382
|
shell=True,
|
351
383
|
cwd=self.scan.path,
|
352
384
|
stdout=subprocess.PIPE,
|
353
385
|
stderr=subprocess.PIPE,
|
354
386
|
)
|
355
|
-
|
387
|
+
try:
|
388
|
+
outs, errs = self._process.communicate()
|
389
|
+
except (TimeoutError, KeyboardInterrupt):
|
390
|
+
self._process.kill()
|
391
|
+
outs, errs = self._process.communicate()
|
356
392
|
|
357
393
|
recons_urls = utils.get_recons_volume_identifier(
|
358
394
|
file_prefix=config_to_dump["output"]["file_prefix"],
|
@@ -412,13 +448,21 @@ class _NabuBaseReconstructor:
|
|
412
448
|
project_name = project_name.replace(" ", "_")
|
413
449
|
cluster_config["job_name"] = project_name
|
414
450
|
|
451
|
+
# extract gpu_mem_fraction and cpu_mem_fraction
|
452
|
+
assert isinstance(config_to_dump, dict)
|
453
|
+
gpu_mem_fraction, cpu_mem_fraction = self._get_gpu_and_cpu_mem_fraction(
|
454
|
+
config_to_dump
|
455
|
+
)
|
456
|
+
|
415
457
|
# submit job
|
416
458
|
script_name = get_slurm_script_name(prefix="nabu")
|
417
459
|
# for now force job name
|
418
460
|
cluster_config["job_name"] = f"tomwer-nabu {conf_file}"
|
419
461
|
job = SBatchScriptJob(
|
420
462
|
slurm_config=cluster_config,
|
421
|
-
script=(
|
463
|
+
script=(
|
464
|
+
f"python3 -m {settings.NABU_FULL_FIELD_APP_PATH} {conf_file} --gpu_mem_fraction {gpu_mem_fraction} --cpu_mem_fraction {cpu_mem_fraction}",
|
465
|
+
),
|
422
466
|
script_path=os.path.join(self.scan.path, "slurm_scripts", script_name),
|
423
467
|
clean_script=False,
|
424
468
|
working_directory=self.scan.working_directory,
|
@@ -445,10 +489,12 @@ class _NabuBaseReconstructor:
|
|
445
489
|
"""Return a tuple a potential callback to be launch once the future is done"""
|
446
490
|
return tuple()
|
447
491
|
|
448
|
-
def _treateOutputSliceConfig(self, config):
|
492
|
+
def _treateOutputSliceConfig(self, config) -> tuple:
|
449
493
|
"""
|
450
494
|
- add or overwrite some parameters of the dictionary
|
451
495
|
- create the output directory if does not exist
|
496
|
+
|
497
|
+
:return: (config: dict, nabu_cfg_folder: str)
|
452
498
|
"""
|
453
499
|
# handle phase
|
454
500
|
pag = False
|
@@ -482,16 +528,26 @@ class _NabuBaseReconstructor:
|
|
482
528
|
location = config["output"].get("location", None)
|
483
529
|
if location not in ("", None):
|
484
530
|
location = format_output_location(location, scan=self.scan)
|
485
|
-
|
486
|
-
if not os.path.isdir(config["output"]["location"]):
|
487
|
-
os.makedirs(location)
|
531
|
+
location_cfg_files = location
|
488
532
|
else:
|
489
533
|
# otherwise default location will be the data root level
|
490
534
|
location = self.scan.path
|
535
|
+
location_cfg_files = location
|
536
|
+
# TODO: if is a single file - append prefix
|
537
|
+
if config["output"].get("file_format") in (
|
538
|
+
NabuOutputFileFormat.EDF.value,
|
539
|
+
NabuOutputFileFormat.TIFF.value,
|
540
|
+
NabuOutputFileFormat.JP2K.value,
|
541
|
+
): # if user specify the location
|
542
|
+
location = "/".join([location, _file_name])
|
543
|
+
|
491
544
|
# add reconstruction path to the list. scan `reconstruction_paths` register all the existing path where
|
492
545
|
# reconstruction are saved in order to be able to browse them all
|
493
546
|
self.scan.add_reconstruction_path(location)
|
494
547
|
config["output"]["location"] = location
|
548
|
+
else:
|
549
|
+
# don't think this could ever happen
|
550
|
+
location_cfg_files = self.scan.path
|
495
551
|
# handle preproc
|
496
552
|
if "preproc" not in config:
|
497
553
|
config["preproc"] = {}
|
@@ -504,14 +560,14 @@ class _NabuBaseReconstructor:
|
|
504
560
|
|
505
561
|
extra_infos = self.scan.intensity_normalization.get_extra_infos()
|
506
562
|
|
507
|
-
|
508
|
-
|
563
|
+
nabu_cfg_folder = os.path.join(
|
564
|
+
location_cfg_files, settings.NABU_CFG_FILE_FOLDER
|
509
565
|
)
|
510
|
-
os.makedirs(
|
566
|
+
os.makedirs(nabu_cfg_folder, exist_ok=True)
|
511
567
|
|
512
568
|
# configuration file and nabu_tomwer_serving_hatch must be in the same folder
|
513
569
|
serving_hatch_file = os.path.join(
|
514
|
-
|
570
|
+
nabu_cfg_folder, settings.NABU_TOMWER_SERVING_HATCH
|
515
571
|
)
|
516
572
|
|
517
573
|
source = extra_infos.get("source", INormSource.NONE)
|
@@ -566,13 +622,36 @@ class _NabuBaseReconstructor:
|
|
566
622
|
)
|
567
623
|
else:
|
568
624
|
raise NotImplementedError(f"source type {source.value} is not handled")
|
569
|
-
|
570
|
-
return config
|
625
|
+
return config, nabu_cfg_folder
|
571
626
|
|
572
627
|
def _get_file_basename_reconstruction(self, pag, db, ctf):
|
573
628
|
"""return created file base name"""
|
574
629
|
raise NotImplementedError("Base class")
|
575
630
|
|
631
|
+
def cancel(self):
|
632
|
+
self._cancelled = True
|
633
|
+
if self._process:
|
634
|
+
# kill childs processes
|
635
|
+
try:
|
636
|
+
parent = psutil.Process(self._process.pid)
|
637
|
+
except psutil.NoSuchProcess:
|
638
|
+
pass
|
639
|
+
else:
|
640
|
+
# TODO: see with Pierre. But from my point of view this
|
641
|
+
# might be handled by nabu it self....
|
642
|
+
childrens = parent.children(recursive=True)
|
643
|
+
for child in childrens:
|
644
|
+
try:
|
645
|
+
child.send_signal(signal.SIGKILL)
|
646
|
+
except psutil.NoSuchProcess:
|
647
|
+
pass
|
648
|
+
else:
|
649
|
+
child.wait()
|
650
|
+
self._process.kill()
|
651
|
+
self._process.wait()
|
652
|
+
finally:
|
653
|
+
self._process = None
|
654
|
+
|
576
655
|
|
577
656
|
def dump_normalization_array_for_nabu(
|
578
657
|
scan: TomwerScanBase, output_file: str, array: Union[numpy.ndarray, float, int]
|