tomwer 1.4.19__py3-none-any.whl → 1.5.2rc0__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/simple_volume_local_reconstruction.ows +11 -8
- orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +12 -9
- orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +1 -1
- orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +21 -10
- tomwer/app/axis.py +1 -1
- tomwer/app/reducedarkflat.py +2 -2
- tomwer/core/process/control/datalistener/rpcserver.py +2 -8
- tomwer/core/process/drac/binning.py +2 -2
- tomwer/core/process/drac/output.py +1 -1
- tomwer/core/process/edit/imagekeyeditor.py +4 -6
- tomwer/core/process/edit/nxtomoeditor.py +58 -20
- tomwer/core/process/output.py +6 -5
- tomwer/core/process/reconstruction/axis/anglemode.py +2 -2
- tomwer/core/process/reconstruction/axis/axis.py +1 -0
- tomwer/core/process/reconstruction/axis/mode.py +2 -2
- tomwer/core/process/reconstruction/axis/params.py +4 -4
- tomwer/core/process/reconstruction/axis/projectiontype.py +1 -1
- tomwer/core/process/reconstruction/axis/side.py +1 -1
- tomwer/core/process/reconstruction/darkref/darkrefs.py +2 -2
- tomwer/core/process/reconstruction/darkref/darkrefscopy.py +1 -1
- tomwer/core/process/reconstruction/darkref/params.py +2 -3
- tomwer/core/process/reconstruction/nabu/castvolume.py +4 -1
- tomwer/core/process/reconstruction/nabu/helical.py +3 -1
- tomwer/core/process/reconstruction/nabu/nabucommon.py +2 -2
- tomwer/core/process/reconstruction/nabu/nabuscores.py +1 -1
- tomwer/core/process/reconstruction/nabu/nabuslices.py +4 -4
- tomwer/core/process/reconstruction/nabu/plane.py +2 -2
- tomwer/core/process/reconstruction/nabu/target.py +1 -1
- tomwer/core/process/reconstruction/nabu/test/test_castvolume.py +2 -0
- tomwer/core/process/reconstruction/nabu/utils.py +15 -14
- tomwer/core/process/reconstruction/normalization/normalization.py +1 -1
- tomwer/core/process/reconstruction/normalization/params.py +4 -4
- tomwer/core/process/reconstruction/output.py +2 -2
- tomwer/core/process/reconstruction/saaxis/params.py +3 -3
- tomwer/core/process/reconstruction/saaxis/saaxis.py +1 -1
- tomwer/core/process/reconstruction/scores/params.py +2 -2
- tomwer/core/process/reconstruction/scores/scores.py +3 -3
- tomwer/core/process/reconstruction/tests/test_axis.py +1 -1
- tomwer/core/process/stitching/metadataholder.py +5 -5
- tomwer/core/process/stitching/nabustitcher.py +1 -4
- tomwer/core/process/tests/test_normalization.py +2 -1
- tomwer/core/scan/edfscan.py +3 -3
- tomwer/core/scan/nxtomoscan.py +3 -3
- tomwer/core/scan/scanbase.py +3 -3
- tomwer/core/scan/scantype.py +1 -1
- tomwer/core/settings.py +1 -1
- tomwer/core/tomwer_object.py +1 -1
- tomwer/core/utils/nxtomoutils.py +2 -2
- tomwer/core/utils/spec.py +6 -3
- tomwer/gui/cluster/slurm.py +3 -3
- tomwer/gui/configuration/level.py +1 -1
- tomwer/gui/control/actions.py +1 -1
- tomwer/gui/control/datadiscovery.py +1 -1
- tomwer/gui/control/datalist.py +1 -1
- tomwer/gui/control/reducedarkflatselector.py +4 -4
- tomwer/gui/control/series/seriescreator.py +5 -5
- tomwer/gui/control/tomoobjdisplaymode.py +1 -1
- tomwer/gui/dataportal/gallery.py +6 -6
- tomwer/gui/edit/imagekeyeditor.py +7 -9
- tomwer/gui/edit/nxtomoeditor.py +420 -112
- tomwer/gui/edit/tests/test_nx_editor.py +155 -83
- tomwer/gui/reconstruction/axis/CalculationWidget.py +1 -1
- tomwer/gui/reconstruction/axis/EstimatedCORWidget.py +12 -8
- tomwer/gui/reconstruction/axis/EstimatedCorComboBox.py +2 -2
- tomwer/gui/reconstruction/axis/InputWidget.py +3 -3
- tomwer/gui/reconstruction/darkref/darkrefwidget.py +2 -2
- tomwer/gui/reconstruction/nabu/castvolume.py +16 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/base.py +2 -4
- tomwer/gui/reconstruction/nabu/nabuconfig/ctf.py +6 -6
- tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +1 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +5 -5
- tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +2 -4
- tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +78 -52
- tomwer/gui/reconstruction/nabu/nabuflow.py +3 -13
- tomwer/gui/reconstruction/nabu/slices.py +11 -11
- tomwer/gui/reconstruction/nabu/test/test_cast_volume.py +19 -0
- tomwer/gui/reconstruction/nabu/volume.py +1 -1
- tomwer/gui/reconstruction/normalization/intensity.py +8 -12
- tomwer/gui/reconstruction/saaxis/corrangeselector.py +2 -2
- tomwer/gui/reconstruction/saaxis/dimensionwidget.py +71 -67
- tomwer/gui/reconstruction/sacommon.py +1 -1
- tomwer/gui/reconstruction/scores/scoreplot.py +18 -10
- tomwer/gui/reconstruction/tests/test_saaxis.py +18 -16
- tomwer/gui/stitching/SingleAxisStitchingWidget.py +8 -8
- tomwer/gui/stitching/StitchingOptionsWidget.py +1 -1
- tomwer/gui/stitching/alignment.py +8 -8
- tomwer/gui/stitching/config/axisparams.py +2 -2
- tomwer/gui/stitching/config/output.py +1 -1
- tomwer/gui/stitching/config/positionoveraxis.py +1 -1
- tomwer/gui/stitching/config/stitchingstrategies.py +4 -6
- tomwer/gui/stitching/config/tomoobjdetails.py +21 -13
- tomwer/gui/stitching/normalization.py +6 -6
- tomwer/gui/stitching/tests/test_ZStitchingWindow.py +8 -1
- tomwer/gui/stitching/tests/test_preview.py +10 -7
- tomwer/gui/stitching/tests/utils.py +27 -18
- tomwer/gui/stitching/z_stitching/fineestimation.py +7 -9
- tomwer/gui/stitching/z_stitching/tests/test_raw_estimation.py +18 -7
- tomwer/gui/stitching/z_stitching/tests/test_stitching_window.py +7 -2
- tomwer/gui/utils/buttons.py +53 -35
- tomwer/gui/utils/flow.py +2 -2
- tomwer/gui/utils/loadingmode.py +1 -1
- tomwer/gui/utils/unitsystem.py +44 -33
- tomwer/gui/utils/vignettes.py +1 -1
- tomwer/gui/visualization/dataviewer.py +7 -7
- tomwer/gui/visualization/diffviewer/diffviewer.py +4 -4
- tomwer/gui/visualization/diffviewer/shiftwidget.py +4 -6
- tomwer/gui/visualization/reconstructionparameters.py +35 -23
- tomwer/gui/visualization/scanoverview.py +28 -11
- tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +25 -13
- tomwer/gui/visualization/test/test_reconstruction_parameters.py +2 -2
- tomwer/model/dataset.py +0 -0
- tomwer/synctools/utils/scanstages.py +3 -3
- tomwer/tasks/reconstruction/cleardarkflat.py +42 -0
- tomwer/tests/app/test_stitching.py +1 -1
- tomwer/tests/orangecontrib/tomwer/widgets/edit/tests/test_nxtomo_editor.py +32 -20
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_nabu_widget.py +1 -1
- tomwer/version.py +3 -3
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/METADATA +8 -8
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/RECORD +123 -121
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/WHEEL +1 -1
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/entry_points.txt +0 -0
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/licenses/LICENSE +0 -0
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/top_level.txt +0 -0
tomwer/gui/utils/unitsystem.py
CHANGED
@@ -9,14 +9,14 @@ from __future__ import annotations
|
|
9
9
|
|
10
10
|
|
11
11
|
import logging
|
12
|
+
import pint
|
12
13
|
|
13
14
|
from silx.gui import qt
|
14
|
-
from pyunitsystem.metricsystem import MetricSystem
|
15
|
-
|
16
|
-
from tomwer.core.utils.char import MU_CHAR
|
17
15
|
|
18
16
|
_logger = logging.getLogger(__name__)
|
19
17
|
|
18
|
+
_ureg = pint.get_application_registry()
|
19
|
+
|
20
20
|
|
21
21
|
class PixelEntry(qt.QWidget):
|
22
22
|
valueChanged = qt.Signal()
|
@@ -69,6 +69,17 @@ class MetricEntry(qt.QWidget):
|
|
69
69
|
editingFinished = qt.Signal()
|
70
70
|
"""emit when editing is finished"""
|
71
71
|
|
72
|
+
valueChanged = qt.Signal()
|
73
|
+
"""emit when the metric value change"""
|
74
|
+
|
75
|
+
_ExposedUnits: set[_ureg.Unit] = {
|
76
|
+
_ureg.nanometer,
|
77
|
+
_ureg.micrometer,
|
78
|
+
_ureg.mm,
|
79
|
+
_ureg.cm,
|
80
|
+
_ureg.m,
|
81
|
+
}
|
82
|
+
|
72
83
|
class DoubleValidator(qt.QDoubleValidator):
|
73
84
|
def __init__(self, *args, **kwargs):
|
74
85
|
super().__init__(*args, **kwargs)
|
@@ -80,22 +91,15 @@ class MetricEntry(qt.QWidget):
|
|
80
91
|
else:
|
81
92
|
return super().validate(a0, a1)
|
82
93
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
"mm": MetricSystem.MILLIMETER.value,
|
87
|
-
"cm": MetricSystem.CENTIMETER.value,
|
88
|
-
"m": MetricSystem.METER.value,
|
89
|
-
}
|
90
|
-
|
91
|
-
valueChanged = qt.Signal()
|
92
|
-
"""emit when the metric value change"""
|
93
|
-
|
94
|
-
def __init__(self, name, value=0.0, default_unit="m", parent=None):
|
94
|
+
def __init__(
|
95
|
+
self, name, value=0.0, default_unit: pint.Unit = _ureg.meter, parent=None
|
96
|
+
):
|
95
97
|
qt.QWidget.__init__(self, parent)
|
96
|
-
|
97
|
-
|
98
|
-
|
98
|
+
if default_unit not in self._ExposedUnits:
|
99
|
+
raise ValueError(
|
100
|
+
f"Unable to use {default_unit} as default unit. Must be in {self._ExposedUnits}"
|
101
|
+
)
|
102
|
+
self._base_unit: pint.Unit = default_unit
|
99
103
|
|
100
104
|
self.setLayout(qt.QHBoxLayout())
|
101
105
|
self._label = qt.QLabel(name, parent=self)
|
@@ -105,11 +109,9 @@ class MetricEntry(qt.QWidget):
|
|
105
109
|
self.layout().addWidget(self._qlePixelSize)
|
106
110
|
|
107
111
|
self._qcbUnit = qt.QComboBox(parent=self)
|
108
|
-
self.
|
109
|
-
|
110
|
-
|
111
|
-
self._qcbUnit.addItem("cm")
|
112
|
-
self._qcbUnit.addItem("m")
|
112
|
+
for unit in self._ExposedUnits:
|
113
|
+
self._qcbUnit.addItem(f"{unit:~}")
|
114
|
+
|
113
115
|
self.layout().addWidget(self._qcbUnit)
|
114
116
|
self._resetBaseUnit()
|
115
117
|
|
@@ -128,10 +130,9 @@ class MetricEntry(qt.QWidget):
|
|
128
130
|
self._label.setText(text)
|
129
131
|
|
130
132
|
def getCurrentUnit(self):
|
131
|
-
|
132
|
-
return self._CONVERSION[self._qcbUnit.currentText()]
|
133
|
+
return _ureg.Unit(self._qcbUnit.currentText())
|
133
134
|
|
134
|
-
def setValue(self, value_m, displayed_unit:
|
135
|
+
def setValue(self, value_m, displayed_unit: pint.Unit = _ureg.meter):
|
135
136
|
"""
|
136
137
|
|
137
138
|
:param value: pixel size in international metric system (meter)
|
@@ -155,16 +156,20 @@ class MetricEntry(qt.QWidget):
|
|
155
156
|
self._qlePixelSize.setText(txt)
|
156
157
|
self._resetBaseUnit(displayed_unit=displayed_unit)
|
157
158
|
|
158
|
-
def _resetBaseUnit(self, displayed_unit=None):
|
159
|
+
def _resetBaseUnit(self, displayed_unit: pint.Unit | None = None):
|
159
160
|
"""Simple reset of the combobox according to the base_unit"""
|
161
|
+
if displayed_unit is not None and not isinstance(displayed_unit, pint.Unit):
|
162
|
+
raise TypeError(
|
163
|
+
f"'displayed_unit' should be a {pint.Unit}. Got {type(displayed_unit)}"
|
164
|
+
)
|
160
165
|
displayed_unit = displayed_unit or self._base_unit
|
161
|
-
index = self._qcbUnit.findText(displayed_unit)
|
162
|
-
if index
|
166
|
+
index = self._qcbUnit.findText(f"{displayed_unit:~}")
|
167
|
+
if index < 0:
|
163
168
|
raise ValueError("unrecognized base unit")
|
164
169
|
else:
|
165
170
|
self._qcbUnit.setCurrentIndex(index)
|
166
171
|
|
167
|
-
def getValue(self) ->
|
172
|
+
def getValue(self) -> pint.Quantity | None:
|
168
173
|
"""
|
169
174
|
|
170
175
|
:return: the value in meter
|
@@ -177,7 +182,13 @@ class MetricEntry(qt.QWidget):
|
|
177
182
|
def setValidator(self, validator):
|
178
183
|
self._qlePixelSize.setValidator(validator)
|
179
184
|
|
180
|
-
def setUnit(self, unit):
|
181
|
-
|
185
|
+
def setUnit(self, unit: pint.Unit):
|
186
|
+
assert isinstance(
|
187
|
+
unit, pint.Unit
|
188
|
+
), f"unit is expected to be a pint.Unit. Got {type(unit)}"
|
189
|
+
unit = f"{unit:~}"
|
182
190
|
idx = self._qcbUnit.findText(unit)
|
183
|
-
|
191
|
+
if idx >= 0:
|
192
|
+
self._qcbUnit.setCurrentIndex(idx)
|
193
|
+
else:
|
194
|
+
_logger.error(f"Unhandled unit ({unit})")
|
tomwer/gui/utils/vignettes.py
CHANGED
@@ -302,7 +302,7 @@ class VignettesWidget(qt.QWidget):
|
|
302
302
|
f"score is expected to be a dict with values as (v1: numpy.ndarray, v2: ComputedScore). v2 type Found: {type(score_cls)}"
|
303
303
|
)
|
304
304
|
scores_values.append(score_cls.get(score_method))
|
305
|
-
self.__score_method = ScoreMethod
|
305
|
+
self.__score_method = ScoreMethod(score_method)
|
306
306
|
highest_score_indices = numpy.nanargmax(scores_values)
|
307
307
|
self._vignettesGroup = qt.QButtonGroup(self)
|
308
308
|
self._vignettesGroup.setExclusive(True)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import weakref
|
2
2
|
|
3
3
|
from silx.gui import qt
|
4
|
-
from
|
4
|
+
from enum import Enum as _Enum
|
5
5
|
|
6
6
|
from tomwer.core.scan.scanbase import TomwerScanBase
|
7
7
|
from tomwer.core.volume.volumebase import TomwerVolumeBase
|
@@ -318,26 +318,26 @@ class DisplayControl(qt.QWidget):
|
|
318
318
|
|
319
319
|
:return: selected mode: display slices or radios
|
320
320
|
"""
|
321
|
-
return _DisplayMode
|
321
|
+
return _DisplayMode(self._displayMode.currentText())
|
322
322
|
|
323
323
|
def setDisplayMode(self, mode):
|
324
|
-
mode = _DisplayMode
|
324
|
+
mode = _DisplayMode(mode)
|
325
325
|
idx = self._displayMode.findText(mode.value)
|
326
326
|
self._displayMode.setCurrentIndex(idx)
|
327
327
|
|
328
328
|
def getRadioOption(self) -> _RadioMode:
|
329
|
-
return _RadioMode
|
329
|
+
return _RadioMode(self._radioMode.currentText())
|
330
330
|
|
331
331
|
def setRadioOption(self, opt):
|
332
|
-
opt = _RadioMode
|
332
|
+
opt = _RadioMode(opt)
|
333
333
|
idx = self._radioMode.findText(opt.value)
|
334
334
|
self._radioMode.setCurrentIndex(idx)
|
335
335
|
|
336
336
|
def getSliceOption(self) -> _SliceMode:
|
337
|
-
return _SliceMode
|
337
|
+
return _SliceMode(self._sliceMode.currentText())
|
338
338
|
|
339
339
|
def setSliceOption(self, opt):
|
340
|
-
opt = _SliceMode
|
340
|
+
opt = _SliceMode(opt)
|
341
341
|
idx = self._sliceMode.findText(opt.value)
|
342
342
|
self._sliceMode.setCurrentIndex(idx)
|
343
343
|
|
@@ -7,13 +7,13 @@ from __future__ import annotations
|
|
7
7
|
import functools
|
8
8
|
import logging
|
9
9
|
import os
|
10
|
+
from enum import Enum
|
10
11
|
|
11
12
|
import numpy
|
12
13
|
from processview.core.dataset import DatasetIdentifier
|
13
14
|
from silx.gui import icons as silx_icons
|
14
15
|
from silx.gui import qt
|
15
16
|
from silx.io.url import DataUrl
|
16
|
-
from silx.utils.enum import Enum as _Enum
|
17
17
|
|
18
18
|
from tomwer.core.scan.nxtomoscan import NXtomoScan
|
19
19
|
from tomwer.core.scan.scanbase import TomwerScanBase
|
@@ -55,7 +55,7 @@ class _FrameSelector(qt.QWidget):
|
|
55
55
|
sigSelectedUrlChanged = qt.Signal()
|
56
56
|
"""signal emitted when the selected url changed"""
|
57
57
|
|
58
|
-
class FrameType(
|
58
|
+
class FrameType(Enum):
|
59
59
|
DARKS = "darks"
|
60
60
|
FLATS = "flats"
|
61
61
|
PROJ = "projections"
|
@@ -110,10 +110,10 @@ class _FrameSelector(qt.QWidget):
|
|
110
110
|
return None
|
111
111
|
|
112
112
|
def getTypeSelected(self):
|
113
|
-
return self.FrameType
|
113
|
+
return self.FrameType(self._frameTypeCB.currentText())
|
114
114
|
|
115
115
|
def _typeChanged(self, *args, **kwargs):
|
116
|
-
type_selected = self.FrameType
|
116
|
+
type_selected = self.FrameType(self.getTypeSelected())
|
117
117
|
self._proj_normalized.setVisible(
|
118
118
|
type_selected in (self.FrameType.PROJ, self.FrameType.ALIGN_PROJ)
|
119
119
|
)
|
@@ -5,11 +5,11 @@ contains gui for diffviewer shift
|
|
5
5
|
"""
|
6
6
|
from __future__ import annotations
|
7
7
|
|
8
|
+
from enum import Enum
|
8
9
|
|
9
10
|
import sys
|
10
11
|
|
11
12
|
from silx.gui import qt
|
12
|
-
from silx.utils.enum import Enum as _Enum
|
13
13
|
|
14
14
|
from tomwer.utils import docstring
|
15
15
|
|
@@ -54,7 +54,7 @@ class TwoFramesShiftTab(qt.QTabWidget, _FrameShiftsBase):
|
|
54
54
|
lrflip is a boolean notifying if we should flip image or not before applying the shift
|
55
55
|
"""
|
56
56
|
|
57
|
-
class ShiftMode(
|
57
|
+
class ShiftMode(Enum):
|
58
58
|
RELATIVE = "relative shift"
|
59
59
|
ABSOLUTE = "absolute shift"
|
60
60
|
|
@@ -206,7 +206,7 @@ class Relative2FramesShift(qt.QWidget, _FrameShiftsBase):
|
|
206
206
|
self._controlWidget.setFocus(qt.Qt.OtherFocusReason)
|
207
207
|
|
208
208
|
def move(self, direction: str):
|
209
|
-
direction = _ControlArrowWidget.Direction
|
209
|
+
direction = _ControlArrowWidget.Direction(direction)
|
210
210
|
shift = self._shiftStepSize.value()
|
211
211
|
if direction is _ControlArrowWidget.Direction.RIGHT:
|
212
212
|
self._xShiftQLE.setValue(self._xShiftQLE.value() + shift)
|
@@ -290,14 +290,12 @@ class _ControlArrowWidget(qt.QWidget):
|
|
290
290
|
sigMoved = qt.Signal(str)
|
291
291
|
"""signal emit when one direction is activated. Will contain the direction in which we want to move"""
|
292
292
|
|
293
|
-
class Direction(
|
293
|
+
class Direction(Enum):
|
294
294
|
LEFT = "left"
|
295
295
|
RIGHT = "right"
|
296
296
|
UP = "up"
|
297
297
|
DOWN = "down"
|
298
298
|
|
299
|
-
VALID_DIRECTIONS = Direction.members()
|
300
|
-
|
301
299
|
ARROW_BUTTON_SIZE = 30
|
302
300
|
|
303
301
|
QKEY_TO_DIR = {
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import numpy
|
3
4
|
import logging
|
4
5
|
from silx.gui import qt
|
5
6
|
from tomwer.core.utils.char import BETA_CHAR, DELTA_CHAR
|
@@ -28,14 +29,16 @@ class ReconstructionParameters(qt.QWidget):
|
|
28
29
|
self._deltaBetaQLE = qt.QLineEdit("", self)
|
29
30
|
self._deltaBetaQLE.setReadOnly(True)
|
30
31
|
self.layout().addRow(self._deltaBetaLabel, self._deltaBetaQLE)
|
31
|
-
# distance
|
32
|
-
self.
|
33
|
-
self.
|
34
|
-
self.layout().addRow(
|
32
|
+
# sample_detector distance
|
33
|
+
self._sampleDetectorDistanceQLE = qt.QLineEdit("", self)
|
34
|
+
self._sampleDetectorDistanceQLE.setReadOnly(True)
|
35
|
+
self.layout().addRow(
|
36
|
+
"sample-detector distance (cm)", self._sampleDetectorDistanceQLE
|
37
|
+
)
|
35
38
|
# pixel size
|
36
|
-
self.
|
37
|
-
self.
|
38
|
-
self.layout().addRow("
|
39
|
+
self._voxelSizeQLE = qt.QLineEdit("", self)
|
40
|
+
self._voxelSizeQLE.setReadOnly(True)
|
41
|
+
self.layout().addRow("voxel size (cm)", self._voxelSizeQLE)
|
39
42
|
# cor
|
40
43
|
self._corQLE = qt.QLineEdit("", self)
|
41
44
|
self._corQLE.setReadOnly(True)
|
@@ -89,7 +92,7 @@ class ReconstructionParameters(qt.QWidget):
|
|
89
92
|
self._setPhaseMethod,
|
90
93
|
self._setDeltaBeta,
|
91
94
|
self._setDistance,
|
92
|
-
self.
|
95
|
+
self._setVoxelSize,
|
93
96
|
self._setCor,
|
94
97
|
self._setPaddingType,
|
95
98
|
self._setHalfTomo,
|
@@ -136,29 +139,38 @@ class ReconstructionParameters(qt.QWidget):
|
|
136
139
|
distance_cm = f"{distance_cm:.2}"
|
137
140
|
else:
|
138
141
|
distance_cm = ""
|
139
|
-
self.
|
142
|
+
self._sampleDetectorDistanceQLE.setText(distance_cm)
|
140
143
|
|
141
|
-
def
|
144
|
+
def _setVoxelSize(self, metadata: dict):
|
142
145
|
# voxel size can be stored as pixel size (old version) or voxel size (new version)
|
143
146
|
recons_params = metadata.get("processing_options", {}).get("reconstruction", {})
|
144
|
-
voxel_size_cm = recons_params.get("voxel_size_cm", None)
|
147
|
+
voxel_size_cm = recons_params.get("voxel_size_cm", [None] * 3)
|
148
|
+
# back compatibility when voxel was a scalar ( ~ nabu 2023 ?)
|
149
|
+
if numpy.isscalar(voxel_size_cm):
|
150
|
+
voxel_size_cm = [voxel_size_cm] * 3
|
145
151
|
|
146
152
|
# now voxel size is expected to be a tuple of three elements
|
147
153
|
if voxel_size_cm is not None:
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
+
|
155
|
+
def clean_voxel_value(value):
|
156
|
+
if isinstance(value, str):
|
157
|
+
for char_to_ignore in (" ", "(", ")", "[", "]"):
|
158
|
+
value = value.replace(char_to_ignore, "")
|
159
|
+
return value
|
160
|
+
|
161
|
+
voxel_size_cm = [clean_voxel_value(value) for value in voxel_size_cm]
|
162
|
+
|
154
163
|
else:
|
155
164
|
# backward compatibility with old volume
|
156
|
-
voxel_size_cm = recons_params.get("pixel_size_cm", None)
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
165
|
+
voxel_size_cm = recons_params.get("pixel_size_cm", [None] * 3)
|
166
|
+
|
167
|
+
voxel_size_cm = filter(None, voxel_size_cm)
|
168
|
+
|
169
|
+
def cast_voxel_value(value: float | None):
|
170
|
+
return f"{float(value):.8}"
|
171
|
+
|
172
|
+
voxel_size_cm = [cast_voxel_value(value) for value in voxel_size_cm]
|
173
|
+
self._voxelSizeQLE.setText("x".join(voxel_size_cm))
|
162
174
|
|
163
175
|
def _setCor(self, metadata: dict):
|
164
176
|
cor = (
|
@@ -47,10 +47,10 @@ class ScanOverviewWidget(qt.QWidget):
|
|
47
47
|
self._estimatedCOR = qt.QTreeWidgetItem(self._frames)
|
48
48
|
self._estimatedCOR.setText(0, "estimated cor")
|
49
49
|
|
50
|
-
self.
|
51
|
-
self.
|
52
|
-
self.
|
53
|
-
self.
|
50
|
+
self._detector_x_pixel_size = qt.QTreeWidgetItem(self._instrument)
|
51
|
+
self._detector_x_pixel_size.setText(0, "x pixel size")
|
52
|
+
self._detector_y_pixel_size = qt.QTreeWidgetItem(self._instrument)
|
53
|
+
self._detector_y_pixel_size.setText(0, "y pixel size")
|
54
54
|
|
55
55
|
# 2: define sample
|
56
56
|
self._sample = qt.QTreeWidgetItem(self._tree)
|
@@ -58,6 +58,11 @@ class ScanOverviewWidget(qt.QWidget):
|
|
58
58
|
self._sample_name = qt.QTreeWidgetItem(self._sample)
|
59
59
|
self._sample_name.setText(0, "name")
|
60
60
|
|
61
|
+
self._sample_x_pixel_size = qt.QTreeWidgetItem(self._sample)
|
62
|
+
self._sample_x_pixel_size.setText(0, "x pixel size")
|
63
|
+
self._sample_y_pixel_size = qt.QTreeWidgetItem(self._sample)
|
64
|
+
self._sample_y_pixel_size.setText(0, "y pixel size")
|
65
|
+
|
61
66
|
# 3: other hight level items
|
62
67
|
self._startTime = qt.QTreeWidgetItem(self._tree)
|
63
68
|
self._startTime.setText(0, "start_time")
|
@@ -96,6 +101,7 @@ class ScanOverviewWidget(qt.QWidget):
|
|
96
101
|
"times": self._updateTimes,
|
97
102
|
"names": self._updateNames,
|
98
103
|
"scan-range": self._updateScanRange,
|
104
|
+
"sample": self._updateSample,
|
99
105
|
}
|
100
106
|
for part_name, fct in parts.items():
|
101
107
|
try:
|
@@ -107,7 +113,7 @@ class ScanOverviewWidget(qt.QWidget):
|
|
107
113
|
def _updateInstrument(self, scan: TomwerScanBase):
|
108
114
|
self._updateFrames(scan=scan)
|
109
115
|
self._updateEnergy(scan=scan)
|
110
|
-
self.
|
116
|
+
self._updateDetectorPixelSize(scan=scan)
|
111
117
|
|
112
118
|
def _setColoredTxt(
|
113
119
|
self, item, text, column=1, hightlight_red=False, hightlight_orange=False
|
@@ -125,7 +131,18 @@ class ScanOverviewWidget(qt.QWidget):
|
|
125
131
|
item.setBackground(0, qt.QBrush(bkg_color))
|
126
132
|
|
127
133
|
def _updateSample(self, scan: TomwerScanBase):
|
128
|
-
|
134
|
+
x_pixel_size = scan.sample_x_pixel_size
|
135
|
+
y_pixel_size = scan.sample_y_pixel_size
|
136
|
+
self._setColoredTxt(
|
137
|
+
item=self._sample_x_pixel_size,
|
138
|
+
text=f"{x_pixel_size} (m)",
|
139
|
+
hightlight_red=x_pixel_size in (None, 0.0, 1.0),
|
140
|
+
)
|
141
|
+
self._setColoredTxt(
|
142
|
+
item=self._sample_y_pixel_size,
|
143
|
+
text=f"{y_pixel_size} (m)",
|
144
|
+
hightlight_red=y_pixel_size in (None, 0.0, 1.0),
|
145
|
+
)
|
129
146
|
|
130
147
|
def _updateTimes(self, scan: TomwerScanBase):
|
131
148
|
self._startTime.setText(1, str(scan.start_time))
|
@@ -213,20 +230,20 @@ class ScanOverviewWidget(qt.QWidget):
|
|
213
230
|
text=str(scan_range),
|
214
231
|
)
|
215
232
|
|
216
|
-
def
|
233
|
+
def _updateDetectorPixelSize(self, scan: TomwerScanBase):
|
217
234
|
assert isinstance(scan, TomwerScanBase)
|
218
235
|
if isinstance(scan, EDFTomoScan):
|
219
236
|
x_pixel_size = y_pixel_size = scan.pixel_size
|
220
237
|
else:
|
221
|
-
x_pixel_size = scan.
|
222
|
-
y_pixel_size = scan.
|
238
|
+
x_pixel_size = scan.detector_x_pixel_size
|
239
|
+
y_pixel_size = scan.detector_y_pixel_size
|
223
240
|
self._setColoredTxt(
|
224
|
-
item=self.
|
241
|
+
item=self._detector_x_pixel_size,
|
225
242
|
text=f"{x_pixel_size} (m)",
|
226
243
|
hightlight_red=x_pixel_size in (None, 0.0, 1.0),
|
227
244
|
)
|
228
245
|
self._setColoredTxt(
|
229
|
-
item=self.
|
246
|
+
item=self._detector_y_pixel_size,
|
230
247
|
text=f"{y_pixel_size} (m)",
|
231
248
|
hightlight_red=y_pixel_size in (None, 0.0, 1.0),
|
232
249
|
)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
|
3
3
|
import numpy
|
4
|
+
import pint
|
4
5
|
from nxtomo.application.nxtomo import NXtomo
|
5
6
|
from silx.gui import qt
|
6
7
|
from nxtomo.nxobject.nxdetector import ImageKey
|
@@ -9,6 +10,8 @@ from tomwer.core.scan.nxtomoscan import NXtomoScan
|
|
9
10
|
from tomwer.gui.visualization.nxtomometadata import NXtomoMetadataViewer
|
10
11
|
from tomwer.tests.conftest import qtapp # noqa F401
|
11
12
|
|
13
|
+
_ureg = pint.get_application_registry()
|
14
|
+
|
12
15
|
|
13
16
|
def test_nx_editor(
|
14
17
|
tmp_path,
|
@@ -16,18 +19,18 @@ def test_nx_editor(
|
|
16
19
|
):
|
17
20
|
# 1.0 create nx tomo with raw data
|
18
21
|
nx_tomo = NXtomo()
|
19
|
-
nx_tomo.instrument.detector.x_pixel_size = 2.6e-6
|
20
|
-
nx_tomo.instrument.detector.y_pixel_size = 2.5e-6
|
22
|
+
nx_tomo.instrument.detector.x_pixel_size = 2.6e-6 * _ureg.meter
|
23
|
+
nx_tomo.instrument.detector.y_pixel_size = 2.5e-6 * _ureg.meter
|
21
24
|
nx_tomo.instrument.detector.field_of_view = "Half"
|
22
|
-
nx_tomo.instrument.detector.distance = 59.0
|
25
|
+
nx_tomo.instrument.detector.distance = 59.0 * _ureg.meter
|
23
26
|
nx_tomo.instrument.detector.x_flipped = True
|
24
27
|
nx_tomo.instrument.detector.y_flipped = False
|
25
|
-
nx_tomo.energy = 12.8
|
26
|
-
nx_tomo.sample.x_translation = numpy.arange(12)
|
27
|
-
nx_tomo.sample.z_translation = numpy.arange(2, 14)
|
28
|
+
nx_tomo.energy = 12.8 * _ureg.keV
|
29
|
+
nx_tomo.sample.x_translation = numpy.arange(12) * _ureg.meter
|
30
|
+
nx_tomo.sample.z_translation = numpy.arange(2, 14) * _ureg.meter
|
28
31
|
nx_tomo.instrument.detector.image_key_control = [ImageKey.PROJECTION.value] * 12
|
29
32
|
nx_tomo.instrument.detector.data = numpy.empty(shape=(12, 10, 10))
|
30
|
-
nx_tomo.sample.rotation_angle = numpy.linspace(0, 180, num=12)
|
33
|
+
nx_tomo.sample.rotation_angle = numpy.linspace(0, 180, num=12) * _ureg.degree
|
31
34
|
|
32
35
|
file_path = os.path.join(tmp_path, "nxtomo.nx")
|
33
36
|
entry = "entry0000"
|
@@ -49,13 +52,22 @@ def test_nx_editor(
|
|
49
52
|
return current_value is None
|
50
53
|
return expected_value == current_value
|
51
54
|
|
52
|
-
assert check_metric(
|
53
|
-
|
54
|
-
|
55
|
-
|
55
|
+
assert check_metric(
|
56
|
+
2.6e-6,
|
57
|
+
widget._xDetectorPixelSizeMetricEntry.getValue().to(_ureg.meter).magnitude,
|
58
|
+
)
|
59
|
+
assert widget._xDetectorPixelSizeMetricEntry._qcbUnit.currentText() == "m"
|
60
|
+
assert check_metric(
|
61
|
+
2.5e-6,
|
62
|
+
widget._yDetectorPixelSizeMetricEntry.getValue().to(_ureg.meter).magnitude,
|
63
|
+
)
|
64
|
+
assert widget._yDetectorPixelSizeMetricEntry._qcbUnit.currentText() == "m"
|
56
65
|
|
57
|
-
assert check_metric(
|
58
|
-
|
66
|
+
assert check_metric(
|
67
|
+
59,
|
68
|
+
widget._sampleDetectorDistanceMetricEntry.getValue().to(_ureg.meter).magnitude,
|
69
|
+
)
|
70
|
+
assert widget._sampleDetectorDistanceMetricEntry._qcbUnit.currentText() == "m"
|
59
71
|
|
60
72
|
assert "Half" == widget._fieldOfViewCB.currentText()
|
61
73
|
assert widget._xFlippedCB.isChecked()
|
@@ -46,8 +46,8 @@ def test_ReconstructionParameters(qtapp, phase_method): # noqa F401
|
|
46
46
|
assert window._methodQLE.text() == "FBP"
|
47
47
|
assert window._paganinQLE.text() == phase_method
|
48
48
|
assert window._deltaBetaQLE.text() == "110.0"
|
49
|
-
assert window.
|
50
|
-
assert window.
|
49
|
+
assert window._sampleDetectorDistanceQLE.text() == "0.4"
|
50
|
+
assert window._voxelSizeQLE.text() == "0.2x0.2x0.2"
|
51
51
|
assert window._corQLE.text() == "104.00"
|
52
52
|
assert window._halfTomoCB.isChecked()
|
53
53
|
assert window._fbpFilterQLE.text() == "Hilbert"
|
tomwer/model/dataset.py
ADDED
File without changes
|
@@ -10,7 +10,7 @@ import os
|
|
10
10
|
import shutil
|
11
11
|
|
12
12
|
from silx.io.url import DataUrl
|
13
|
-
from
|
13
|
+
from enum import Enum as _Enum
|
14
14
|
|
15
15
|
from tomwer.core.scan.edfscan import EDFTomoScan
|
16
16
|
from tomwer.core.scan.nxtomoscan import NXtomoScan
|
@@ -59,7 +59,7 @@ class ScanStages:
|
|
59
59
|
:param stage:
|
60
60
|
:param dest_dir:
|
61
61
|
"""
|
62
|
-
stage = ScanStages.AcquisitionStage
|
62
|
+
stage = ScanStages.AcquisitionStage(stage)
|
63
63
|
if not dest_dir.endswith(os.path.basename(self.scan.path)):
|
64
64
|
dest_dir = os.path.join(dest_dir, os.path.basename(self.scan.path))
|
65
65
|
for t_stage in ScanStages.AcquisitionStage:
|
@@ -75,7 +75,7 @@ class ScanStages:
|
|
75
75
|
"""
|
76
76
|
if not dest_dir.endswith(os.path.basename(self.scan.path)):
|
77
77
|
dest_dir = os.path.join(dest_dir, os.path.basename(self.scan.path))
|
78
|
-
stage = ScanStages.AcquisitionStage
|
78
|
+
stage = ScanStages.AcquisitionStage(stage)
|
79
79
|
if stage is ScanStages.AcquisitionStage.ACQUI_NOT_STARTED:
|
80
80
|
return
|
81
81
|
elif stage is ScanStages.AcquisitionStage.ACQUI_STARTED:
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"""
|
2
|
+
Contains task to clear reduced dark and flat frames
|
3
|
+
"""
|
4
|
+
|
5
|
+
from __future__ import annotations
|
6
|
+
|
7
|
+
from tomoscan.scanbase import TomoScanBase as TomoscanScanBase
|
8
|
+
|
9
|
+
from processview.core.manager import DatasetState, ProcessManager
|
10
|
+
from processview.core.superviseprocess import SuperviseProcess
|
11
|
+
|
12
|
+
from tomwer.tasks.task import Task
|
13
|
+
from tomwer.core.scan.scanbase import TomwerScanBase
|
14
|
+
from tomwer.core.scan.scanfactory import ScanFactory
|
15
|
+
from tomwer.core.utils.scanutils import data_identifier_to_scan
|
16
|
+
from tomwer.core.reconstruction.darkflat import params as dkrf_reconsparams
|
17
|
+
from tomwer.utils import docstring
|
18
|
+
|
19
|
+
|
20
|
+
class ClearReducedDarkAndFlat(
|
21
|
+
Task,
|
22
|
+
SuperviseProcess,
|
23
|
+
input_names=("data",),
|
24
|
+
output_names=("data",),
|
25
|
+
):
|
26
|
+
"""
|
27
|
+
Task to clear reduced darks and flats. Both on disk and on the object cache.
|
28
|
+
th goal of this task is to make sure the scan is cleared of any reduced frames to reprocess it later.
|
29
|
+
"""
|
30
|
+
|
31
|
+
def run(self):
|
32
|
+
scan = self.inputs.data
|
33
|
+
if not isinstance(scan, TomoscanScanBase):
|
34
|
+
raise TypeError(
|
35
|
+
f"scan should be an instance of {TomoscanScanBase}. Got {type(scan)}"
|
36
|
+
)
|
37
|
+
scan.set_reduced_flats(None)
|
38
|
+
scan.reduced_flats_infos = None
|
39
|
+
scan.set_reduced_darks(None)
|
40
|
+
scan.reduced_darks_infos = None
|
41
|
+
|
42
|
+
self.outputs.data = scan
|
@@ -32,7 +32,7 @@ def _create_objects_for_stitching(stitching_type: StitchingType, output_dir) ->
|
|
32
32
|
]
|
33
33
|
)
|
34
34
|
|
35
|
-
stitching_type = StitchingType
|
35
|
+
stitching_type = StitchingType(stitching_type)
|
36
36
|
if stitching_type is StitchingType.Y_PREPROC:
|
37
37
|
nxtomos, positions, _ = test_y_preprocessing_stitching.build_nxtomos(
|
38
38
|
output_dir=output_dir, flip_lr=False, flip_ud=False
|