tomwer 1.4.0rc0__py3-none-any.whl → 1.4.0rc1__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.
Files changed (51) hide show
  1. orangecontrib/tomwer/tutorials/test_cor.ows +3 -3
  2. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +6 -14
  3. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +4 -2
  4. tomwer/app/axis.py +0 -3
  5. tomwer/app/multipag.py +11 -3
  6. tomwer/core/process/reconstruction/axis/axis.py +27 -736
  7. tomwer/core/process/reconstruction/axis/mode.py +86 -24
  8. tomwer/core/process/reconstruction/axis/params.py +127 -138
  9. tomwer/core/process/reconstruction/axis/side.py +8 -0
  10. tomwer/core/process/reconstruction/nabu/nabuscores.py +17 -20
  11. tomwer/core/process/reconstruction/nabu/nabuslices.py +5 -1
  12. tomwer/core/process/reconstruction/saaxis/saaxis.py +4 -4
  13. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +4 -4
  14. tomwer/core/process/reconstruction/tests/test_axis.py +1 -1
  15. tomwer/core/process/reconstruction/tests/test_utils.py +4 -4
  16. tomwer/core/process/reconstruction/utils/cor.py +8 -4
  17. tomwer/core/process/tests/test_nabu.py +1 -3
  18. tomwer/core/scan/scanbase.py +4 -4
  19. tomwer/core/scan/tests/test_process_registration.py +0 -18
  20. tomwer/gui/fonts.py +5 -0
  21. tomwer/gui/reconstruction/axis/AxisMainWindow.py +20 -9
  22. tomwer/gui/reconstruction/axis/AxisOptionsWidget.py +239 -79
  23. tomwer/gui/reconstruction/axis/AxisSettingsWidget.py +38 -17
  24. tomwer/gui/reconstruction/axis/AxisWidget.py +16 -8
  25. tomwer/gui/reconstruction/axis/CalculationWidget.py +40 -200
  26. tomwer/gui/reconstruction/axis/ControlWidget.py +10 -2
  27. tomwer/gui/reconstruction/axis/EstimatedCORWidget.py +383 -0
  28. tomwer/gui/reconstruction/axis/EstimatedCorComboBox.py +118 -0
  29. tomwer/gui/reconstruction/axis/InputWidget.py +11 -155
  30. tomwer/gui/reconstruction/saaxis/corrangeselector.py +19 -10
  31. tomwer/gui/reconstruction/scores/scoreplot.py +5 -2
  32. tomwer/gui/reconstruction/tests/test_nabu.py +8 -0
  33. tomwer/gui/stitching/z_stitching/fineestimation.py +1 -1
  34. tomwer/gui/tests/test_axis_gui.py +31 -15
  35. tomwer/synctools/stacks/reconstruction/axis.py +5 -23
  36. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +1 -1
  37. tomwer/synctools/stacks/reconstruction/nabu.py +2 -2
  38. tomwer/synctools/stacks/reconstruction/normalization.py +1 -1
  39. tomwer/synctools/stacks/reconstruction/saaxis.py +1 -1
  40. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +1 -1
  41. tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_axis.py +0 -16
  42. tomwer/tests/test_ewoks/test_single_node_execution.py +1 -1
  43. tomwer/tests/test_ewoks/test_workflows.py +1 -1
  44. tomwer/version.py +1 -1
  45. {tomwer-1.4.0rc0.dist-info → tomwer-1.4.0rc1.dist-info}/METADATA +2 -2
  46. {tomwer-1.4.0rc0.dist-info → tomwer-1.4.0rc1.dist-info}/RECORD +50 -47
  47. tomwer/core/process/tests/test_axis.py +0 -231
  48. {tomwer-1.4.0rc0.dist-info → tomwer-1.4.0rc1.dist-info}/LICENSE +0 -0
  49. {tomwer-1.4.0rc0.dist-info → tomwer-1.4.0rc1.dist-info}/WHEEL +0 -0
  50. {tomwer-1.4.0rc0.dist-info → tomwer-1.4.0rc1.dist-info}/entry_points.txt +0 -0
  51. {tomwer-1.4.0rc0.dist-info → tomwer-1.4.0rc1.dist-info}/top_level.txt +0 -0
@@ -6,17 +6,10 @@ from silx.gui import qt
6
6
 
7
7
  from tomwer.core.process.reconstruction.axis import mode as axis_mode
8
8
  from tomwer.core.process.reconstruction.axis.anglemode import CorAngleMode
9
- from tomwer.core.process.reconstruction.axis.params import (
10
- DEFAULT_CMP_N_SUBSAMPLING_Y,
11
- DEFAULT_CMP_OVERSAMPLING,
12
- DEFAULT_CMP_TAKE_LOG,
13
- DEFAULT_CMP_THETA,
14
- )
15
9
  from tomwer.gui.utils.scrollarea import QComboBoxIgnoreWheel
