tomwer 1.4.19__py3-none-any.whl → 1.5.0rc0__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/reducedarkflat.py +2 -2
- 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/darkref/darkrefs.py +2 -2
- tomwer/core/process/reconstruction/darkref/darkrefscopy.py +1 -1
- tomwer/core/process/reconstruction/darkref/params.py +1 -1
- tomwer/core/process/reconstruction/nabu/castvolume.py +4 -1
- tomwer/core/process/reconstruction/nabu/helical.py +3 -1
- 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/test/test_castvolume.py +2 -0
- tomwer/core/process/reconstruction/nabu/utils.py +15 -14
- tomwer/core/process/reconstruction/normalization/params.py +1 -1
- tomwer/core/process/reconstruction/output.py +2 -2
- 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/scan/edfscan.py +3 -3
- tomwer/core/scan/nxtomoscan.py +3 -3
- tomwer/core/scan/scanbase.py +2 -2
- tomwer/core/tomwer_object.py +1 -1
- tomwer/core/utils/nxtomoutils.py +2 -2
- tomwer/core/utils/spec.py +6 -3
- tomwer/gui/control/datadiscovery.py +1 -1
- tomwer/gui/control/reducedarkflatselector.py +4 -4
- tomwer/gui/edit/imagekeyeditor.py +7 -9
- tomwer/gui/edit/nxtomoeditor.py +420 -112
- tomwer/gui/edit/tests/test_nx_editor.py +154 -82
- tomwer/gui/reconstruction/axis/CalculationWidget.py +1 -1
- tomwer/gui/reconstruction/axis/EstimatedCORWidget.py +12 -8
- tomwer/gui/reconstruction/darkref/darkrefwidget.py +2 -2
- tomwer/gui/reconstruction/nabu/castvolume.py +16 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/base.py +1 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +1 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +2 -2
- tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +2 -4
- tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +71 -49
- tomwer/gui/reconstruction/nabu/nabuflow.py +3 -13
- tomwer/gui/reconstruction/nabu/slices.py +6 -6
- tomwer/gui/reconstruction/nabu/test/test_cast_volume.py +19 -0
- tomwer/gui/reconstruction/normalization/intensity.py +2 -2
- tomwer/gui/reconstruction/saaxis/dimensionwidget.py +71 -67
- tomwer/gui/reconstruction/scores/scoreplot.py +15 -7
- 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/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 +1 -1
- tomwer/gui/utils/unitsystem.py +44 -33
- tomwer/gui/visualization/diffviewer/diffviewer.py +4 -4
- tomwer/gui/visualization/diffviewer/shiftwidget.py +4 -6
- tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +25 -13
- tomwer/model/dataset.py +0 -0
- 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.0rc0.dist-info}/METADATA +8 -8
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/RECORD +84 -82
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/WHEEL +1 -1
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/entry_points.txt +0 -0
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/licenses/LICENSE +0 -0
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,13 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import os
|
2
4
|
import h5py
|
3
5
|
|
4
6
|
import numpy
|
5
7
|
import pytest
|
8
|
+
import pint
|
6
9
|
from silx.gui import qt
|
7
10
|
|
8
|
-
from pyunitsystem.energysystem import EnergySI
|
9
|
-
from pyunitsystem.metricsystem import MetricSystem
|
10
|
-
|
11
11
|
from nxtomo.application.nxtomo import NXtomo
|
12
12
|
from nxtomo.nxobject.nxdetector import ImageKey, FOV
|
13
13
|
from nxtomo.utils.transformation import (
|
@@ -22,41 +22,63 @@ from tomwer.core.scan.nxtomoscan import NXtomoScan
|
|
22
22
|
from tomwer.gui.edit.nxtomoeditor import NXtomoEditor, _TranslationMetricEntry
|
23
23
|
from tomwer.tests.conftest import qtapp # noqa F401
|
24
24
|
|
25
|
+
_ureg = pint.get_application_registry()
|
25
26
|
|
26
|
-
|
27
|
-
@pytest.mark.parametrize("
|
27
|
+
|
28
|
+
@pytest.mark.parametrize("detector_x_pixel_size", (0.12 * _ureg.millimeter,))
|
29
|
+
@pytest.mark.parametrize("detector_y_pixel_size", (None,))
|
30
|
+
@pytest.mark.parametrize("sample_x_pixel_size", (None,))
|
31
|
+
@pytest.mark.parametrize("sample_y_pixel_size", (None, 0.0066 * _ureg.meter))
|
28
32
|
@pytest.mark.parametrize("field_of_view", FOV.values())
|
29
|
-
@pytest.mark.parametrize("
|
30
|
-
@pytest.mark.parametrize("
|
31
|
-
@pytest.mark.parametrize("
|
33
|
+
@pytest.mark.parametrize("sample_detector_distance", (1.2 * _ureg.meter,))
|
34
|
+
@pytest.mark.parametrize("sample_source_distance", (-10.2 * _ureg.meter,))
|
35
|
+
@pytest.mark.parametrize("propagation_distance", (1.01 * _ureg.meter,))
|
36
|
+
@pytest.mark.parametrize("energy", (None, 23.5 * _ureg.keV))
|
37
|
+
@pytest.mark.parametrize("x_flipped", (False,))
|
32
38
|
@pytest.mark.parametrize("y_flipped", (True, False))
|
33
|
-
@pytest.mark.parametrize(
|
34
|
-
|
39
|
+
@pytest.mark.parametrize(
|
40
|
+
"x_translation",
|
41
|
+
(None, numpy.ones(12) * _ureg.meter, numpy.arange(12) * _ureg.meter),
|
42
|
+
)
|
43
|
+
@pytest.mark.parametrize(
|
44
|
+
"z_translation",
|
45
|
+
(None, numpy.zeros(12) * _ureg.meter, numpy.arange(12, 24) * _ureg.meter),
|
46
|
+
)
|
35
47
|
def test_nx_editor(
|
36
48
|
tmp_path,
|
37
49
|
qtapp, # noqa F811
|
38
|
-
|
39
|
-
|
50
|
+
detector_x_pixel_size: pint.Quantity | None,
|
51
|
+
detector_y_pixel_size: pint.Quantity | None,
|
52
|
+
sample_x_pixel_size: pint.Quantity | None,
|
53
|
+
sample_y_pixel_size: pint.Quantity | None,
|
54
|
+
propagation_distance: pint.Quantity | None,
|
55
|
+
sample_source_distance: pint.Quantity | None,
|
40
56
|
field_of_view,
|
41
|
-
|
42
|
-
energy,
|
57
|
+
sample_detector_distance: pint.Quantity,
|
58
|
+
energy: pint.Quantity,
|
43
59
|
x_flipped,
|
44
60
|
y_flipped,
|
45
|
-
x_translation,
|
46
|
-
z_translation,
|
61
|
+
x_translation: pint.Quantity,
|
62
|
+
z_translation: pint.Quantity,
|
47
63
|
):
|
48
64
|
# 1.0 create nx tomo with raw data
|
49
65
|
nx_tomo = NXtomo()
|
50
|
-
nx_tomo.instrument.detector.x_pixel_size = x_pixel_size
|
51
|
-
nx_tomo.instrument.detector.y_pixel_size = y_pixel_size
|
52
|
-
nx_tomo.instrument.detector.field_of_view = field_of_view
|
53
|
-
nx_tomo.instrument.detector.distance = distance
|
54
66
|
nx_tomo.energy = energy
|
55
|
-
nx_tomo.
|
56
|
-
nx_tomo.
|
67
|
+
nx_tomo.instrument.detector.x_pixel_size = detector_x_pixel_size
|
68
|
+
nx_tomo.instrument.detector.y_pixel_size = detector_y_pixel_size
|
69
|
+
nx_tomo.instrument.detector.field_of_view = field_of_view
|
70
|
+
nx_tomo.instrument.detector.distance = sample_detector_distance
|
57
71
|
nx_tomo.instrument.detector.image_key_control = [ImageKey.PROJECTION.value] * 12
|
58
72
|
nx_tomo.instrument.detector.data = numpy.empty(shape=(12, 10, 10))
|
59
|
-
|
73
|
+
|
74
|
+
nx_tomo.sample.rotation_angle = numpy.linspace(0, 20, num=12) * _ureg.degree
|
75
|
+
nx_tomo.sample.x_translation = x_translation
|
76
|
+
nx_tomo.sample.z_translation = z_translation
|
77
|
+
nx_tomo.sample.x_pixel_size = sample_x_pixel_size
|
78
|
+
nx_tomo.sample.y_pixel_size = sample_y_pixel_size
|
79
|
+
nx_tomo.sample.propagation_distance = propagation_distance
|
80
|
+
|
81
|
+
nx_tomo.instrument.source.distance = sample_source_distance
|
60
82
|
|
61
83
|
nx_tomo.instrument.detector.transformations.add_transformation(
|
62
84
|
DetZFlipTransformation(flip=x_flipped)
|
@@ -82,16 +104,32 @@ def test_nx_editor(
|
|
82
104
|
def check_metric(expected_value, current_value):
|
83
105
|
if expected_value is None:
|
84
106
|
return current_value is None
|
85
|
-
return numpy.isclose(expected_value,
|
86
|
-
|
87
|
-
assert check_metric(x_pixel_size, widget._xPixelSizeMetricEntry.getValue())
|
88
|
-
assert widget._xPixelSizeMetricEntry._qcbUnit.currentText() == "m"
|
89
|
-
assert check_metric(y_pixel_size, widget._yPixelSizeMetricEntry.getValue())
|
90
|
-
assert widget._yPixelSizeMetricEntry._qcbUnit.currentText() == "m"
|
91
|
-
|
92
|
-
assert check_metric(distance, widget._distanceMetricEntry.getValue())
|
93
|
-
assert widget._distanceMetricEntry._qcbUnit.currentText() == "m"
|
107
|
+
return numpy.isclose(expected_value, current_value)
|
94
108
|
|
109
|
+
assert check_metric(
|
110
|
+
detector_x_pixel_size, widget._xDetectorPixelSizeMetricEntry.getValue()
|
111
|
+
)
|
112
|
+
assert widget._xDetectorPixelSizeMetricEntry._qcbUnit.currentText() == "m"
|
113
|
+
assert check_metric(
|
114
|
+
detector_y_pixel_size, widget._yDetectorPixelSizeMetricEntry.getValue()
|
115
|
+
)
|
116
|
+
assert widget._yDetectorPixelSizeMetricEntry._qcbUnit.currentText() == "m"
|
117
|
+
assert check_metric(
|
118
|
+
sample_detector_distance, widget._sampleDetectorDistanceMetricEntry.getValue()
|
119
|
+
)
|
120
|
+
assert widget._sampleDetectorDistanceMetricEntry._qcbUnit.currentText() == "m"
|
121
|
+
assert check_metric(
|
122
|
+
sample_x_pixel_size, widget._xSamplePixelSizeMetricEntry.getValue()
|
123
|
+
)
|
124
|
+
assert check_metric(
|
125
|
+
sample_y_pixel_size, widget._ySamplePixelSizeMetricEntry.getValue()
|
126
|
+
)
|
127
|
+
assert check_metric(
|
128
|
+
sample_source_distance, widget._sampleSourceDistanceMetricEntry.getValue()
|
129
|
+
)
|
130
|
+
assert check_metric(
|
131
|
+
propagation_distance, widget._propagationDistanceMetricEntry.getValue()
|
132
|
+
)
|
95
133
|
assert field_of_view == widget._fieldOfViewCB.currentText()
|
96
134
|
assert x_flipped == widget._xFlippedCB.isChecked()
|
97
135
|
assert y_flipped == widget._yFlippedCB.isChecked()
|
@@ -99,12 +137,18 @@ def test_nx_editor(
|
|
99
137
|
if energy is None:
|
100
138
|
assert widget._energyEntry.getValue() is None
|
101
139
|
else:
|
102
|
-
assert numpy.isclose(
|
140
|
+
assert numpy.isclose(
|
141
|
+
energy.to(_ureg.keV).magnitude, widget._energyEntry.getValue()
|
142
|
+
)
|
103
143
|
|
104
144
|
def check_translation(expected_value, current_value):
|
105
145
|
if expected_value is None:
|
106
146
|
return current_value is None
|
107
147
|
else:
|
148
|
+
expected_value = expected_value.to_base_units().magnitude
|
149
|
+
assert current_value is not None
|
150
|
+
if isinstance(current_value, pint.Quantity):
|
151
|
+
current_value = current_value.to_base_units().magnitude
|
108
152
|
u_values = numpy.unique(expected_value)
|
109
153
|
if u_values.size == 1:
|
110
154
|
return float(current_value) == u_values[0]
|
@@ -118,15 +162,18 @@ def test_nx_editor(
|
|
118
162
|
|
119
163
|
# 4.0 edit some parameters
|
120
164
|
widget._energyEntry.setText("23.789")
|
121
|
-
widget.
|
122
|
-
widget.
|
123
|
-
widget.
|
165
|
+
widget._xDetectorPixelSizeMetricEntry.setUnit(_ureg.nanometer)
|
166
|
+
widget._yDetectorPixelSizeMetricEntry.setValue(2.1e-7)
|
167
|
+
widget._xSamplePixelSizeMetricEntry.setValue(value_m=5.6e-6)
|
168
|
+
widget._sampleDetectorDistanceMetricEntry.setValue("unknown")
|
169
|
+
widget._sampleSourceDistanceMetricEntry.setValue(-99)
|
170
|
+
widget._propagationDistanceMetricEntry.setValue(88)
|
124
171
|
widget._fieldOfViewCB.setCurrentText(FOV.HALF.value)
|
125
172
|
widget._xFlippedCB.setChecked(not x_flipped)
|
126
173
|
widget._xTranslationQLE.setValue(1.8)
|
127
|
-
widget._xTranslationQLE.setUnit(
|
174
|
+
widget._xTranslationQLE.setUnit(_ureg.millimeter)
|
128
175
|
widget._zTranslationQLE.setValue(2.8)
|
129
|
-
widget._zTranslationQLE.setUnit(
|
176
|
+
widget._zTranslationQLE.setUnit(_ureg.meter)
|
130
177
|
|
131
178
|
# 5.0
|
132
179
|
task = NXtomoEditorTask(
|
@@ -143,19 +190,18 @@ def test_nx_editor(
|
|
143
190
|
data_path=entry,
|
144
191
|
)
|
145
192
|
|
146
|
-
assert overwrite_nx_tomo.energy
|
147
|
-
assert overwrite_nx_tomo.energy.unit == EnergySI.KILOELECTRONVOLT
|
193
|
+
assert overwrite_nx_tomo.energy == 23.789 * _ureg.keV
|
148
194
|
|
149
|
-
if
|
150
|
-
assert overwrite_nx_tomo.instrument.detector.x_pixel_size
|
195
|
+
if detector_x_pixel_size is None:
|
196
|
+
assert overwrite_nx_tomo.instrument.detector.x_pixel_size is None
|
151
197
|
else:
|
152
198
|
assert numpy.isclose(
|
153
|
-
overwrite_nx_tomo.instrument.detector.x_pixel_size
|
154
|
-
|
199
|
+
overwrite_nx_tomo.instrument.detector.x_pixel_size,
|
200
|
+
0.12 * _ureg.nanometer,
|
155
201
|
)
|
156
|
-
assert overwrite_nx_tomo.instrument.detector.y_pixel_size
|
202
|
+
assert overwrite_nx_tomo.instrument.detector.y_pixel_size == 2.1e-7 * _ureg.meter
|
157
203
|
|
158
|
-
assert overwrite_nx_tomo.instrument.detector.distance
|
204
|
+
assert overwrite_nx_tomo.instrument.detector.distance is None
|
159
205
|
assert overwrite_nx_tomo.instrument.detector.field_of_view is FOV.HALF
|
160
206
|
|
161
207
|
final_transformation = NXtransformations()
|
@@ -172,15 +218,13 @@ def test_nx_editor(
|
|
172
218
|
)
|
173
219
|
|
174
220
|
numpy.testing.assert_array_almost_equal(
|
175
|
-
overwrite_nx_tomo.sample.x_translation
|
176
|
-
numpy.array([1.8 *
|
221
|
+
overwrite_nx_tomo.sample.x_translation,
|
222
|
+
(numpy.array([1.8] * 12) * _ureg.millimeter).to_base_units(),
|
177
223
|
)
|
178
|
-
assert overwrite_nx_tomo.sample.x_translation.unit is MetricSystem.METER
|
179
224
|
numpy.testing.assert_array_almost_equal(
|
180
|
-
overwrite_nx_tomo.sample.z_translation
|
181
|
-
numpy.array([2.8 *
|
225
|
+
overwrite_nx_tomo.sample.z_translation,
|
226
|
+
numpy.array([2.8] * 12) * _ureg.meter,
|
182
227
|
)
|
183
|
-
assert overwrite_nx_tomo.sample.z_translation.unit is MetricSystem.METER
|
184
228
|
# end
|
185
229
|
widget.setAttribute(qt.Qt.WA_DeleteOnClose)
|
186
230
|
widget.close()
|
@@ -194,16 +238,20 @@ def test_nx_editor_lock(
|
|
194
238
|
"""test the pad lock buttons of the NXtomo editor"""
|
195
239
|
# 1.0 create nx tomos with raw data
|
196
240
|
nx_tomo_1 = NXtomo()
|
197
|
-
nx_tomo_1.instrument.
|
198
|
-
nx_tomo_1.instrument.detector.
|
241
|
+
nx_tomo_1.instrument.source.distance = 54.8 * _ureg.meter
|
242
|
+
nx_tomo_1.instrument.detector.x_pixel_size = 0.023 * _ureg.meter
|
243
|
+
nx_tomo_1.instrument.detector.y_pixel_size = 0.025 * _ureg.meter
|
199
244
|
nx_tomo_1.instrument.detector.field_of_view = "full"
|
200
|
-
nx_tomo_1.instrument.detector.distance = 2.4
|
245
|
+
nx_tomo_1.instrument.detector.distance = 2.4 * _ureg.meter
|
201
246
|
nx_tomo_1.instrument.detector.x_flipped = False
|
202
247
|
nx_tomo_1.instrument.detector.y_flipped = True
|
203
|
-
nx_tomo_1.energy = 5.9
|
248
|
+
nx_tomo_1.energy = 5.9 * _ureg.keV
|
204
249
|
nx_tomo_1.instrument.detector.image_key_control = [ImageKey.PROJECTION.value] * 12
|
205
250
|
nx_tomo_1.instrument.detector.data = numpy.empty(shape=(12, 10, 10))
|
206
|
-
nx_tomo_1.sample.rotation_angle = numpy.linspace(0, 20, num=12)
|
251
|
+
nx_tomo_1.sample.rotation_angle = numpy.linspace(0, 20, num=12) * _ureg.degree
|
252
|
+
nx_tomo_1.sample.propagation_distance = 22.0 * _ureg.meter
|
253
|
+
nx_tomo_1.sample.x_pixel_size = 0.023 * _ureg.millimeter
|
254
|
+
nx_tomo_1.sample.y_pixel_size = 0.025 * _ureg.millimeter
|
207
255
|
|
208
256
|
file_path = os.path.join(tmp_path, "nxtomo.nx")
|
209
257
|
entry = "entry0000"
|
@@ -215,20 +263,21 @@ def test_nx_editor_lock(
|
|
215
263
|
scan_1 = NXtomoScan(file_path, entry)
|
216
264
|
|
217
265
|
nx_tomo_2 = NXtomo()
|
218
|
-
nx_tomo_2.instrument.
|
219
|
-
nx_tomo_2.instrument.detector.
|
266
|
+
nx_tomo_2.instrument.source.distance = 8 * _ureg.meter
|
267
|
+
nx_tomo_2.instrument.detector.x_pixel_size = 4.023 * _ureg.meter
|
268
|
+
nx_tomo_2.instrument.detector.y_pixel_size = 6.025 * _ureg.meter
|
220
269
|
nx_tomo_2.instrument.detector.field_of_view = "full"
|
221
|
-
nx_tomo_2.instrument.detector.distance = 2.89
|
270
|
+
nx_tomo_2.instrument.detector.distance = 2.89 * _ureg.meter
|
222
271
|
nx_tomo_2.instrument.detector.x_flipped = (
|
223
272
|
not nx_tomo_1.instrument.detector.x_flipped
|
224
273
|
)
|
225
274
|
nx_tomo_2.instrument.detector.y_flipped = (
|
226
275
|
not nx_tomo_1.instrument.detector.y_flipped
|
227
276
|
)
|
228
|
-
nx_tomo_2.energy = 5.754
|
277
|
+
nx_tomo_2.energy = 5.754 * _ureg.keV
|
229
278
|
nx_tomo_2.instrument.detector.image_key_control = [ImageKey.PROJECTION.value] * 12
|
230
279
|
nx_tomo_2.instrument.detector.data = numpy.empty(shape=(12, 10, 10))
|
231
|
-
nx_tomo_2.sample.rotation_angle = numpy.linspace(0, 20, num=12)
|
280
|
+
nx_tomo_2.sample.rotation_angle = numpy.linspace(0, 20, num=12) * _ureg.degree
|
232
281
|
|
233
282
|
file_path = os.path.join(tmp_path, "nxtomo.nx")
|
234
283
|
entry = "entry0001"
|
@@ -249,12 +298,16 @@ def test_nx_editor_lock(
|
|
249
298
|
widget.setScan(scan=scan_2)
|
250
299
|
# widget values must be the same (NXtomo field value not loaded if the lockers are active)
|
251
300
|
assert widget._energyEntry.getValue() == 5.9
|
252
|
-
assert widget.
|
253
|
-
assert widget.
|
254
|
-
assert widget.
|
301
|
+
assert widget._xDetectorPixelSizeMetricEntry.getValue() == 0.023 * _ureg.meter
|
302
|
+
assert widget._yDetectorPixelSizeMetricEntry.getValue() == 0.025 * _ureg.meter
|
303
|
+
assert widget._sampleDetectorDistanceMetricEntry.getValue() == 2.4 * _ureg.meter
|
304
|
+
assert widget._propagationDistanceMetricEntry.getValue() == 22.0 * _ureg.meter
|
255
305
|
assert widget._fieldOfViewCB.currentText() == "Full"
|
256
306
|
assert not widget._xFlippedCB.isChecked()
|
257
307
|
assert widget._yFlippedCB.isChecked()
|
308
|
+
assert widget._xSamplePixelSizeMetricEntry.getValue() == 0.023 * _ureg.millimeter
|
309
|
+
assert widget._ySamplePixelSizeMetricEntry.getValue() == 0.025 * _ureg.millimeter
|
310
|
+
assert widget._sampleSourceDistanceMetricEntry.getValue() == 54.8 * _ureg.meter
|
258
311
|
|
259
312
|
# 3.0 save the nxtomo
|
260
313
|
task = NXtomoEditorTask(
|
@@ -271,20 +324,20 @@ def test_nx_editor_lock(
|
|
271
324
|
data_path=entry,
|
272
325
|
)
|
273
326
|
assert (
|
274
|
-
overwrite_nx_tomo.instrument.detector.x_pixel_size
|
275
|
-
== nx_tomo_1.instrument.detector.x_pixel_size
|
327
|
+
overwrite_nx_tomo.instrument.detector.x_pixel_size
|
328
|
+
== nx_tomo_1.instrument.detector.x_pixel_size
|
276
329
|
)
|
277
330
|
assert (
|
278
|
-
overwrite_nx_tomo.instrument.detector.y_pixel_size
|
279
|
-
== nx_tomo_1.instrument.detector.y_pixel_size
|
331
|
+
overwrite_nx_tomo.instrument.detector.y_pixel_size
|
332
|
+
== nx_tomo_1.instrument.detector.y_pixel_size
|
280
333
|
)
|
281
334
|
assert (
|
282
335
|
overwrite_nx_tomo.instrument.detector.field_of_view
|
283
336
|
== nx_tomo_1.instrument.detector.field_of_view
|
284
337
|
)
|
285
338
|
assert (
|
286
|
-
overwrite_nx_tomo.instrument.detector.distance
|
287
|
-
== nx_tomo_1.instrument.detector.distance
|
339
|
+
overwrite_nx_tomo.instrument.detector.distance
|
340
|
+
== nx_tomo_1.instrument.detector.distance
|
288
341
|
)
|
289
342
|
assert (
|
290
343
|
overwrite_nx_tomo.instrument.detector.x_flipped
|
@@ -294,8 +347,17 @@ def test_nx_editor_lock(
|
|
294
347
|
overwrite_nx_tomo.instrument.detector.y_flipped
|
295
348
|
== nx_tomo_1.instrument.detector.y_flipped
|
296
349
|
)
|
297
|
-
assert overwrite_nx_tomo.energy
|
298
|
-
|
350
|
+
assert overwrite_nx_tomo.energy == nx_tomo_1.energy
|
351
|
+
assert (
|
352
|
+
overwrite_nx_tomo.sample.propagation_distance
|
353
|
+
== nx_tomo_1.sample.propagation_distance
|
354
|
+
)
|
355
|
+
assert overwrite_nx_tomo.sample.x_pixel_size == nx_tomo_1.sample.x_pixel_size
|
356
|
+
assert overwrite_nx_tomo.sample.y_pixel_size == nx_tomo_1.sample.y_pixel_size
|
357
|
+
assert (
|
358
|
+
overwrite_nx_tomo.instrument.source.distance
|
359
|
+
== nx_tomo_1.instrument.source.distance
|
360
|
+
)
|
299
361
|
assert widget.getConfiguration() == {
|
300
362
|
"instrument.beam.energy": (5.9, True),
|
301
363
|
"instrument.detector.distance": (2.4, True),
|
@@ -304,6 +366,10 @@ def test_nx_editor_lock(
|
|
304
366
|
"instrument.detector.y_pixel_size": (0.025, True),
|
305
367
|
"instrument.detector.x_flipped": (False, True),
|
306
368
|
"instrument.detector.y_flipped": (True, True),
|
369
|
+
"instrument.source.distance": (54.8, True),
|
370
|
+
"sample.propagation_distance": (22.0, True),
|
371
|
+
"sample.x_pixel_size": (2.3e-5, True),
|
372
|
+
"sample.y_pixel_size": (2.5e-5, True),
|
307
373
|
"sample.x_translation": (None,),
|
308
374
|
"sample.z_translation": (None,),
|
309
375
|
}
|
@@ -319,6 +385,12 @@ def test_nx_editor_lock(
|
|
319
385
|
"instrument.detector.y_pixel_size": (0.025, False),
|
320
386
|
"instrument.detector.x_flipped": (False, False),
|
321
387
|
"instrument.detector.y_flipped": (True, False),
|
388
|
+
"instrument.source.distance": (54.8, False),
|
389
|
+
"sample.x_translation": (None,),
|
390
|
+
"sample.z_translation": (None,),
|
391
|
+
"sample.propagation_distance": (22.0, False),
|
392
|
+
"sample.x_pixel_size": (2.3e-5, False),
|
393
|
+
"sample.y_pixel_size": (2.5e-5, False),
|
322
394
|
"sample.x_translation": (None,),
|
323
395
|
"sample.z_translation": (None,),
|
324
396
|
}
|
@@ -336,7 +408,7 @@ def test_nxtomo_editor_with_missing_paths(
|
|
336
408
|
nx_tomo = NXtomo()
|
337
409
|
nx_tomo.instrument.detector.image_key_control = [ImageKey.PROJECTION.value] * 12
|
338
410
|
nx_tomo.instrument.detector.data = numpy.empty(shape=(12, 10, 10))
|
339
|
-
nx_tomo.sample.rotation_angle = numpy.linspace(0, 20, num=12)
|
411
|
+
nx_tomo.sample.rotation_angle = numpy.linspace(0, 20, num=12) * _ureg.degree
|
340
412
|
|
341
413
|
file_path = os.path.join(tmp_path, "nxtomo.nx")
|
342
414
|
entry = "entry0000"
|
@@ -361,10 +433,10 @@ def test_nxtomo_editor_with_missing_paths(
|
|
361
433
|
|
362
434
|
widget.setScan(scan=scan)
|
363
435
|
|
364
|
-
widget.
|
365
|
-
widget._energyEntry.setValue(50)
|
366
|
-
widget.
|
367
|
-
widget.
|
436
|
+
widget._sampleDetectorDistanceMetricEntry.setValue(0.05)
|
437
|
+
widget._energyEntry.setValue(50.0)
|
438
|
+
widget._xDetectorPixelSizeMetricEntry.setValue(0.02)
|
439
|
+
widget._yDetectorPixelSizeMetricEntry.setValue(0.03)
|
368
440
|
|
369
441
|
# overwrite the NXtomo
|
370
442
|
task = NXtomoEditorTask(
|
@@ -380,7 +452,7 @@ def test_nxtomo_editor_with_missing_paths(
|
|
380
452
|
file_path=file_path,
|
381
453
|
data_path=entry,
|
382
454
|
)
|
383
|
-
assert overwrite_nx_tomo.instrument.detector.x_pixel_size
|
384
|
-
assert overwrite_nx_tomo.instrument.detector.y_pixel_size
|
385
|
-
assert overwrite_nx_tomo.energy
|
386
|
-
assert overwrite_nx_tomo.instrument.detector.distance
|
455
|
+
assert overwrite_nx_tomo.instrument.detector.x_pixel_size == 0.02 * _ureg.meter
|
456
|
+
assert overwrite_nx_tomo.instrument.detector.y_pixel_size == 0.03 * _ureg.meter
|
457
|
+
assert overwrite_nx_tomo.energy == 50 * _ureg.keV
|
458
|
+
assert overwrite_nx_tomo.instrument.detector.distance == 0.05 * _ureg.meter
|
@@ -212,5 +212,5 @@ class CalculationWidget(qt.QWidget):
|
|
212
212
|
self.setMode(self._axis_params.mode)
|
213
213
|
|
214
214
|
def setScan(self, scan: TomwerScanBase | None):
|
215
|
-
self._estimatedCorWidget.setPixelSize(pixel_size_m=scan.
|
215
|
+
self._estimatedCorWidget.setPixelSize(pixel_size_m=scan.sample_x_pixel_size)
|
216
216
|
self._estimatedCorWidget.setImageWidth(image_width=scan.dim_1)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import pint
|
3
4
|
from silx.gui import qt
|
4
5
|
from processview.gui.DropDownWidget import DropDownWidget
|
5
6
|
from tomwer.synctools.axis import QAxisRP
|
@@ -10,7 +11,8 @@ from tomwer.core.process.reconstruction.axis.side import Side
|
|
10
11
|
from tomwer.core.process.reconstruction.axis import mode as axis_mode
|
11
12
|
from tomwer.gui.fonts import FONT_SMALL
|
12
13
|
from tomwer.gui.utils.scrollarea import QDoubleSpinBoxIgnoreWheel
|
13
|
-
|
14
|
+
|
15
|
+
_ureg = pint.get_application_registry()
|
14
16
|
|
15
17
|
|
16
18
|
class EstimatedCORWidget(qt.QGroupBox):
|
@@ -345,19 +347,19 @@ class _OffsetCalibration(qt.QGroupBox):
|
|
345
347
|
def _motorOffsetChanged(self):
|
346
348
|
"""Recalculate the offset when the motor offset changes."""
|
347
349
|
if self._pixelSizeSB.value() and self._motorOffsetSB.value():
|
348
|
-
|
349
|
-
|
350
|
+
pixel_size = self._pixelSizeSB.value() * _ureg.micrometer
|
351
|
+
motor_offset = self._motorOffsetSB.value() * _ureg.millimeter
|
350
352
|
with block_signals(self):
|
351
|
-
self.setOffset(
|
353
|
+
self.setOffset((motor_offset / pixel_size).to_base_units().magnitude)
|
352
354
|
self.sigOffsetChanged.emit()
|
353
355
|
|
354
356
|
def _pixelSizeChanged(self):
|
355
357
|
"""Recalculate the offset when the pixel size changes."""
|
356
358
|
if self._pixelSizeSB.value() and self._motorOffsetSB.value():
|
357
|
-
|
358
|
-
|
359
|
+
pixel_size = self._pixelSizeSB.value() * _ureg.micrometer
|
360
|
+
motor_offset = self._motorOffsetSB.value() * _ureg.millimeter
|
359
361
|
with block_signals(self):
|
360
|
-
self.setOffset(
|
362
|
+
self.setOffset((motor_offset / pixel_size).to_base_units().magnitude)
|
361
363
|
self.sigOffsetChanged.emit()
|
362
364
|
|
363
365
|
def _xRotationAxisPixelPositionEdited(self):
|
@@ -387,7 +389,9 @@ class _OffsetCalibration(qt.QGroupBox):
|
|
387
389
|
if pixel_size_m is None:
|
388
390
|
self._pixelSizeSB.clear()
|
389
391
|
else:
|
390
|
-
self._pixelSizeSB.setValue(
|
392
|
+
self._pixelSizeSB.setValue(
|
393
|
+
(pixel_size_m * _ureg.meter).to(_ureg.micrometer).magnitude
|
394
|
+
)
|
391
395
|
|
392
396
|
def _togglePixelSizeLock(self, locked: bool):
|
393
397
|
"""Lock or unlock the pixel size spin box."""
|
@@ -125,7 +125,7 @@ class _WhatCheckBox(qt.QWidget):
|
|
125
125
|
|
126
126
|
def getMode(self) -> dkrf.ReduceMethod:
|
127
127
|
if self._checkbox.isChecked():
|
128
|
-
return dkrf.ReduceMethod
|
128
|
+
return dkrf.ReduceMethod(self._modeCB.currentText())
|
129
129
|
else:
|
130
130
|
return dkrf.ReduceMethod.NONE
|
131
131
|
|
@@ -136,7 +136,7 @@ class _WhatCheckBox(qt.QWidget):
|
|
136
136
|
self.sigChanged.emit(self.getMode())
|
137
137
|
|
138
138
|
def setMode(self, mode):
|
139
|
-
mode = dkrf.ReduceMethod
|
139
|
+
mode = dkrf.ReduceMethod(mode)
|
140
140
|
assert mode in dkrf.ReduceMethod
|
141
141
|
self._checkbox.toggled.disconnect(self._modeChange)
|
142
142
|
self._modeCB.currentIndexChanged.disconnect(self._modeChange)
|
@@ -130,7 +130,11 @@ class CastVolumeWidget(qt.QWidget):
|
|
130
130
|
# overwrite
|
131
131
|
self._overwriteCB = qt.QCheckBox("overwrite", self)
|
132
132
|
self._overwriteCB.setChecked(True)
|
133
|
-
self.layout().addWidget(self._overwriteCB, 16, 0, 1,
|
133
|
+
self.layout().addWidget(self._overwriteCB, 16, 0, 1, 2)
|
134
|
+
# remove input volume
|
135
|
+
self._removeInputvolumeCB = qt.QCheckBox("remove input volume", self)
|
136
|
+
self._removeInputvolumeCB.setChecked(False)
|
137
|
+
self.layout().addWidget(self._removeInputvolumeCB, 17, 0, 1, 2)
|
134
138
|
# spacer
|
135
139
|
self._spacer = qt.QWidget(self)
|
136
140
|
self._spacer.setSizePolicy(
|
@@ -156,6 +160,7 @@ class CastVolumeWidget(qt.QWidget):
|
|
156
160
|
self._maxPixValue.textChanged.connect(self._configChanged)
|
157
161
|
self._lowPercentileQSB.valueChanged.connect(self._configChanged)
|
158
162
|
self._highPercentileQSB.valueChanged.connect(self._configChanged)
|
163
|
+
self._removeInputvolumeCB.toggled.connect(self._configChanged)
|
159
164
|
|
160
165
|
def _updateCRatiosVis(self, *args, **kwargs):
|
161
166
|
self._cRatiosLabel.setVisible(
|
@@ -200,6 +205,12 @@ class CastVolumeWidget(qt.QWidget):
|
|
200
205
|
def setOverwrite(self, remove) -> None:
|
201
206
|
self._overwriteCB.setChecked(remove)
|
202
207
|
|
208
|
+
def isRemoveInputVolume(self) -> bool:
|
209
|
+
return self._removeInputvolumeCB.isChecked()
|
210
|
+
|
211
|
+
def setRemoveInputVolume(self, remove: bool) -> None:
|
212
|
+
self._removeInputvolumeCB.setChecked(remove)
|
213
|
+
|
203
214
|
def getDataMin(self) -> float | None:
|
204
215
|
if (
|
205
216
|
self._minMaxAuto.isChecked()
|
@@ -281,6 +292,7 @@ class CastVolumeWidget(qt.QWidget):
|
|
281
292
|
"data_min": data_min,
|
282
293
|
"data_max": data_max,
|
283
294
|
"compression_ratios": self.getCompressionRatios(),
|
295
|
+
"remove_input_volume": self.isRemoveInputVolume(),
|
284
296
|
}
|
285
297
|
|
286
298
|
def setConfiguration(self, config: dict) -> None:
|
@@ -306,6 +318,9 @@ class CastVolumeWidget(qt.QWidget):
|
|
306
318
|
self.setDataMax(config["data_max"])
|
307
319
|
if "compression_ratios" in config:
|
308
320
|
self.setCompressionRatios(config["compression_ratios"])
|
321
|
+
remove_input_volume = config.get("remove_input_volume", None)
|
322
|
+
if remove_input_volume is not None:
|
323
|
+
self.setRemoveInputVolume(remove=remove_input_volume)
|
309
324
|
|
310
325
|
def _configChanged(self, *args, **kwargs):
|
311
326
|
self.sigConfigChanged.emit()
|
@@ -38,7 +38,7 @@ class _NabuStageConfigBase:
|
|
38
38
|
if stage is None:
|
39
39
|
self.__stage = None
|
40
40
|
else:
|
41
|
-
self.__stage = _NabuStages
|
41
|
+
self.__stage = _NabuStages(stage)
|
42
42
|
self._registeredWidgets = {}
|
43
43
|
# list required widgets. Key is widget, value is the configuration
|
44
44
|
# level
|
@@ -135,7 +135,7 @@ class NabuConfiguration(qt.QWidget):
|
|
135
135
|
):
|
136
136
|
widget.setVisible(True)
|
137
137
|
else:
|
138
|
-
stage = _NabuStages
|
138
|
+
stage = _NabuStages(stage)
|
139
139
|
self._preProcessingGB.setVisible(stage is _NabuStages.PRE)
|
140
140
|
self._reconstructionGB.setVisible(stage is _NabuStages.PROC)
|
141
141
|
self._outputGB.setVisible(stage is _NabuStages.POST)
|
@@ -102,7 +102,7 @@ class _NabuPhaseConfig(qt.QWidget, base._NabuStageConfigBase):
|
|
102
102
|
self.sigConfChanged.emit(param)
|
103
103
|
|
104
104
|
def getMethod(self) -> _NabuPhaseMethod:
|
105
|
-
return _NabuPhaseMethod
|
105
|
+
return _NabuPhaseMethod(self._methodCB.currentText())
|
106
106
|
|
107
107
|
@docstring(base._NabuStageConfigBase)
|
108
108
|
def setConfiguration(self, config) -> None:
|
@@ -111,7 +111,7 @@ class _NabuPhaseConfig(qt.QWidget, base._NabuStageConfigBase):
|
|
111
111
|
if method == "none":
|
112
112
|
method = _NabuPhaseMethod.NONE
|
113
113
|
self._paganinOpts.setConfiguration(config)
|
114
|
-
method = _NabuPhaseMethod
|
114
|
+
method = _NabuPhaseMethod(method)
|
115
115
|
index_method = self._methodCB.findText(method.value)
|
116
116
|
if index_method >= 0:
|
117
117
|
self._methodCB.setCurrentIndex(index_method)
|
@@ -401,9 +401,7 @@ class _NabuPreProcessingConfig(_NabuStageConfigBase, qt.QWidget):
|
|
401
401
|
if sino_rings_correction is not None:
|
402
402
|
if sino_rings_correction == "":
|
403
403
|
sino_rings_correction = RingCorrectionMethod.NONE
|
404
|
-
sino_rings_correction = RingCorrectionMethod.
|
405
|
-
sino_rings_correction
|
406
|
-
).value
|
404
|
+
sino_rings_correction = RingCorrectionMethod(sino_rings_correction).value
|
407
405
|
idx = self._sinoRingCorrectionMthd.findText(sino_rings_correction)
|
408
406
|
if idx >= 0:
|
409
407
|
self._sinoRingCorrectionMthd.setCurrentIndex(idx)
|
@@ -581,7 +579,7 @@ class SinoRingsOptions(qt.QWidget):
|
|
581
579
|
self._sigmaHigh.setValue(float(high_pass))
|
582
580
|
|
583
581
|
def setMethod(self, method: RingCorrectionMethod):
|
584
|
-
method = RingCorrectionMethod
|
582
|
+
method = RingCorrectionMethod(method)
|
585
583
|
self._method = method
|
586
584
|
# handle munch options
|
587
585
|
self._sigmaMunch.setVisible(method is RingCorrectionMethod.MUNCH)
|