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
@@ -28,10 +28,13 @@ __license__ = "MIT"
|
|
28
28
|
__date__ = "31/03/2021"
|
29
29
|
|
30
30
|
|
31
|
+
import logging
|
31
32
|
from typing import Optional
|
32
33
|
from silx.gui import qt
|
33
34
|
from tomwer.core.utils.char import BETA_CHAR, DELTA_CHAR
|
34
35
|
|
36
|
+
_logger = logging.getLogger(__name__)
|
37
|
+
|
35
38
|
|
36
39
|
class ReconstructionParameters(qt.QWidget):
|
37
40
|
"""
|
@@ -114,7 +117,10 @@ class ReconstructionParameters(qt.QWidget):
|
|
114
117
|
self._setSinoNormalization,
|
115
118
|
self._setSoftwareVersion,
|
116
119
|
):
|
117
|
-
|
120
|
+
try:
|
121
|
+
func(metadata)
|
122
|
+
except Exception as e:
|
123
|
+
_logger.warning(f"Fail update when call {func}. Error is", e)
|
118
124
|
|
119
125
|
def _setMethod(self, metadata: dict):
|
120
126
|
method = (
|
@@ -140,8 +146,10 @@ class ReconstructionParameters(qt.QWidget):
|
|
140
146
|
metadata.get("processing_options", {})
|
141
147
|
.get("phase", {})
|
142
148
|
.get("distance_cm", None)
|
149
|
+
) or metadata.get("processing_options", {}).get("reconstruction", {}).get(
|
150
|
+
"sample_detector_dist", None
|
143
151
|
)
|
144
|
-
if distance_cm not in (None, ""):
|
152
|
+
if distance_cm not in (None, "", "None"):
|
145
153
|
distance_cm = float(distance_cm)
|
146
154
|
distance_cm = f"{distance_cm:.2}"
|
147
155
|
else:
|
@@ -151,12 +159,24 @@ class ReconstructionParameters(qt.QWidget):
|
|
151
159
|
def _setPixelSize(self, metadata: dict):
|
152
160
|
# voxel size can be stored as pixel size (old version) or voxel size (new version)
|
153
161
|
recons_params = metadata.get("processing_options", {}).get("reconstruction", {})
|
154
|
-
voxel_size_cm = recons_params.get("voxel_size_cm", None)
|
155
|
-
|
156
|
-
|
162
|
+
voxel_size_cm = recons_params.get("voxel_size_cm", None)
|
163
|
+
|
164
|
+
# now voxel size is expected to be a tuple of three elements
|
165
|
+
if voxel_size_cm is not None:
|
166
|
+
voxel_size_cm = voxel_size_cm[0]
|
167
|
+
# FIXME: load_ini seems to fail to remove some char like '(' or ')'... to be fixed or investigate
|
168
|
+
# simplest might be to filter those when dumping it to text file... ??? or to handle those at silx level
|
169
|
+
if isinstance(voxel_size_cm, str):
|
170
|
+
for char_to_ignore in (" ", "(", ")", "[", "]"):
|
171
|
+
voxel_size_cm = voxel_size_cm.replace(char_to_ignore, "")
|
172
|
+
else:
|
173
|
+
# backward compatibility with old volume
|
174
|
+
voxel_size_cm = recons_params.get("pixel_size_cm", None)
|
157
175
|
if voxel_size_cm is not None:
|
158
176
|
voxel_size_cm = f"{float(voxel_size_cm):.8}"
|
159
|
-
self._pixelSizeQLE.setText(
|
177
|
+
self._pixelSizeQLE.setText(
|
178
|
+
str(voxel_size_cm) if voxel_size_cm is not None else ""
|
179
|
+
)
|
160
180
|
|
161
181
|
def _setCor(self, metadata: dict):
|
162
182
|
cor = (
|
@@ -59,7 +59,13 @@ class SinogramViewer(qt.QMainWindow):
|
|
59
59
|
sigSinoLoadEnded = qt.Signal()
|
60
60
|
"""Signal emitted when a computation is ended"""
|
61
61
|
|
62
|
-
def __init__(
|
62
|
+
def __init__(
|
63
|
+
self,
|
64
|
+
parent=None,
|
65
|
+
scan=None,
|
66
|
+
opts_orientation=qt.Qt.Vertical,
|
67
|
+
backend=None,
|
68
|
+
):
|
63
69
|
qt.QMainWindow.__init__(self, parent)
|
64
70
|
self._scan = None
|
65
71
|
self._sinoInfoCache = None
|
@@ -53,14 +53,12 @@ def test_ReconstructionParameters(qtapp, phase_method): # noqa F401
|
|
53
53
|
},
|
54
54
|
},
|
55
55
|
"processing_options": {
|
56
|
-
"phase": {
|
57
|
-
"distance_cm": 0.4,
|
58
|
-
},
|
59
56
|
"reconstruction": {
|
60
|
-
"voxel_size_cm": 0.2,
|
57
|
+
"voxel_size_cm": (0.2, 0.2, 0.2),
|
61
58
|
"rotation_axis_position": 104,
|
62
59
|
"enable_halftomo": True,
|
63
60
|
"fbp_filter_type": "Hilbert",
|
61
|
+
"sample_detector_dist": 0.4,
|
64
62
|
},
|
65
63
|
"take_log": {
|
66
64
|
"log_min_clip": 1.0,
|
@@ -357,6 +357,8 @@ class VolumeViewer(qt.QMainWindow):
|
|
357
357
|
self._set_volume(data)
|
358
358
|
# set reconstruction parameters
|
359
359
|
try:
|
360
|
+
# warning: limitation expected for .vol as it gets two configuration file. The default one is vol.info and does not contains
|
361
|
+
# any of the metadata 'distance', 'pixel size'... but it is here for backward compatiblity
|
360
362
|
self._reconsWidget.setVolumeMetadata(
|
361
363
|
volume.metadata or volume.load_metadata()
|
362
364
|
)
|
tomwer/resources/__init__.py
CHANGED
@@ -24,17 +24,17 @@
|
|
24
24
|
# ###########################################################################*/
|
25
25
|
|
26
26
|
|
27
|
-
import
|
27
|
+
from __future__ import annotations
|
28
28
|
import os
|
29
29
|
import sys
|
30
|
+
import contextlib
|
31
|
+
import atexit
|
32
|
+
from typing import NamedTuple, Optional
|
33
|
+
import importlib
|
34
|
+
import functools
|
30
35
|
|
31
|
-
|
32
|
-
# When pkg_resources is not available, the resources dir defaults to the
|
33
|
-
# directory containing this module.
|
34
|
-
try:
|
36
|
+
if sys.version_info < (3, 9):
|
35
37
|
import pkg_resources
|
36
|
-
except ImportError:
|
37
|
-
pkg_resources = None
|
38
38
|
|
39
39
|
# For packaging purpose, patch this variable to use an alternative directory
|
40
40
|
# E.g., replace with _RESOURCES_DIR = '/usr/share/silx/data'
|
@@ -56,25 +56,20 @@ if getattr(sys, "frozen", False):
|
|
56
56
|
_RESOURCES_DIR = _dir
|
57
57
|
|
58
58
|
|
59
|
-
|
59
|
+
# Manage resource files life-cycle
|
60
|
+
_file_manager = contextlib.ExitStack()
|
61
|
+
atexit.register(_file_manager.close)
|
62
|
+
|
63
|
+
|
64
|
+
class _ResourceDirectory(NamedTuple):
|
60
65
|
"""Store a source of resources"""
|
61
66
|
|
62
|
-
|
63
|
-
|
64
|
-
if package_path is None:
|
65
|
-
if pkg_resources is None:
|
66
|
-
# In this case we have to compute the package path
|
67
|
-
# Else it will not be used
|
68
|
-
module = importlib.import_module(package_name)
|
69
|
-
package_path = os.path.abspath(os.path.dirname(module.__file__))
|
70
|
-
self.package_name = package_name
|
71
|
-
self.package_path = package_path
|
72
|
-
self.forced_path = forced_path
|
67
|
+
package_name: str
|
68
|
+
forced_path: Optional[str] = None
|
73
69
|
|
74
70
|
|
75
71
|
_TOMWER_DIRECTORY = _ResourceDirectory(
|
76
72
|
package_name=__name__,
|
77
|
-
package_path=os.path.abspath(os.path.dirname(__file__)),
|
78
73
|
forced_path=_RESOURCES_DIR,
|
79
74
|
)
|
80
75
|
|
@@ -100,45 +95,62 @@ def _get_package_and_resource(resource, default_directory=None):
|
|
100
95
|
else:
|
101
96
|
prefix = "tomwer"
|
102
97
|
if default_directory is not None:
|
103
|
-
resource =
|
98
|
+
resource = f"{default_directory}/{resource}"
|
104
99
|
if prefix not in _RESOURCE_DIRECTORIES:
|
105
100
|
raise ValueError("Resource '%s' uses an unregistred prefix", resource)
|
106
101
|
resource_directory = _RESOURCE_DIRECTORIES[prefix]
|
107
102
|
return resource_directory, resource
|
108
103
|
|
109
104
|
|
110
|
-
|
105
|
+
# Manage resource files life-cycle
|
106
|
+
_file_manager = contextlib.ExitStack()
|
107
|
+
atexit.register(_file_manager.close)
|
108
|
+
|
109
|
+
|
110
|
+
@functools.lru_cache(maxsize=None)
|
111
|
+
def _get_resource_filename(package: str, resource: str) -> str:
|
112
|
+
"""Returns path to requested resource in package
|
113
|
+
|
114
|
+
:param package: Name of the package in which to look for the resource
|
115
|
+
:param resource: Resource path relative to package using '/' path separator
|
116
|
+
:return: Abolute resource path in the file system
|
117
|
+
"""
|
118
|
+
if sys.version_info < (3, 9):
|
119
|
+
return pkg_resources.resource_filename(package, resource)
|
120
|
+
|
121
|
+
# Caching prevents extracting the resource twice
|
122
|
+
file_context = importlib.resources.as_file(
|
123
|
+
importlib.resources.files(package) / resource
|
124
|
+
)
|
125
|
+
path = _file_manager.enter_context(file_context)
|
126
|
+
return str(path.absolute())
|
127
|
+
|
128
|
+
|
129
|
+
def _resource_filename(resource: str, default_directory: Optional[str] = None) -> str:
|
111
130
|
"""Return filename corresponding to resource.
|
112
131
|
|
113
|
-
|
132
|
+
The existence of the resource is not checked.
|
114
133
|
|
115
|
-
|
134
|
+
The resource name can be prefixed by the name of a resource directory. For
|
116
135
|
example "silx:foo.png" identify the resource "foo.png" from the resource
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
:rtype: str
|
136
|
+
directory "silx". See also :func:`register_resource_directory`.
|
137
|
+
|
138
|
+
:param resource: Resource path relative to resource directory
|
139
|
+
using '/' path separator. It can be either a file or
|
140
|
+
a directory.
|
141
|
+
:param default_directory: If the resource is not prefixed, the resource
|
142
|
+
will be searched on this default directory of the silx resource
|
143
|
+
directory. It should only be used internally by silx.
|
144
|
+
:return: Absolute resource path in the file system
|
127
145
|
"""
|
128
146
|
resource_directory, resource_name = _get_package_and_resource(
|
129
147
|
resource, default_directory=default_directory
|
130
148
|
)
|
149
|
+
|
131
150
|
if resource_directory.forced_path is not None:
|
132
151
|
# if set, use this directory
|
133
152
|
base_dir = resource_directory.forced_path
|
134
153
|
resource_path = os.path.join(base_dir, *resource_name.split("/"))
|
135
154
|
return resource_path
|
136
|
-
|
137
|
-
|
138
|
-
base_dir = resource_directory.package_path
|
139
|
-
resource_path = os.path.join(base_dir, *resource_name.split("/"))
|
140
|
-
return resource_path
|
141
|
-
else:
|
142
|
-
# Preferred way to get resources as it supports zipfile package
|
143
|
-
package_name = resource_directory.package_name
|
144
|
-
return pkg_resources.resource_filename(package_name, resource_name)
|
155
|
+
|
156
|
+
return _get_resource_filename(resource_directory.package_name, resource_name)
|
Binary file
|
@@ -0,0 +1,75 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
3
|
+
|
4
|
+
<svg
|
5
|
+
width="48"
|
6
|
+
height="48"
|
7
|
+
viewBox="0 0 12.7 12.7"
|
8
|
+
version="1.1"
|
9
|
+
id="svg286"
|
10
|
+
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
11
|
+
sodipodi:docname="compose.svg"
|
12
|
+
inkscape:export-filename="compose.png"
|
13
|
+
inkscape:export-xdpi="96"
|
14
|
+
inkscape:export-ydpi="96"
|
15
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
16
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
17
|
+
xmlns="http://www.w3.org/2000/svg"
|
18
|
+
xmlns:svg="http://www.w3.org/2000/svg">
|
19
|
+
<sodipodi:namedview
|
20
|
+
id="namedview288"
|
21
|
+
pagecolor="#ffffff"
|
22
|
+
bordercolor="#000000"
|
23
|
+
borderopacity="0.25"
|
24
|
+
inkscape:showpageshadow="2"
|
25
|
+
inkscape:pageopacity="0.0"
|
26
|
+
inkscape:pagecheckerboard="0"
|
27
|
+
inkscape:deskcolor="#d1d1d1"
|
28
|
+
inkscape:document-units="mm"
|
29
|
+
showgrid="false"
|
30
|
+
inkscape:zoom="4.7572176"
|
31
|
+
inkscape:cx="23.858484"
|
32
|
+
inkscape:cy="53.182348"
|
33
|
+
inkscape:window-width="1920"
|
34
|
+
inkscape:window-height="1131"
|
35
|
+
inkscape:window-x="0"
|
36
|
+
inkscape:window-y="32"
|
37
|
+
inkscape:window-maximized="1"
|
38
|
+
inkscape:current-layer="g872" />
|
39
|
+
<defs
|
40
|
+
id="defs283" />
|
41
|
+
<g
|
42
|
+
inkscape:label="Layer 1"
|
43
|
+
inkscape:groupmode="layer"
|
44
|
+
id="layer1">
|
45
|
+
<g
|
46
|
+
id="g872"
|
47
|
+
transform="matrix(2.7603153,0,0,2.1174268,-0.61582227,-584.86385)">
|
48
|
+
<g
|
49
|
+
id="g877"
|
50
|
+
transform="matrix(0.69394884,-0.91617956,0.56586616,0.69394884,-154.75708,81.317197)"
|
51
|
+
inkscape:transform-center-x="6.3041843"
|
52
|
+
inkscape:transform-center-y="-5.6562159"
|
53
|
+
style="fill:none">
|
54
|
+
<rect
|
55
|
+
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.233763;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
56
|
+
id="rect825"
|
57
|
+
width="3.7308216"
|
58
|
+
height="0.62381279"
|
59
|
+
x="-4.3877668"
|
60
|
+
y="281.05283" />
|
61
|
+
<path
|
62
|
+
style="fill:none;stroke:#000000;stroke-width:0.168986;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
63
|
+
d="m -4.3877668,281.67664 c -0.2793163,0.009 -0.5577288,-0.0435 -0.8324456,-0.35142 0.2750181,-0.18258 0.5523208,-0.28005 0.8324456,-0.27239"
|
64
|
+
id="path827"
|
65
|
+
inkscape:connector-curvature="0"
|
66
|
+
sodipodi:nodetypes="ccc" />
|
67
|
+
<path
|
68
|
+
style="fill:none;stroke:#000000;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
69
|
+
d="m -1.110839,281.0557 0.00835,0.60971"
|
70
|
+
id="path848"
|
71
|
+
inkscape:connector-curvature="0" />
|
72
|
+
</g>
|
73
|
+
</g>
|
74
|
+
</g>
|
75
|
+
</svg>
|
@@ -30,7 +30,9 @@ __date__ = "28/01/2019"
|
|
30
30
|
|
31
31
|
from silx.gui import qt
|
32
32
|
|
33
|
-
from tomwer.core.process.control.scantransfer import
|
33
|
+
from tomwer.core.process.control.scantransfer import (
|
34
|
+
ScanTransferTask as FolderTransfertP,
|
35
|
+
)
|
34
36
|
from tomwer.core.scan.scanbase import TomwerScanBase
|
35
37
|
|
36
38
|
|
@@ -109,12 +109,18 @@ class _DarkFlatPatchProcessingThread(ProcessingThread, SuperviseProcess):
|
|
109
109
|
self._configuration = configuration
|
110
110
|
|
111
111
|
def run(self):
|
112
|
+
# TODO: must be replace by calling the 'DarkFlatPatch' task directly
|
112
113
|
self.sigComputationStarted.emit()
|
113
114
|
_logger.processStarted(f"{self._scan} Start dark-flat patch")
|
115
|
+
process = darkflatpatch.DarkFlatPatchTask(
|
116
|
+
inputs={
|
117
|
+
"data": self._scan,
|
118
|
+
"configuration": self._configuration,
|
119
|
+
"serialize_output_data": False,
|
120
|
+
}
|
121
|
+
)
|
114
122
|
try:
|
115
|
-
|
116
|
-
config=self._configuration, scan=self._scan
|
117
|
-
)
|
123
|
+
process.run()
|
118
124
|
except Exception as e:
|
119
125
|
info = f"Fail to patch dark-flat for {self._scan}. Reason is {e}"
|
120
126
|
_logger.processFailed(info)
|
@@ -124,36 +130,35 @@ class _DarkFlatPatchProcessingThread(ProcessingThread, SuperviseProcess):
|
|
124
130
|
state=DatasetState.FAILED,
|
125
131
|
details=info,
|
126
132
|
)
|
133
|
+
return
|
134
|
+
|
135
|
+
index = self._scan.pop_process_index()
|
136
|
+
if isinstance(self._scan, EDFTomoScan):
|
137
|
+
entry = None
|
127
138
|
else:
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
results={},
|
144
|
-
process=darkflatpatch.DarkFlatPatch,
|
145
|
-
process_index=index,
|
146
|
-
overwrite=True,
|
147
|
-
)
|
148
|
-
except Exception as e:
|
149
|
-
_logger.warning(
|
150
|
-
f"Fail to register DarkFlatPatch process. Reason is {e}"
|
151
|
-
)
|
152
|
-
info = f"Dark-flat patched for {self._scan}."
|
153
|
-
_logger.processSucceed(info)
|
154
|
-
ProcessManager().notify_dataset_state(
|
155
|
-
dataset=self._scan,
|
156
|
-
process=self,
|
157
|
-
state=DatasetState.SUCCEED,
|
158
|
-
details=info,
|
139
|
+
entry = self._scan.entry
|
140
|
+
configuration_to_dump = self._configuration
|
141
|
+
keys = list(configuration_to_dump.keys())
|
142
|
+
for key in keys:
|
143
|
+
if isinstance(configuration_to_dump[key], DataUrl):
|
144
|
+
configuration_to_dump[key] = configuration_to_dump[key].path()
|
145
|
+
try:
|
146
|
+
darkflatpatch.DarkFlatPatchTask._register_process(
|
147
|
+
process_file=self._scan.process_file,
|
148
|
+
entry=entry,
|
149
|
+
configuration=configuration_to_dump,
|
150
|
+
results={},
|
151
|
+
process=darkflatpatch.DarkFlatPatchTask,
|
152
|
+
process_index=index,
|
153
|
+
overwrite=True,
|
159
154
|
)
|
155
|
+
except Exception as e:
|
156
|
+
_logger.warning(f"Fail to register DarkFlatPatch process. Reason is {e}")
|
157
|
+
info = f"Dark-flat patched for {self._scan}."
|
158
|
+
_logger.processSucceed(info)
|
159
|
+
ProcessManager().notify_dataset_state(
|
160
|
+
dataset=self._scan,
|
161
|
+
process=self,
|
162
|
+
state=DatasetState.SUCCEED,
|
163
|
+
details=info,
|
164
|
+
)
|
@@ -32,7 +32,6 @@ import logging
|
|
32
32
|
from processview.core.manager import DatasetState, ProcessManager
|
33
33
|
from processview.core.superviseprocess import SuperviseProcess
|
34
34
|
from silx.gui import qt
|
35
|
-
from tomoscan.esrf.scan.hdf5scan import ImageKey
|
36
35
|
|
37
36
|
from tomwer.core.process.edit import imagekeyeditor
|
38
37
|
from tomwer.core.scan.scanbase import TomwerScanBase
|
@@ -107,10 +106,15 @@ class _ImageKeyEditorProcessingThread(ProcessingThread, SuperviseProcess):
|
|
107
106
|
def run(self):
|
108
107
|
self.sigComputationStarted.emit()
|
109
108
|
_logger.processStarted(f"Start image key edition of {self._scan}")
|
109
|
+
task = imagekeyeditor.ImageKeyEditorTask(
|
110
|
+
inputs={
|
111
|
+
"data": self._scan,
|
112
|
+
"serialize_output_data": False,
|
113
|
+
"configuration": self._configuration,
|
114
|
+
},
|
115
|
+
)
|
110
116
|
try:
|
111
|
-
|
112
|
-
config=self._configuration, scan=self._scan
|
113
|
-
)
|
117
|
+
task.run()
|
114
118
|
except Exception as e:
|
115
119
|
info = f"Fail to edit image keys for {self._scan}. Reason is {e}"
|
116
120
|
_logger.processFailed(info)
|
@@ -121,29 +125,6 @@ class _ImageKeyEditorProcessingThread(ProcessingThread, SuperviseProcess):
|
|
121
125
|
details=info,
|
122
126
|
)
|
123
127
|
else:
|
124
|
-
conf_to_dump = {}
|
125
|
-
if "modifications" in self._configuration:
|
126
|
-
for frame_index, new_frame_type in self._configuration[
|
127
|
-
"modifications"
|
128
|
-
].items():
|
129
|
-
conf_to_dump[str(frame_index)] = ImageKey.from_value(
|
130
|
-
new_frame_type
|
131
|
-
).value
|
132
|
-
index = self._scan.pop_process_index()
|
133
|
-
try:
|
134
|
-
imagekeyeditor.ImageKeyEditor._register_process(
|
135
|
-
process_file=self._scan.process_file,
|
136
|
-
entry=self._scan.entry,
|
137
|
-
configuration=conf_to_dump,
|
138
|
-
results={},
|
139
|
-
process=imagekeyeditor.ImageKeyEditor,
|
140
|
-
process_index=index,
|
141
|
-
overwrite=True,
|
142
|
-
)
|
143
|
-
except Exception as e:
|
144
|
-
_logger.warning(
|
145
|
-
f"Fail to register ImageKeyEditor process. Reason is {e}"
|
146
|
-
)
|
147
128
|
info = f"Image key edited for {self._scan.get_identifier()}."
|
148
129
|
_logger.processSucceed(info)
|
149
130
|
ProcessManager().notify_dataset_state(
|
@@ -28,7 +28,10 @@ __license__ = "MIT"
|
|
28
28
|
__date__ = "08/01/2020"
|
29
29
|
|
30
30
|
|
31
|
-
from
|
31
|
+
from collections import deque
|
32
|
+
from typing import Optional
|
33
|
+
from tomwer.core.tomwer_object import TomwerObject
|
34
|
+
from silx.gui.utils import blockSignals
|
32
35
|
|
33
36
|
from processview.core.manager import DatasetState, ProcessManager
|
34
37
|
from processview.core.superviseprocess import SuperviseProcess
|
@@ -42,7 +45,7 @@ class ProcessingThread(qt.QThread):
|
|
42
45
|
"""Signal emitted when a computation is started"""
|
43
46
|
|
44
47
|
|
45
|
-
class FIFO(
|
48
|
+
class FIFO(SuperviseProcess):
|
46
49
|
"""Processing Queue with a First In, First Out behavior"""
|
47
50
|
|
48
51
|
sigComputationStarted = qt.Signal(object)
|
@@ -53,7 +56,7 @@ class FIFO(Queue, SuperviseProcess):
|
|
53
56
|
|
54
57
|
def __init__(self, process_id=None):
|
55
58
|
SuperviseProcess.__init__(self, process_id=process_id)
|
56
|
-
|
59
|
+
self._deque = deque()
|
57
60
|
self._computationThread = self._create_processing_thread(process_id=process_id)
|
58
61
|
assert isinstance(self._computationThread, ProcessingThread)
|
59
62
|
self._computationThread.sigComputationStarted.connect(
|
@@ -64,6 +67,10 @@ class FIFO(Queue, SuperviseProcess):
|
|
64
67
|
"""Scan computed currently"""
|
65
68
|
self._processing = False
|
66
69
|
|
70
|
+
@property
|
71
|
+
def data_currently_computed(self) -> Optional[TomwerObject]:
|
72
|
+
return self._data_currently_computed
|
73
|
+
|
67
74
|
def add(self, data, configuration=None, callback=None):
|
68
75
|
"""
|
69
76
|
add a scan to process
|
@@ -82,7 +89,7 @@ class FIFO(Queue, SuperviseProcess):
|
|
82
89
|
except Exception:
|
83
90
|
pass
|
84
91
|
|
85
|
-
|
92
|
+
self.append((data, configuration, callback))
|
86
93
|
if self.can_process_next():
|
87
94
|
self._process_next()
|
88
95
|
|
@@ -90,11 +97,11 @@ class FIFO(Queue, SuperviseProcess):
|
|
90
97
|
raise NotImplementedError("Virtual class")
|
91
98
|
|
92
99
|
def _process_next(self):
|
93
|
-
if
|
100
|
+
if len(self) == 0:
|
94
101
|
return
|
95
102
|
|
96
103
|
self._processing = True
|
97
|
-
data, configuration, callback =
|
104
|
+
data, configuration, callback = self.pop()
|
98
105
|
self._process(data=data, configuration=configuration or {}, callback=callback)
|
99
106
|
|
100
107
|
def can_process_next(self):
|
@@ -154,8 +161,37 @@ class FIFO(Queue, SuperviseProcess):
|
|
154
161
|
future_tomo_obj=future_tomo_obj,
|
155
162
|
)
|
156
163
|
|
164
|
+
def cancel(self):
|
165
|
+
if self._computationThread.isRunning():
|
166
|
+
with blockSignals(self._computationThread):
|
167
|
+
self._computationThread.cancel()
|
168
|
+
# stop stack
|
169
|
+
self.stop()
|
170
|
+
# emit next
|
171
|
+
self.sigComputationEnded.emit(None, None)
|
172
|
+
|
157
173
|
def stop(self):
|
158
|
-
while not self.empty():
|
159
|
-
self.get()
|
160
|
-
self._computationThread.blockSignals(True)
|
161
174
|
self._computationThread.wait()
|
175
|
+
self._processing = False
|
176
|
+
self._data_currently_computed = None
|
177
|
+
|
178
|
+
# expose deque API
|
179
|
+
def append(self, value):
|
180
|
+
self._deque.append(value)
|
181
|
+
|
182
|
+
def clear(self):
|
183
|
+
self._deque.clear()
|
184
|
+
|
185
|
+
def pop(self):
|
186
|
+
return self._deque.pop()
|
187
|
+
|
188
|
+
def remove(self, value):
|
189
|
+
return self._deque.remove(value)
|
190
|
+
|
191
|
+
def __len__(self):
|
192
|
+
return len(self._deque)
|
193
|
+
|
194
|
+
def __contains__(self, value):
|
195
|
+
return value.get_identifier().to_str() in [
|
196
|
+
scan.get_identifier().to_str() for scan in self._deque
|
197
|
+
]
|
@@ -34,7 +34,7 @@ from processview.core.manager import DatasetState, ProcessManager
|
|
34
34
|
from processview.core.superviseprocess import SuperviseProcess
|
35
35
|
from silx.gui import qt
|
36
36
|
|
37
|
-
from tomwer.core.process.reconstruction.axis import
|
37
|
+
from tomwer.core.process.reconstruction.axis import AxisTask
|
38
38
|
from tomwer.core.process.reconstruction.axis.axis import NoAxisUrl
|
39
39
|
from tomwer.core.process.reconstruction.axis.mode import AxisMode
|
40
40
|
from tomwer.core.scan.hdf5scan import HDF5TomoScan
|
@@ -98,10 +98,10 @@ class AxisProcessStack(FIFO, qt.QObject):
|
|
98
98
|
entry = "entry"
|
99
99
|
try:
|
100
100
|
with data.acquire_process_file_lock():
|
101
|
-
|
101
|
+
AxisTask._register_process(
|
102
102
|
process_file=data.process_file,
|
103
103
|
entry=entry,
|
104
|
-
process=
|
104
|
+
process=AxisTask,
|
105
105
|
results={"center_of_rotation": cor if cor is not None else "-"},
|
106
106
|
configuration=self._axis_params.to_dict(),
|
107
107
|
process_index=data.pop_process_index(),
|
@@ -115,7 +115,7 @@ class AxisProcessStack(FIFO, qt.QObject):
|
|
115
115
|
|
116
116
|
elif (
|
117
117
|
not self._axis_params.use_sinogram
|
118
|
-
and mode not in
|
118
|
+
and mode not in AxisTask._CALCULATIONS_METHODS
|
119
119
|
):
|
120
120
|
_logger.warning(f"no method defined to compute {mode}")
|
121
121
|
if callback is not None:
|
@@ -188,10 +188,11 @@ class _ProcessingThread(ProcessingThread, SuperviseProcess):
|
|
188
188
|
|
189
189
|
def run(self):
|
190
190
|
self.sigComputationStarted.emit()
|
191
|
-
axis =
|
191
|
+
axis = AxisTask(
|
192
192
|
inputs={
|
193
193
|
"data": self._scan,
|
194
194
|
"axis_params": self._axis_params,
|
195
|
+
"serialize_output_data": False,
|
195
196
|
},
|
196
197
|
process_id=self.process_id,
|
197
198
|
)
|
@@ -152,6 +152,7 @@ class _ProcessingThread(ProcessingThread, SuperviseProcess):
|
|
152
152
|
inputs = self._inputs
|
153
153
|
inputs["data"] = self._data
|
154
154
|
inputs["save_dir"] = self._save_dir
|
155
|
+
inputs["serialize_output_data"] = False
|
155
156
|
process = DarkRefsCopyWithSig(
|
156
157
|
parent=self.parent(), inputs=inputs, process_id=self.process_id
|
157
158
|
)
|