16
10
  from tomwer.core.scan.scanbase import TomwerScanBase
17
11
  from tomwer.gui.utils.qt_utils import block_signals
18
12
  from tomwer.synctools.axis import QAxisRP
19
- from .CalculationWidget import CalculationWidget
20
13
  from .ManualFramesSelection import ManualFramesSelection
21
14
 
22
15
  _logger = logging.getLogger(__name__)
@@ -55,74 +48,24 @@ class InputWidget(qt.QWidget):
55
48
 
56
49
  # sinogram input
57
50
  self._sinogramGB = qt.QGroupBox(self)
58
- self._sinogramGB.setLayout(qt.QVBoxLayout())
59
- self._standardSinogramOpts = qt.QGroupBox(self)
60
- self._sinogramGB.layout().addWidget(self._standardSinogramOpts)
61
- self._standardSinogramOpts.setLayout(qt.QFormLayout())
62
- self._standardSinogramOpts.layout().setContentsMargins(0, 0, 0, 0)
63
- self._standardSinogramOpts.setTitle("standard options")
51
+ self._sinogramGB.setLayout(qt.QFormLayout())
64
52
 
65
53
  self._sinogramGB.setTitle("sinogram")
66
54
  self._sinogramGB.setCheckable(True)
67
55
  self.layout().addWidget(self._sinogramGB)
68
56
  ## sinogram line
69
57
  self._sinogramLineSB = _SliceSelector(self)
70
- self._standardSinogramOpts.layout().addRow("line", self._sinogramLineSB)
58
+ self._sinogramGB.layout().addRow("line", self._sinogramLineSB)
71
59
  ## sinogram subsampling
72
60
  self._sinogramSubsampling = qt.QSpinBox(self)
73
61
  self._sinogramSubsampling.setRange(1, 1000)
74
62
  self._sinogramSubsampling.setValue(10)
75
- self._standardSinogramOpts.layout().addRow(
76
- "subsampling", self._sinogramSubsampling
77
- )
63
+ self._sinogramGB.layout().addRow("subsampling", self._sinogramSubsampling)
78
64
 
79
65
  self._spacer = qt.QWidget(self)
80
66
  self._spacer.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
81
67
  self.layout().addWidget(self._spacer)
82
68
 
83
- ## options for the composite mode
84
- self._compositeOpts = qt.QGroupBox(self)
85
- self._compositeOpts.setTitle("composite options")
86
- self._sinogramGB.layout().addWidget(self._compositeOpts)
87
- self._compositeOpts.setLayout(qt.QFormLayout())
88
- self._compositeOpts.layout().setContentsMargins(0, 0, 0, 0)
89
- self._thetaSB = qt.QSpinBox(self)
90
- self._thetaSB.setRange(0, 360)
91
- self._thetaSB.setValue(DEFAULT_CMP_THETA)
92
- self._thetaSB.setToolTip("a radio will be picked each theta degres")
93
- self._thetaLabel = qt.QLabel("angle interval (in degree)", self)
94
- self._thetaLabel.setToolTip(
95
- "algorithm will take one projection each 'angle interval'. Also know as 'theta'"
96
- )
97
- self._compositeOpts.layout().addRow(self._thetaLabel, self._thetaSB)
98
-
99
- self._oversamplingSB = qt.QSpinBox(self)
100
- self._oversamplingSB.setValue(DEFAULT_CMP_OVERSAMPLING)
101
- self._oversamplingSB.setToolTip("sinogram oversampling")
102
- self._compositeOpts.layout().addRow("oversampling", self._oversamplingSB)
103
-
104
- self._nearwidthSB = qt.QSpinBox(self)
105
- self._nearwidthSB.setRange(-40000, 40000)
106
- self._nearwidthSB.setValue(0)
107
- self._nearwidthSB.setToolTip("position to be used with near option")
108
- self._nearwidthLabel = qt.QLabel("near width", self)
109
- self._nearwidthLabel.setToolTip("position to be used with near option")
110
- self._compositeOpts.layout().addRow(self._nearwidthLabel, self._nearwidthSB)
111
-
112
- self._subsamplingYSB = qt.QSpinBox(self)
113
- self._subsamplingYSB.setValue(DEFAULT_CMP_N_SUBSAMPLING_Y)
114
- self._subsamplingYSB.setToolTip("sinogram number of subsampling along y")
115
- self._compositeOpts.layout().addRow("n_subsampling_y", self._subsamplingYSB)
116
-
117
- self._takeLogCB = qt.QCheckBox(self)
118
- self._takeLogCB.setToolTip("Take logarithm")
119
- self._takeLogCB.setChecked(DEFAULT_CMP_TAKE_LOG)
120
- self._takeTheLogLabel = qt.QLabel("linearisation (-log(I/I0))")
121
- self._takeTheLogLabel.setToolTip(
122
- "take (-log(I/I0)) as input. Also know as 'take_log' option"
123
- )
124
- self._compositeOpts.layout().addRow(self._takeTheLogLabel, self._takeLogCB)
125
-
126
69
  # set up
127
70
  self._sinogramGB.setChecked(False)
128
71
 
@@ -131,11 +74,6 @@ class InputWidget(qt.QWidget):
131
74
  self._radioGB.toggled.connect(self._radiosChecked)
132
75
  self._sinogramSubsampling.valueChanged.connect(self._changed)
133
76
  self._sinogramLineSB.sigChanged.connect(self._changed)
134
- self._thetaSB.valueChanged.connect(self._changed)
135
- self._oversamplingSB.valueChanged.connect(self._changed)
136
- self._subsamplingYSB.valueChanged.connect(self._changed)
137
- self._nearwidthSB.valueChanged.connect(self._changed)
138
- self._takeLogCB.toggled.connect(self._changed)
139
77
  self._angleModeWidget.sigChanged.connect(self._sigUrlChanged)
140
78
 
141
79
  def setScan(self, scan: TomwerScanBase):
@@ -151,10 +89,11 @@ class InputWidget(qt.QWidget):
151
89
  if axis_params is not None:
152
90
  assert isinstance(axis_params, QAxisRP)
153
91
  with block_signals(self._sinogramGB):
154
- self._sinogramChecked(axis_params.use_sinogram, on_load=True)
92
+ self._sinogramChecked(
93
+ axis_params.mode.requires_sinogram_index(), on_load=True
94
+ )
155
95
  self._sinogramLineSB.setSlice(axis_params.sinogram_line)
156
96
  self._sinogramSubsampling.setValue(axis_params.sinogram_subsampling)
157
- self.setCompositeOptions(axis_params.composite_options)
158
97
  self._angleModeWidget.setAxisParams(axis_params)
159
98
  self._axis_params = axis_params
160
99
 
@@ -202,10 +141,8 @@ class InputWidget(qt.QWidget):
202
141
 
203
142
  def _updateAxisParams(self):
204
143
  if not self._blockUpdateAxisParams:
205
- self._axis_params.use_sinogram = self._sinogramGB.isChecked()
206
144
  self._axis_params.sinogram_line = self.getSinogramLine()
207
145
  self._axis_params.sinogram_subsampling = self.getSinogramSubsampling()
208
- self._axis_params.composite_options = self.getCompositeOptions()
209
146
 
210
147
  def setValidInputs(self, modes: list | tuple):
211
148
  """
@@ -230,102 +167,21 @@ class InputWidget(qt.QWidget):
230
167
  raise ValueError("modes is empty")
231
168
  else:
232
169
  mode = axis_mode._InputType.from_value(modes.pop())
233
- if mode in (axis_mode._InputType.SINOGRAM, axis_mode._InputType.COMPOSITE):
170
+ if mode is axis_mode._InputType.SINOGRAM:
234
171
  self._sinogramGB.setEnabled(True)
235
172
  self._radioGB.setEnabled(False)
236
173
  self._sinogramGB.setChecked(True)
237
- self._compositeOpts.setEnabled(mode is axis_mode._InputType.COMPOSITE)
238
- self._standardSinogramOpts.setEnabled(
239
- mode is not axis_mode._InputType.COMPOSITE
240
- )
241
174
  elif mode is axis_mode._InputType.RADIOS_X2:
242
175
  self._radioGB.setEnabled(True)
243
176
  self._sinogramGB.setEnabled(False)
244
177
  self._radioGB.setChecked(True)
178
+ elif mode is axis_mode._InputType.COMPOSITE:
179
+ # those mode are neither sinogram neither radio. Now one of the two will be checked but without any much meaning
180
+ self._radioGB.setEnabled(False)
181
+ self._sinogramGB.setEnabled(False)
245
182
  else:
246
183
  raise ValueError(f"Nothing implemented for {mode.value}")
247
184
 
248
- def getCompositeOptions(self) -> dict:
249
- return {
250
- "theta": self.getTheta(),
251
- "oversampling": self.getOversampling(),
252
- "n_subsampling_y": self.getSubsamplingY(),
253
- "take_log": self.getTakeLog(),
254
- "near_pos": self.getNearpos(),
255
- "near_width": self.getNearwidth(),
256
- }
257
-
258
- def setCompositeOptions(self, opts: dict) -> None:
259
- if not isinstance(opts, dict):
260
- raise TypeError("opts should be an instance of dict")
261
- for key in opts.keys():
262
- if key not in (
263
- "theta",
264
- "oversampling",
265
- "n_subsampling_y",
266
- "take_log",
267
- "near_pos",
268
- "near_width",
269
- ):
270
- raise KeyError(f"{key} is not recogized")
271
- theta = opts.get("theta", None)
272
- if theta is not None:
273
- self.setTheta(theta=theta)
274
- oversampling = opts.get("oversampling", None)
275
- if oversampling is not None:
276
- self.setOversampling(oversampling)
277
- n_subsampling_y = opts.get("n_subsampling_y", None)
278
- if n_subsampling_y is not None:
279
- self.setSubsamplingY(n_subsampling_y)
280
-
281
- near_width = opts.get("near_width", None)
282
- if near_width is not None:
283
- self.setNearwidth(near_width)
284
-
285
- take_log = opts.get("take_log", None)
286
- if take_log is not None:
287
- self.setTakeLog(take_log)
288
-
289
- def getTheta(self) -> int:
290
- return self._thetaSB.value()
291
-
292
- def setTheta(self, theta: int) -> None:
293
- self._thetaSB.setValue(theta)
294
-
295
- def getOversampling(self) -> int:
296
- return self._oversamplingSB.value()
297
-
298
- def setOversampling(self, oversampling: int) -> None:
299
- self._oversamplingSB.setValue(oversampling)
300
-
301
- def getNearpos(self) -> int:
302
- cal_widget = self.parentWidget().widget(0)
303
- assert isinstance(cal_widget, CalculationWidget)
304
- return cal_widget.getEstimatedCor()
305
-
306
- def setNearpos(self, value) -> int:
307
- cal_widget = self.parentWidget().widget(0)
308
- assert isinstance(cal_widget, CalculationWidget)
309
- cal_widget.setNearPosition(value)
310
-
311
- def getNearwidth(self) -> int:
312
- return self._nearwidthSB.value()
313
-
314
- def setNearwidth(self, value) -> int:
315
- return self._nearwidthSB.setValue(value)
316
-
317
- def getSubsamplingY(self) -> int:
318
- return self._subsamplingYSB.value()
319
-
320
- def setSubsamplingY(self, subsampling: int) -> None:
321
- self._subsamplingYSB.setValue(subsampling)
322
-
323
- def getTakeLog(self) -> bool:
324
- return self._takeLogCB.isChecked()
325
-
326
- def setTakeLog(self, log: bool) -> None:
327
- self._takeLogCB.setChecked(log)
328
-
329
185
 
330
186
  class _AngleSelectionWidget(qt.QWidget):
331
187
  """Group box to select the angle to used for cor calculation
@@ -16,6 +16,10 @@ from silx.gui.plot import items
16
16
  from silx.utils.enum import Enum as _Enum
17
17
  from tomoscan.esrf.scan.utils import get_data
18
18
 
19
+ from tomwer.core.process.reconstruction.utils.cor import (
20
+ absolute_pos_to_relative,
21
+ relative_pos_to_absolute,
22
+ )
19
23
  from tomwer.core.process.reconstruction.saaxis.saaxis import ReconstructionMode
20
24
  from tomwer.core.scan.scanbase import TomwerScanBase
21
25
  from tomwer.gui import icons
@@ -23,6 +27,7 @@ from tomwer.gui.reconstruction.saaxis.sliceselector import SliceSelector
23
27
  from tomwer.gui.utils.lineselector import QSliceSelectorDialog
24
28
  from tomwer.gui.utils.slider import LogSlider
25
29
  from tomwer.gui.visualization.sinogramviewer import SinogramViewer as _SinogramViewer
30
+ from tomwer.gui.fonts import FONT_MEDIUM, FONT_IMPORTANT
26
31
 
27
32
  _logger = logging.getLogger(__name__)
28
33
 
@@ -493,7 +498,9 @@ class _EstimatedCorWidget(qt.QGroupBox):
493
498
  return 0.0
494
499
  elif mode in ("abs", "absolute"):
495
500
  if self._frameWidth is not None:
496
- return (self._frameWidth - 1) / 2.0
501
+ return relative_pos_to_absolute(
502
+ relative_pos=0.0, det_width=self._frameWidth
503
+ )
497
504
  else:
498
505
  return self._MIDDLE_COR_TXT
499
506
  else:
@@ -519,7 +526,9 @@ class _EstimatedCorWidget(qt.QGroupBox):
519
526
  old = self.blockSignals(True)
520
527
  old_mcor = self._manualCORAbs.blockSignals(True)
521
528
  self._manualCORAbs.setValue(
522
- self._manualCORRel.value() + (self._frameWidth - 1) / 2.0
529
+ relative_pos_to_absolute(
530
+ relative_pos=self._manualCORRel.value(), det_width=self._frameWidth
531
+ )
523
532
  )
524
533
  self._manualCORAbs.blockSignals(old_mcor)
525
534
  self.blockSignals(old)
@@ -529,7 +538,10 @@ class _EstimatedCorWidget(qt.QGroupBox):
529
538
  old = self.blockSignals(True)
530
539
  old_mcor = self._manualCORRel.blockSignals(True)
531
540
  self._manualCORRel.setValue(
532
- self._manualCORAbs.value() - (self._frameWidth - 1) / 2.0
541
+ absolute_pos_to_relative(
542
+ absolute_pos=self._manualCORAbs.value(),
543
+ det_width=self._frameWidth,
544
+ )
533
545
  )
534
546
  self._manualCORRel.blockSignals(old_mcor)
535
547
  self.blockSignals(old)
@@ -582,15 +594,12 @@ class SAAxisOptions(qt.QWidget):
582
594
  sigConfigurationChanged = qt.Signal()
583
595
  """signal emitted when the configuration change"""
584
596
 
585
- _FONT_IMPORTANT = qt.QFont("Arial", 12)
586
- _FONT_MEDIUM = qt.QFont("Arial", 10)
587
-
588
597
  def __init__(self, parent=None):
589
598
  qt.QWidget.__init__(self, parent)
590
599
  self.setLayout(qt.QVBoxLayout())
591
600
  # reconstruction mode
592
601
  self._reconstructionMode = _ReconstructionModeGB(parent=self)
593
- self._reconstructionMode.setFont(self._FONT_MEDIUM)
602
+ self._reconstructionMode.setFont(FONT_MEDIUM)
594
603
  self.layout().addWidget(self._reconstructionMode)
595
604
 
596
605
  # estimated cor
@@ -598,12 +607,12 @@ class SAAxisOptions(qt.QWidget):
598
607
  self,
599
608
  title="Estimated cor position (x axis)",
600
609
  )
601
- self._estimatedCorWidget.setFont(self._FONT_IMPORTANT)
610
+ self._estimatedCorWidget.setFont(FONT_IMPORTANT)
602
611
  self.layout().addWidget(self._estimatedCorWidget)
603
612
 
604
613
  # detection accuracy
605
614
  self._detectionAccuracy = _DetectionAccuracyGB(parent=self)
606
- self._detectionAccuracy.setFont(self._FONT_MEDIUM)
615
+ self._detectionAccuracy.setFont(FONT_MEDIUM)
607
616
  self.layout().addWidget(self._detectionAccuracy)
608
617
 
609
618
  # number of reconstructions eq volume size
@@ -613,7 +622,7 @@ class SAAxisOptions(qt.QWidget):
613
622
  self._nReconsSB = qt.QSpinBox(self._nReconsWidget)
614
623
  self._nReconsSB.setRange(0, 2000)
615
624
  self._nReconsSB.setValue(30)
616
- self._nReconsWidget.setFont(self._FONT_IMPORTANT)
625
+ self._nReconsWidget.setFont(FONT_IMPORTANT)
617
626
  self._nReconsWidget.layout().addRow("Number of reconstruction", self._nReconsSB)
618
627
  self.layout().addWidget(self._nReconsWidget)
619
628
 
@@ -14,6 +14,7 @@ from matplotlib import image as _matplotlib_image
14
14
  from silx.gui import qt
15
15
  from silx.gui.plot import PlotWidget
16
16
 
17
+ from tomwer.core.process.reconstruction.utils.cor import relative_pos_to_absolute
17
18
  from tomwer.core.process.reconstruction.scores.params import ScoreMethod
18
19
  from tomwer.gui import icons, settings
19
20
  from tomwer.gui.reconstruction.saaxis.dimensionwidget import DimensionWidget
@@ -307,7 +308,9 @@ class CorSelection(VariableSelection):
307
308
  if relative_value is None or self._img_width is None:
308
309
  self._absoluteVarValueLE.clear()
309
310
  else:
310
- absolute_value = relative_value + (self._img_width - 1) / 2.0
311
+ absolute_value = relative_pos_to_absolute(
312
+ relative_pos=relative_value, det_width=self._img_width
313
+ )
311
314
  self._absoluteVarValueLE.setText(f"{absolute_value:.3f}")
312
315
 
313
316
  def getWindowTitle(self):
@@ -422,7 +425,7 @@ class _VariableValueLabels(qt.QWidget):
422
425
  # paint oblique text
423
426
  with PainterRotationCM(
424
427
  painter=painter,
425
- x=var_px_pos + self._slider_ticks_margin / 2.0,
428
+ x=var_px_pos + (self._slider_ticks_margin / 2.0),
426
429
  y=0,
427
430
  angle=self.rotation_angle_degree,
428
431
  ) as l_painter:
@@ -19,8 +19,11 @@ from tomwer.gui.reconstruction.nabu.nabuconfig.reconstruction import (
19
19
  )
20
20
  from tomwer.gui.reconstruction.nabu.nabuflow import NabuFlowControl
21
21
  from tomwer.gui.reconstruction.nabu.volume import NabuVolumeTabWidget
22
+ from tomwer.gui.reconstruction.axis.EstimatedCORWidget import EstimatedCORWidget
22
23
  from tomwer.tests.utils import skip_gui_test
23
24
  from tomwer.core.process.output import ProcessDataOutputDirMode
25
+ from tomwer.tests.conftest import qtapp # noqa F401
26
+ from tomwer.synctools.axis import QAxisRP
24
27
 
25
28
 
26
29
  class ProcessClass:
@@ -356,3 +359,8 @@ class TestNabuVolumeWidget(TestCaseQt):
356
359
  }
357
360
  )
358
361
  self.assertEqual(self.nabuWidget.getConfiguration(), conf)
362
+
363
+
364
+ def test_EstimatedCorWidget(qtapp): # noqa F811
365
+ """test of EstimatedCorWidget"""
366
+ EstimatedCORWidget(parent=None, axis_params=QAxisRP())
@@ -73,7 +73,7 @@ class Axis_N_Params(qt.QGroupBox):
73
73
 
74
74
  class AutoRefineWidget(qt.QWidget):
75
75
  """
76
- widget grouping information not specific to objects (output file, stithcing strategy...)
76
+ widget grouping information not specific to objects (output file, stitching strategy...)
77
77
  """
78
78
 
79
79
  def __init__(self, parent=None):
@@ -1,4 +1,5 @@
1
1
  import pytest
2
+ import numpy
2
3
 
3
4
  from tomwer.gui.reconstruction.axis.AxisSettingsWidget import AxisSettingsTabWidget
4
5
  from tomwer.synctools.axis import QAxisRP
@@ -10,18 +11,33 @@ from tomwer.tests.conftest import qtapp # noqa F401
10
11
  def test_get_nabu_cor_opts(qtapp): # noqa F811
11
12
  axis_params = QAxisRP()
12
13
  widget = AxisSettingsTabWidget(recons_params=axis_params)
13
- assert axis_params.get_nabu_cor_options_as_str() == "side='right'"
14
- widget._calculationWidget._corOpts.setText("low_pass=2")
15
- widget._calculationWidget._corOpts.editingFinished.emit()
16
- assert axis_params.get_nabu_cor_options_as_str() == "side='right' ; low_pass=2"
17
- widget._calculationWidget._corOpts.setText("low_pass=2 ; high_pass=10")
18
- widget._calculationWidget._corOpts.editingFinished.emit()
19
- assert axis_params.get_nabu_cor_options_as_str() == (
20
- "side='right' ; low_pass=2 ; high_pass=10"
21
- )
22
- widget._calculationWidget._sideCB.setCurrentText("left")
23
- widget._calculationWidget._corOpts.editingFinished.emit()
24
- assert (
25
- axis_params.get_nabu_cor_options_as_str()
26
- == "side='left' ; low_pass=2 ; high_pass=10"
27
- )
14
+ assert axis_params.get_nabu_cor_options_as_dict() == {
15
+ "side": "right",
16
+ "radio_angles": (0.0, numpy.pi),
17
+ "slice_idx": "middle",
18
+ }
19
+ widget._optionsWidget._corOpts.setText("low_pass=2.0")
20
+ widget._optionsWidget._corOpts.editingFinished.emit()
21
+ assert axis_params.get_nabu_cor_options_as_dict() == {
22
+ "side": "right",
23
+ "radio_angles": (0.0, numpy.pi),
24
+ "slice_idx": "middle",
25
+ "low_pass": 2.0,
26
+ }
27
+ widget._optionsWidget._corOpts.setText("low_pass=2 ; high_pass=10")
28
+ widget._optionsWidget._corOpts.editingFinished.emit()
29
+ assert axis_params.get_nabu_cor_options_as_dict() == {
30
+ "side": "right",
31
+ "radio_angles": (0.0, numpy.pi),
32
+ "slice_idx": "middle",
33
+ "low_pass": 2.0,
34
+ "high_pass": 10.0,
35
+ }
36
+ widget._calculationWidget.setEstimatedCorValue("left")
37
+ assert axis_params.get_nabu_cor_options_as_dict() == {
38
+ "side": "left",
39
+ "radio_angles": (0.0, numpy.pi),
40
+ "slice_idx": "middle",
41
+ "low_pass": 2.0,
42
+ "high_pass": 10.0,
43
+ }
@@ -23,7 +23,7 @@ _logger = logging.getLogger(__name__)
23
23
 
24
24
 
25
25
  class AxisProcessStack(FIFO, qt.QObject):
26
- """Implementation of the `.AxisProcess` but having a stack for treating
26
+ """Implementation of the `.AxisTask` but having a stack for treating
27
27
  scans and making computation in threads"""
28
28
 
29
29
  def __init__(self, axis_params, process_id=None):
@@ -55,7 +55,7 @@ class AxisProcessStack(FIFO, qt.QObject):
55
55
  if callback is not None:
56
56
  callback()
57
57
  self.scan_ready(scan=data)
58
- elif not self._axis_params.use_sinogram and mode in (AxisMode.manual,):
58
+ elif mode is (AxisMode.manual,):
59
59
  # if cor is not set then set it to 0 (can be the case if no)
60
60
  # interaction has been dne
61
61
  cor = self._axis_params.relative_cor_value
@@ -84,14 +84,6 @@ class AxisProcessStack(FIFO, qt.QObject):
84
84
  # we will keep the actual one (should have been defined previously)
85
85
  self._end_computation(data=data, future_tomo_obj=None, callback=callback)
86
86
 
87
- elif (
88
- not self._axis_params.use_sinogram
89
- and mode not in AxisTask._CALCULATIONS_METHODS
90
- ):
91
- _logger.warning(f"no method defined to compute {mode}")
92
- if callback is not None:
93
- callback()
94
- self._process_next()
95
87
  else:
96
88
  _logger.processStarted(
97
89
  f"Start cor calculation on {data} ({self._axis_params.get_simple_str()})"
@@ -113,7 +105,7 @@ class AxisProcessStack(FIFO, qt.QObject):
113
105
  """
114
106
  assert isinstance(data, TomwerScanBase)
115
107
  assert self._axis_params is not None
116
- # copy result computed on scan on the AxisProcess reconsparams
108
+ # copy result computed on scan on the AxisTask reconsparams
117
109
  self._axis_params.set_relative_value(
118
110
  data.axis_params.relative_cor_value
119
111
  ) # noqa
@@ -167,23 +159,13 @@ class _ProcessingThread(ProcessingThread, SuperviseProcess):
167
159
  },
168
160
  process_id=self.process_id,
169
161
  )
170
- axis = self.apply_patch(axis=axis)
171
162
  try:
172
163
  axis.run()
173
164
  except NoAxisUrl as e:
174
165
  self.center_of_rotation = None
175
- _logger.error(str(e))
166
+ _logger.error(f"CoR calculation failed. Issue with input ({e})")
176
167
  except Exception as e:
177
- _logger.error(str(e))
168
+ _logger.error(f"CoR calculation failed ({e})", stack_info=True)
178
169
  self.center_of_rotation = None
179
170
  else:
180
171
  self.center_of_rotation = self._scan.axis_params.relative_cor_value
181
-
182
- def patch_calc_method(self, mode, function):
183
- self.__patch[mode] = function
184
-
185
- def apply_patch(self, axis):
186
- for mode, patch_fct in self.__patch.items():
187
- if mode in AxisMode:
188
- axis._CALCULATIONS_METHODS[mode] = patch_fct
189
- return axis
@@ -23,7 +23,7 @@ _logger = logging.getLogger(__name__)
23
23
 
24
24
 
25
25
  class DarkRefCopyProcessStack(FIFO, qt.QObject):
26
- """Implementation of the `.AxisProcess` but having a stack for treating
26
+ """Implementation of the `.AxisTask` but having a stack for treating
27
27
  scans and making computation in threads"""
28
28
 
29
29
  sigRefSetted = qt.Signal(str)
@@ -21,7 +21,7 @@ _logger = logging.getLogger(__name__)
21
21
 
22
22
 
23
23
  class NabuSliceProcessStack(FIFO, qt.QObject):
24
- """Implementation of the `.AxisProcess` but having a stack for treating
24
+ """Implementation of the `.AxisTask` but having a stack for treating
25
25
  scans and making computation in threads"""
26
26
 
27
27
  def __init__(self, parent=None, process_id=None):
@@ -78,7 +78,7 @@ class NabuSliceProcessStack(FIFO, qt.QObject):
78
78
 
79
79
 
80
80
  class NabuVolumeProcessStack(NabuSliceProcessStack):
81
- """Implementation of the `.AxisProcess` but having a stack for treating
81
+ """Implementation of the `.AxisTask` but having a stack for treating
82
82
  scans and making computation in threads"""
83
83
 
84
84
  def _create_processing_thread(self, process_id=None) -> qt.QThread:
@@ -20,7 +20,7 @@ _logger = logging.getLogger(__name__)
20
20
 
21
21
 
22
22
  class INormalizationProcessStack(FIFO, qt.QObject):
23
- """Implementation of the `.AxisProcess` but having a stack for treating
23
+ """Implementation of the `.AxisTask` but having a stack for treating
24
24
  scans and making computation in threads"""
25
25
 
26
26
  def __init__(self, process_id=None):
@@ -22,7 +22,7 @@ _logger = logging.getLogger(__name__)
22
22
 
23
23
 
24
24
  class SAAxisProcessStack(FIFO, qt.QObject):
25
- """Implementation of the `.AxisProcess` but having a stack for treating
25
+ """Implementation of the `.AxisTask` but having a stack for treating
26
26
  scans and making computation in threads"""
27
27
 
28
28
  def __init__(self, saaxis_params, process_id=None):
@@ -24,7 +24,7 @@ _logger = logging.getLogger(__name__)
24
24
 
25
25
 
26
26
  class SADeltaBetaProcessStack(FIFO, qt.QObject):
27
- """Implementation of the `.AxisProcess` but having a stack for treating
27
+ """Implementation of the `.AxisTask` but having a stack for treating
28
28
  scans and making computation in threads"""
29
29
 
30
30
  def __init__(self, sa_delta_beta_params, process_id=None):
@@ -179,22 +179,6 @@ class TestAxisStack(TestCaseQt):
179
179
  self.assertEqual(self._scan2.axis_params, None)
180
180
  self.assertEqual(self._scan3.axis_params, None)
181
181
 
182
- def testUnlockStack(self):
183
- """Check that all axis position will be computed properly if we set a
184
- stack of scan"""
185
- self._mainWindow.recons_params.set_relative_value(1.0)
186
- for scan in (self._scan1, self._scan2, self._scan3):
187
- self._mainWindow.process(scan)
188
-
189
- for i in range(5):
190
- self.qapp.processEvents()
191
- time.sleep(0.2)
192
- self.qapp.processEvents()
193
-
194
- self.assertNotEqual(self._scan1.axis_params, None)
195
- self.assertNotEqual(self._scan2.axis_params, None)
196
- self.assertNotEqual(self._scan3.axis_params, None)
197
-
198
182
  def testLockStack(self):
199
183
  """Check that axis position will be simply copy if we are in a lock
200
184
  stack"""
@@ -37,7 +37,7 @@ pytest.mark.skipif(condition=not has_nabu, reason="nabu not installed")
37
37
 
38
38
  classes_to_test = {
39
39
  "darkref": "tomwer.core.process.reconstruction.darkref.darkrefs.DarkRefs",
40
- "axis": "tomwer.core.process.reconstruction.axis.axis.AxisProcess",
40
+ "axis": "tomwer.core.process.reconstruction.axis.axis.AxisTask",
41
41
  "nabu slices": "tomwer.core.process.reconstruction.nabu.nabuslices.NabuSlices",
42
42
  }
43
43
 
@@ -55,7 +55,7 @@ def test_simple_workflow_nabu():
55
55
  {
56
56
  "id": "axis",
57
57
  "task_type": "class",
58
- "task_identifier": "tomwer.core.process.reconstruction.axis.axis.AxisProcess",
58
+ "task_identifier": "tomwer.core.process.reconstruction.axis.axis.AxisTask",
59
59
  "default_inputs": [
60
60
  {
61
61
  "name": "axis_params",
tomwer/version.py CHANGED
@@ -79,7 +79,7 @@ MAJOR = 1
79
79
  MINOR = 4
80
80
  MICRO = 0
81
81
  RELEV = "rc" # <16
82
- SERIAL = 0 # <16
82
+ SERIAL = 1 # <16
83
83
 
84
84
  date = __date__
85
85
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tomwer
3
- Version: 1.4.0rc0
3
+ Version: 1.4.0rc1
4
4
  Summary: "tomography workflow tools"
5
5
  Home-page: https://gitlab.esrf.fr/tomotools/tomwer
6
6
  Author: Henri Payno, Pierre Paleo, Pierre-Olivier Autran, Jérôme Lesaint, Alessandro Mirone
@@ -28,7 +28,7 @@ Requires-Dist: silx[full]>=2.0
28
28
  Requires-Dist: tomoscan>=2.1.0a18
29
29
  Requires-Dist: nxtomo>=1.3.0dev4
30
30
  Requires-Dist: nxtomomill>=1.1.0a0
31
- Requires-Dist: processview>=1.3
31
+ Requires-Dist: processview>=1.4.3
32
32
  Requires-Dist: ewoks>=0.1.1
33
33
  Requires-Dist: sluurp>=0.4.0
34
34
  Requires-Dist: packaging