orGUI 1.0.1__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 (83) hide show
  1. orGUI-1.0.1.dist-info/LICENSE +21 -0
  2. orGUI-1.0.1.dist-info/METADATA +147 -0
  3. orGUI-1.0.1.dist-info/RECORD +83 -0
  4. orGUI-1.0.1.dist-info/WHEEL +5 -0
  5. orGUI-1.0.1.dist-info/entry_points.txt +2 -0
  6. orGUI-1.0.1.dist-info/top_level.txt +1 -0
  7. orgui/__init__.py +36 -0
  8. orgui/app/ArrayTableDialog.py +433 -0
  9. orgui/app/QReflectionSelector.py +538 -0
  10. orgui/app/QScanSelector.py +692 -0
  11. orgui/app/QUBCalculator.py +1210 -0
  12. orgui/app/__init__.py +36 -0
  13. orgui/app/database.py +487 -0
  14. orgui/app/orGUI.py +2613 -0
  15. orgui/app/qutils.py +51 -0
  16. orgui/backend/__init__.py +32 -0
  17. orgui/backend/backends.py +157 -0
  18. orgui/backend/beamline/ID31DiffractLinTilt.py +77 -0
  19. orgui/backend/beamline/P212_tools.py +577 -0
  20. orgui/backend/beamline/__init__.py +36 -0
  21. orgui/backend/beamline/fio_reader.py +110 -0
  22. orgui/backend/beamline/id31_tools.py +651 -0
  23. orgui/backend/scans.py +95 -0
  24. orgui/backend/udefaults.py +163 -0
  25. orgui/backend/universalScanLoader.py +105 -0
  26. orgui/datautils/__init__.py +32 -0
  27. orgui/datautils/util.py +705 -0
  28. orgui/datautils/xrayutils/CTRcalc.py +3022 -0
  29. orgui/datautils/xrayutils/CTRopt.py +623 -0
  30. orgui/datautils/xrayutils/CTRplotutil.py +904 -0
  31. orgui/datautils/xrayutils/DetectorCalibration.py +685 -0
  32. orgui/datautils/xrayutils/HKLVlieg.py +1360 -0
  33. orgui/datautils/xrayutils/ReciprocalNavigation.py +401 -0
  34. orgui/datautils/xrayutils/_CTRcalc_accel.py +181 -0
  35. orgui/datautils/xrayutils/__init__.py +46 -0
  36. orgui/datautils/xrayutils/element_data.py +213 -0
  37. orgui/datautils/xrayutils/test/__init__.py +57 -0
  38. orgui/datautils/xrayutils/test/test_CTRcalc.py +152 -0
  39. orgui/datautils/xrayutils/test/test_DetectorCalibration.py +336 -0
  40. orgui/datautils/xrayutils/test/test_HKLcalc.py +88 -0
  41. orgui/datautils/xrayutils/unitcells/Fe3O4(100).bul +59 -0
  42. orgui/datautils/xrayutils/unitcells/Pt100.bul +7 -0
  43. orgui/datautils/xrayutils/unitcells/Pt100_small.bul +5 -0
  44. orgui/datautils/xrayutils/unitcells/Pt110.bul +5 -0
  45. orgui/datautils/xrayutils/unitcells/Pt111.bul +6 -0
  46. orgui/datautils/xrayutils/unitcells/Pt310.bul +13 -0
  47. orgui/datautils/xrayutils/unitcells/Pt3O4(100).bul +19 -0
  48. orgui/datautils/xrayutils/unitcells/PtO(001).bul +9 -0
  49. orgui/datautils/xrayutils/unitcells/PtO(010).bul +9 -0
  50. orgui/datautils/xrayutils/unitcells/PtO(100).bul +9 -0
  51. orgui/datautils/xrayutils/unitcells/__init__.py +67 -0
  52. orgui/datautils/xrayutils/unitcells/a-PtO2(0001).bul +6 -0
  53. orgui/main.py +101 -0
  54. orgui/resources/__init__.py +40 -0
  55. orgui/resources/icons/alpha.png +0 -0
  56. orgui/resources/icons/alpha.svg +67 -0
  57. orgui/resources/icons/diffractometer_v3.png +0 -0
  58. orgui/resources/icons/disable-image.png +0 -0
  59. orgui/resources/icons/disable-image.svg +68 -0
  60. orgui/resources/icons/document-nx-open.png +0 -0
  61. orgui/resources/icons/document-nx-open.svg +152 -0
  62. orgui/resources/icons/document-nx-save.png +0 -0
  63. orgui/resources/icons/document-nx-save.svg +73 -0
  64. orgui/resources/icons/logo.png +0 -0
  65. orgui/resources/icons/logo.svg +808 -0
  66. orgui/resources/icons/max_image.png +0 -0
  67. orgui/resources/icons/max_image.svg +77 -0
  68. orgui/resources/icons/max_image2.png +0 -0
  69. orgui/resources/icons/max_image2.svg +83 -0
  70. orgui/resources/icons/search-image.png +0 -0
  71. orgui/resources/icons/search-image.svg +94 -0
  72. orgui/resources/icons/search-reflection.png +0 -0
  73. orgui/resources/icons/search-reflection.svg +126 -0
  74. orgui/resources/icons/search.png +0 -0
  75. orgui/resources/icons/search.svg +91 -0
  76. orgui/resources/icons/select-image.png +0 -0
  77. orgui/resources/icons/select-image.svg +60 -0
  78. orgui/resources/icons/set-reflection.png +0 -0
  79. orgui/resources/icons/set-reflection.svg +91 -0
  80. orgui/resources/icons/sum_image.png +0 -0
  81. orgui/resources/icons/sum_image.svg +63 -0
  82. orgui/resources/icons/sum_image2.png +0 -0
  83. orgui/resources/icons/sum_image2.svg +75 -0
orgui/app/orGUI.py ADDED
@@ -0,0 +1,2613 @@
1
+ # -*- coding: utf-8 -*-
2
+ # /*##########################################################################
3
+ #
4
+ # Copyright (c) 2020-2024 Timo Fuchs
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #
24
+ # ###########################################################################*/
25
+ __author__ = "Timo Fuchs"
26
+ __credits__ = ['Finn Schroeter']
27
+ __copyright__ = "Copyright 2020-2024 Timo Fuchs"
28
+ __license__ = "MIT License"
29
+ __version__ = "1.0.0"
30
+ __maintainer__ = "Timo Fuchs"
31
+ __email__ = "fuchs@physik.uni-kiel.de"
32
+
33
+
34
+ import sys
35
+ import os
36
+ from silx.gui import qt
37
+ import warnings
38
+
39
+ from io import StringIO
40
+ import concurrent.futures
41
+ import queue
42
+ import threading
43
+
44
+ #from IPython import embed
45
+ import silx.gui.plot
46
+ from silx.gui.plot import items
47
+ from silx.gui.colors import Colormap
48
+ import weakref
49
+
50
+ #from silx import sx
51
+
52
+ import silx
53
+ from silx.utils.weakref import WeakMethodProxy
54
+ from silx.gui.plot.Profile import ProfileToolBar
55
+ from silx.gui.plot.AlphaSlider import NamedImageAlphaSlider
56
+ from silx.gui.dialog import ImageFileDialog
57
+ from silx.gui.plot.tools.roi import RegionOfInterestManager
58
+ from silx.gui.plot.tools.roi import RegionOfInterestTableWidget
59
+ from silx.gui.plot.items.roi import RectangleROI, PolygonROI, ArcROI
60
+ from silx.gui.plot.actions import control as control_actions
61
+
62
+ try:
63
+ from silx.gui import console
64
+ except:
65
+ console = False
66
+
67
+ import traceback
68
+
69
+ from . import qutils
70
+ from .QScanSelector import QScanSelector
71
+ from .QReflectionSelector import QReflectionSelector, QReflectionAnglesDialog
72
+ from .QUBCalculator import QUBCalculator
73
+ from .ArrayTableDialog import ArrayTableDialog
74
+ from .database import DataBase
75
+ from ..backend.scans import SimulationScan
76
+ from ..backend import backends
77
+ from ..backend import universalScanLoader
78
+ from .. import resources
79
+
80
+ import numpy as np
81
+ from ..datautils.xrayutils import HKLVlieg, CTRcalc
82
+ from ..datautils.xrayutils import ReciprocalNavigation as rn
83
+ import pyFAI.detectors
84
+
85
+ import sys
86
+ #legacy import:
87
+ from ..backend.beamline.id31_tools import BlissScan_EBS, Fastscan, BlissScan
88
+
89
+ QTVERSION = qt.qVersion()
90
+ DEBUG = 0
91
+
92
+ silx.config.DEFAULT_PLOT_SYMBOL = '.'
93
+
94
+
95
+ class orGUI(qt.QMainWindow):
96
+ def __init__(self,configfile,parent=None):
97
+ qt.QMainWindow.__init__(self, parent)
98
+ self.h5database = None # must be a h5py file-like, by default not opened to avoid reading issues at beamtimes!
99
+ self.images_loaded = False
100
+ self.resetZoom = True
101
+ #icon = resources.getQicon("sum_image.svg")
102
+ self.fscan = None
103
+ self.activescanname = "scan"
104
+ self.numberthreads = int(min(os.cpu_count(), 8)) if os.cpu_count() is not None else 1
105
+ if 'SLURM_CPUS_ON_NODE' in os.environ:
106
+ self.numberthreads = int(os.environ['SLURM_CPUS_ON_NODE'])
107
+
108
+ self.filedialogdir = os.getcwd()
109
+
110
+ self.excludedImagesDialog = ArrayTableDialog(True, 1)
111
+ self.excludedImagesDialog.setArrayData(np.array([-1]),editable=True, header= ['image no'])
112
+
113
+
114
+ self.centralPlot = Plot2DHKL(self.newXyHKLConverter(),parent=self)
115
+ self.centralPlot.setDefaultColormap(Colormap(name='jet',normalization='log'))
116
+ self.centralPlot.setCallback(self._graphCallback)
117
+ toolbar = qt.QToolBar()
118
+ toolbar.addAction(control_actions.OpenGLAction(parent=toolbar, plot=self.centralPlot))
119
+ self.centralPlot.addToolBar(toolbar)
120
+
121
+ self.currentImageLabel = None
122
+ self.currentAddImageLabel = None
123
+
124
+ selectorDock = qt.QDockWidget("Scan data")
125
+ selectorDock.setAllowedAreas(qt.Qt.LeftDockWidgetArea | qt.Qt.RightDockWidgetArea)
126
+ self.scanSelector = QScanSelector(self)
127
+ selectorDock.setWidget(self.scanSelector)
128
+ self.addDockWidget(qt.Qt.LeftDockWidgetArea,selectorDock)
129
+
130
+ self.imagepath = ''
131
+ self.imageno = 0
132
+
133
+
134
+ ubWidget = qt.QSplitter(qt.Qt.Vertical)
135
+ ubWidget.setChildrenCollapsible(False)
136
+ #ubLayout = qt.QVBoxLayout()
137
+ self.ubcalc = QUBCalculator(configfile, self)
138
+ self.ubcalc.sigNewReflection.connect(self._onNewReflection)
139
+
140
+
141
+
142
+ maincentralwidget = qt.QTabWidget()
143
+
144
+ self.integrdataPlot = silx.gui.plot.Plot1D(self)
145
+ legendwidget = self.integrdataPlot.getLegendsDockWidget()
146
+
147
+ toolbar = qt.QToolBar()
148
+ toolbar.addAction(control_actions.OpenGLAction(parent=toolbar, plot=self.integrdataPlot))
149
+ self.integrdataPlot.addToolBar(toolbar)
150
+
151
+ self.integrdataPlot.addDockWidget(qt.Qt.RightDockWidgetArea,legendwidget)
152
+ legendwidget.show()
153
+ self.database = DataBase(self.integrdataPlot)
154
+ dbdockwidget = qt.QDockWidget("Integrated data")
155
+ dbdockwidget.setWidget(self.database)
156
+
157
+ self.integrdataPlot.addDockWidget(qt.Qt.RightDockWidgetArea,dbdockwidget)
158
+
159
+
160
+ self.scanSelector.sigImageNoChanged.connect(self._onSliderValueChanged)
161
+
162
+ self.scanSelector.sigImagePathChanged.connect(self._onImagePathChanged)
163
+ self.scanSelector.sigScanChanged.connect(self._onScanChanged)
164
+
165
+ self.scanSelector.showMaxAct.toggled.connect(self._onMaxToggled)
166
+ self.scanSelector.showSumAct.toggled.connect(self._onSumToggled)
167
+
168
+ self.scanSelector.sigROIChanged.connect(self.updateROI)
169
+ self.scanSelector.sigROIintegrate.connect(self.integrateROI)
170
+ self.scanSelector.sigSearchHKL.connect(self.onSearchHKLforStaticROI)
171
+
172
+ self.scanSelector.excludeImageAct.toggled.connect(self._onToggleExcludeImage)
173
+
174
+
175
+ toolbar = self.scanSelector.getScanToolbar()
176
+
177
+
178
+ self.centralPlot.addToolBar(qt.Qt.BottomToolBarArea,toolbar)
179
+
180
+ maincentralwidget.addTab(self.centralPlot,"Scan Image browser")
181
+ maincentralwidget.addTab(self.integrdataPlot,"ROI integrated data")
182
+
183
+ self.setCentralWidget(maincentralwidget)
184
+
185
+
186
+ # Create the object controlling the ROIs and set it up
187
+ self.roiManager = RegionOfInterestManager(self.centralPlot)
188
+ self.roiManager.setColor('pink') # Set the color of ROI
189
+
190
+ #self.roiTable = RegionOfInterestTableWidget()
191
+ #self.roiTable.setRegionOfInterestManager(self.roiManager)
192
+
193
+ #roi order: left, top, right, bottom, croi
194
+ self.rois = []
195
+ for i in range(5):
196
+
197
+ roi = RectangleROI()
198
+ roi.setGeometry(origin=(0, 0), size=(0, 0))
199
+ if i == 4:
200
+ roi.setColor('red') # center color
201
+ else:
202
+ roi.setColor('pink') # bg color
203
+
204
+ #roi.setEditable(False)
205
+ roi.setLineWidth(2)
206
+ roi.setLineStyle('-')
207
+ roi.setVisible(True)
208
+
209
+ self.roiManager.addRoi(roi,useManagerColor=False)
210
+ self.rois.append(roi)
211
+
212
+ #self.reflTable.view._model.dataChanged.connect(printmodel)
213
+ #self.reflTable.setArrayData(np.array([0,0,0,0,10,10],dtype=np.float64))
214
+ ubDock = qt.QDockWidget("Reciprocal space navigation")
215
+ ubDock.setAllowedAreas(qt.Qt.LeftDockWidgetArea | qt.Qt.RightDockWidgetArea | qt.Qt.BottomDockWidgetArea)
216
+
217
+ self.reflectionSel = QReflectionSelector(self.centralPlot, self.ubcalc, self)
218
+ self.reflectionSel.sigQueryImageChange.connect(self._onChangeImage)
219
+
220
+ self.ubcalc.setReflectionHandler(self.getReflections)
221
+
222
+ self.ubcalc.sigPlottableMachineParamsChanged.connect(self._onPlotMachineParams)
223
+ self.ubcalc.sigReplotRequest.connect(self.updatePlotItems)
224
+ self.allimgsum = None
225
+ self.allimgmax = None
226
+
227
+ ubWidget.addWidget(self.reflectionSel)
228
+ ubWidget.addWidget(self.ubcalc)
229
+
230
+
231
+ #ubWidget.setLayout(ubLayout)
232
+ ubDock.setWidget(ubWidget)
233
+ self.centralPlot.addDockWidget(qt.Qt.RightDockWidgetArea,ubDock)
234
+
235
+
236
+
237
+ menu_bar = qt.QMenuBar()
238
+ file = menu_bar.addMenu("&File")
239
+ file.addAction(self.scanSelector.openFileAction)
240
+ file.addAction(self.scanSelector.refreshFileAction)
241
+ file.addAction(self.scanSelector.closeFileAction)
242
+ file.addSeparator()
243
+
244
+ self.folderToScan = file.addAction("Generate scan from images")
245
+ self.folderToScan.triggered.connect(self._onLoadScanFromImages)
246
+ file.addSeparator()
247
+
248
+ self.loadImagesAct = file.addAction("reload images")
249
+ self.loadImagesAct.triggered.connect(self._onLoadAll)
250
+
251
+ config_menu = menu_bar.addMenu("&Config")
252
+ loadConfigAct = qt.QAction("Load config",self) # connected with UBCalculator below
253
+ #loadXtalAct = qt.QAction("Load Crystal file",self)
254
+ machineParamsAct = qt.QAction("Machine parameters",self)
255
+ machineParamsAct.setCheckable(True)
256
+ xtalParamsAct = qt.QAction("Crystal parameters",self)
257
+ xtalParamsAct.setCheckable(True)
258
+ cpucountAct = qt.QAction("Set CPU count",self)
259
+
260
+
261
+ loadConfigAct.triggered.connect(self.ubcalc._onLoadConfig)
262
+ machineParamsAct.toggled.connect(lambda checked: self.ubcalc.machineDialog.setVisible(checked))
263
+ self.ubcalc.machineDialog.sigHide.connect(lambda : machineParamsAct.setChecked(False))
264
+
265
+ xtalParamsAct.toggled.connect(lambda checked: self.ubcalc.xtalDialog.setVisible(checked))
266
+ self.ubcalc.xtalDialog.sigHide.connect(lambda : xtalParamsAct.setChecked(False))
267
+
268
+ cpucountAct.triggered.connect(self._onSelectCPUcount)
269
+
270
+ self.autoLoadAct = qt.QAction("Auto load scans",self)
271
+ self.autoLoadAct.setCheckable(True)
272
+ self.autoLoadAct.setChecked(True)
273
+
274
+ self.showExcludedImagesAct = qt.QAction("Excluded images",self)
275
+ self.showExcludedImagesAct.setCheckable(True)
276
+ self.showExcludedImagesAct.toggled.connect(lambda visible : self.excludedImagesDialog.setVisible(visible))
277
+
278
+
279
+
280
+ config_menu.addAction(loadConfigAct)
281
+ #config_menu.addAction(loadXtalAct)
282
+ config_menu.addSeparator()
283
+ config_menu.addAction(machineParamsAct)
284
+ config_menu.addAction(xtalParamsAct)
285
+ config_menu.addSeparator()
286
+ config_menu.addAction(cpucountAct)
287
+ config_menu.addAction(self.autoLoadAct)
288
+ config_menu.addAction(self.showExcludedImagesAct)
289
+
290
+ view_menu = menu_bar.addMenu("&View")
291
+ showRefReflectionsAct = view_menu.addAction("reference reflections")
292
+ showRefReflectionsAct.setCheckable(True)
293
+ showRefReflectionsAct.setChecked(True)
294
+ showRefReflectionsAct.toggled.connect(lambda checked: self.reflectionSel.setReferenceReflectionsVisible(checked))
295
+
296
+ showBraggAct = view_menu.addAction("allowed Bragg reflections")
297
+ showBraggAct.setCheckable(True)
298
+ showBraggAct.setChecked(False)
299
+ showBraggAct.toggled.connect(self.onShowBragg)
300
+
301
+ showROIAct = view_menu.addAction("show ROI")
302
+ showROIAct.setCheckable(True)
303
+ showROIAct.setChecked(False)
304
+ showROIAct.toggled.connect(self.onShowROI)
305
+ self.roivisible = False
306
+ #self.scanSelector.showROICheckBox.addAction(showROIAct)
307
+
308
+ self.showCTRreflAct = view_menu.addAction("CTR reflections")
309
+ self.showCTRreflAct.setCheckable(True)
310
+ self.showCTRreflAct.setChecked(False)
311
+ self.showCTRreflAct.toggled.connect(self.onShowCTRreflections)
312
+ self.reflectionsVisible = False
313
+
314
+ self.showMachineParamsAct = view_menu.addAction("machine parameters")
315
+ self.showMachineParamsAct.setCheckable(True)
316
+ self.showMachineParamsAct.setChecked(False)
317
+ self.showMachineParamsAct.toggled.connect(self._onPlotMachineParams)
318
+
319
+ view_menu.addSeparator()
320
+
321
+ saveBraggAct = view_menu.addAction("save allowed Bragg reflections")
322
+ saveBraggAct.setCheckable(False)
323
+ saveBraggAct.triggered.connect(self.saveBraggRefl)
324
+ if console:
325
+ view_menu.addSeparator()
326
+
327
+ custom_banner = f"""orGUI v. {__version__} console
328
+ Available variables:
329
+ orgui : top level gui
330
+ ub : gui for UB matrix and angle calculations
331
+ """
332
+
333
+ self.console_dockwidget = console.IPythonDockWidget(self, {'orgui': self, 'ub': self.ubcalc}, custom_banner, "orGUI console")
334
+
335
+ self.console_dockwidget.setAllowedAreas(qt.Qt.LeftDockWidgetArea | qt.Qt.RightDockWidgetArea | qt.Qt.BottomDockWidgetArea)
336
+ self.tabifyDockWidget(selectorDock,self.console_dockwidget)
337
+ #self.addDockWidget(qt.Qt.LeftDockWidgetArea,self.console_dockwidget)
338
+ self.console_dockwidget.setVisible(False)
339
+ consoleViewAct = self.console_dockwidget.toggleViewAction()
340
+ view_menu.addAction(consoleViewAct)
341
+
342
+
343
+ ##############################
344
+
345
+ editUAct = qt.QAction("Edit orientation matrix",self)
346
+ editUAct.setCheckable(True)
347
+ editUAct.toggled.connect(lambda checked: self.ubcalc.ueditDialog.setVisible(checked))
348
+ self.ubcalc.ueditDialog.sigHide.connect(lambda : editUAct.setChecked(False))
349
+
350
+ calcCTRsAvailableAct = qt.QAction("Calculate available CTRs",self)
351
+ calcCTRsAvailableAct.triggered.connect(self._onCalcAvailableCTR)
352
+ rs = menu_bar.addMenu("&Reciprocal space")
353
+ rs.addAction(calcCTRsAvailableAct)
354
+ rs.addAction(editUAct)
355
+
356
+ simul = menu_bar.addMenu("&Simulation")
357
+
358
+ createScanAct = simul.addAction("Create dummy scan")
359
+ createScanAct.triggered.connect(self._onCreateScan)
360
+
361
+ datamenu = menu_bar.addMenu("Data processing")
362
+ hackAct = datamenu.addAction("Rocking scan integration")
363
+ hackAct.triggered.connect(self.rocking_extraction)
364
+
365
+ helpmenu = menu_bar.addMenu("&Help")
366
+
367
+ diffractAct = helpmenu.addAction("Diffraction geometry")
368
+ diffractAct.triggered.connect(self._onShowDiffractionGeometry)
369
+
370
+ helpmenu.addSeparator()
371
+
372
+ aboutAct = helpmenu.addAction("About")
373
+ aboutAct.triggered.connect(self._onShowAbout)
374
+
375
+
376
+ aboutQtAct = helpmenu.addAction("About Qt")
377
+ aboutQtAct.triggered.connect(lambda : qt.QMessageBox.aboutQt(self))
378
+
379
+ self.setMenuBar(menu_bar)
380
+
381
+
382
+ def rocking_extraction(self):
383
+ if self.fscan is None: #or isinstance(self.fscan, SimulationScan):
384
+ qt.QMessageBox.warning(self, "No scan loaded", "Cannot integrate scan: No scan loaded.")
385
+ return
386
+
387
+ # make ROI visible in orgui images
388
+ self.roivisible = True
389
+ try:
390
+ self.updateROI()
391
+ except Exception:
392
+ qutils.warning_detailed_message(self, "Cannot show ROI", "Cannot show ROI", traceback.format_exc())
393
+ return
394
+
395
+
396
+ # select static ROI integration instead of hkl scan
397
+ self.scanSelector.scanstab.setCurrentIndex(1)
398
+
399
+ # open CTR selection dialog
400
+ diag_rock = QRockingScanCreator()
401
+ if diag_rock.exec() == qt.QDialog.Accepted:
402
+
403
+ # define integration boundaries
404
+ l_min = diag_rock.Lmin.value()
405
+ l_max = diag_rock.Lmax.value()
406
+ step_width = diag_rock.interval.value()
407
+ step_nr = round((l_max-l_min)/step_width) + 1
408
+
409
+ #calculate useful ROI size
410
+ try:
411
+ min_coordinates = self.searchPixelCoordHKL([diag_rock.selectedH.value(),diag_rock.selectedK.value(),l_min])
412
+ max_coordinates = self.searchPixelCoordHKL([diag_rock.selectedH.value(),diag_rock.selectedK.value(),l_max])
413
+ except Exception:
414
+ qutils.warning_detailed_message(self, "Cannot calculate coordiantes", "Cannot calculate pixel coordinates. See details!", traceback.format_exc())
415
+ return
416
+ refl_dialog = QReflectionAnglesDialog(min_coordinates,"Select the correct intersection with Ewald sphere", self)
417
+ for no_show in range(3):
418
+ if qt.QDialog.Accepted == refl_dialog.exec():
419
+ for i, cb in enumerate(refl_dialog.checkboxes):
420
+ if cb.isChecked():
421
+ which_Ewald_intersect = i
422
+ break
423
+ else:
424
+ qt.QMessageBox.warning(self, "No reflection selected", "Select a reflection on the rod you want to integrate.")
425
+ continue
426
+ break
427
+ else:
428
+ return
429
+ dist_in_pixels = min_coordinates['xy_%s' % int(which_Ewald_intersect+1)][1] - max_coordinates['xy_%s' % int(which_Ewald_intersect+1)][1]
430
+ roi_hlength = np.ceil(dist_in_pixels/step_nr)
431
+
432
+ # open ROI selection dialog
433
+ diag_rock_roi = QRockingScanROI(roi_hlength)
434
+ if diag_rock_roi.exec() == qt.QDialog.Accepted:
435
+
436
+ # select integration parameters such as ROI size, background
437
+ self.scanSelector.hsize.setValue(diag_rock_roi.roi_hsize.value())
438
+ self.scanSelector.vsize.setValue(diag_rock_roi.roi_vsize.value())
439
+ self.scanSelector.left.setValue(diag_rock_roi.roi_hsize_bg.value())
440
+ self.scanSelector.right.setValue(diag_rock_roi.roi_vsize_bg.value())
441
+ self.scanSelector.sigROIChanged.emit()
442
+
443
+ # additional scanSelector options:
444
+ # background: orgui.scanSelector.top, orgui.scanSelector.bottom
445
+ # offset: orgui.scanSelector.offsetx, orgui.scanSelector.offsety
446
+
447
+ # set default mask for pilatus 2M CdTe detector
448
+ #det = pyFAI.detector_factory('Pilatus 2m CdTe')
449
+ #mask = det.calc_mask()
450
+ #self.centralPlot.setSelectionMask(mask) # don't do this, as more sophisticated masks will be overwritten!
451
+
452
+ # set integration options
453
+ #self.scanSelector.useMaskBox.setChecked(True)
454
+ #self.scanSelector.useSolidAngleBox.setChecked(True)
455
+ #self.scanSelector.usePolarizationBox.setChecked(True)
456
+
457
+ progress = qt.QProgressDialog("Integrating rocking scan at ROI position","abort",0,step_nr,self)
458
+ progress.setWindowModality(qt.Qt.WindowModal)
459
+
460
+ for no, i in enumerate(np.linspace(l_min, l_max, step_nr)):
461
+ print('\n execute integration at L = %s' % round(i,2))
462
+ progress.setLabelText("Integrating rocking scan at ROI position L = %s" % round(i,6))
463
+ progress.setValue(no)
464
+ if progress.wasCanceled():
465
+ qt.QMessageBox.warning(self, "Rocking scan aborted", "Rocking scan was aborted.")
466
+ progress.setValue(step_nr)
467
+ return
468
+ coordinates = self.searchPixelCoordHKL([diag_rock.selectedH.value(),diag_rock.selectedK.value(),i])
469
+ xpos = coordinates['xy_%s' % int(which_Ewald_intersect+1)][0]
470
+ ypos = coordinates['xy_%s' % int(which_Ewald_intersect+1)][1]
471
+
472
+ self.scanSelector.set_xy_static_loc(xpos, ypos)
473
+ self.scanSelector.sigROIChanged.emit()
474
+ self.integrateROI()
475
+
476
+ qt.QMessageBox.information(self, "Rocking scan integrated", "Rocking scan was successfully integrated.")
477
+ progress.setValue(step_nr)
478
+
479
+
480
+ # save extracted rocking scan curves into hdf5 file
481
+ #self.database.saveDBFile('C:/Users/fschroeter/data_analysis/orgui/test_rocking_extract.h5')
482
+
483
+ def updatePlotItems(self, recalculate=True):
484
+ if self.roivisible:
485
+ try:
486
+ self.updateROI()
487
+ except Exception:
488
+ pass
489
+
490
+ if self.reflectionsVisible:
491
+ if recalculate:
492
+ try:
493
+ hkm = self.calculateAvailableCTR()
494
+ hk = np.unique(hkm[:,:2],axis=0)
495
+ H_0 = np.hstack((hk, np.zeros((hk.shape[0],1))))
496
+ H_1 = np.array([0,0,1])
497
+ self.reflectionsToDisplay = H_0, H_1
498
+ except Exception:
499
+ self.showCTRreflAct.setChecked(False)
500
+ self.reflectionsVisible = False
501
+ self.updateReflections()
502
+
503
+ if self.reflectionSel.showBraggReflections:
504
+ try:
505
+ self.calcBraggRefl()
506
+ except:
507
+ pass
508
+
509
+
510
+ def onShowBragg(self,visible):
511
+ try:
512
+ self.reflectionSel.setBraggReflectionsVisible(visible)
513
+ self.calcBraggRefl()
514
+ except Exception:
515
+ qutils.warning_detailed_message(self, "Cannot show show Bragg reflections", "Cannot show Bragg reflections", traceback.format_exc())
516
+ #qt.QMessageBox.critical(self,"Cannot show show Bragg reflections", "Cannot Cannot show Bragg reflections:\n%s" % traceback.format_exc())
517
+
518
+ def onShowROI(self,visible):
519
+ self.roivisible = visible
520
+ try:
521
+ self.updateROI()
522
+ except Exception:
523
+ qutils.warning_detailed_message(self, "Cannot show ROI", "Cannot show ROI", traceback.format_exc())
524
+ #qt.QMessageBox.critical(self,"Cannot show ROI", "Cannot Cannot show ROI:\n%s" % traceback.format_exc())
525
+
526
+ def onShowCTRreflections(self,visible):
527
+ self.reflectionsVisible = visible
528
+ if self.reflectionsVisible:
529
+ try:
530
+ hkm = self.calculateAvailableCTR()
531
+ except Exception:
532
+ qutils.warning_detailed_message(self, "Cannot calculate CTR locations", "Cannot calculate CTR locatons", traceback.format_exc())
533
+ #qt.QMessageBox.critical(self,"Cannot calculate CTR locatons", "Cannot calculate CTR locatons:\n%s" % traceback.format_exc())
534
+ self.showCTRreflAct.setChecked(False)
535
+ self.reflectionsVisible = False
536
+ return
537
+ hk = np.unique(hkm[:,:2],axis=0)
538
+ H_0 = np.hstack((hk, np.zeros((hk.shape[0],1))))
539
+ H_1 = np.array([0,0,1])
540
+
541
+ self.reflectionsToDisplay = H_0, H_1
542
+ self.updateReflections()
543
+
544
+ def _onShowAbout(self):
545
+ messageStr = """Copyright (c) 2020-2024 Timo Fuchs, published under MIT License
546
+ <br> <br>
547
+ orGUI: Orientation and Integration with 2D detectors (1.0.0).<br>
548
+ Zenodo. <a href=\"https://doi.org/10.5281/zenodo.12592485\">https://doi.org/10.5281/zenodo.12592485</a> <br> <br>
549
+ New software updates will be published under <a href=\"https://doi.org/10.5281/zenodo.12592485\">Zenodo</a>.
550
+ <br> <br>
551
+ Help requests can be send via Email to Timo Fuchs.
552
+ <br> <br>
553
+ "orGUI" was developed during the PhD work of Timo Fuchs,
554
+ within the group of Olaf Magnussen.
555
+ """
556
+ msg0 = qt.QMessageBox(self)
557
+ msg0.setWindowTitle("About orGUI")
558
+ msg0.setText(messageStr)
559
+ msg0.setTextInteractionFlags(qt.Qt.TextBrowserInteraction)
560
+ msg0.setTextFormat(qt.Qt.RichText)
561
+ msg0.exec()
562
+
563
+ def _onShowDiffractionGeometry(self):
564
+ if hasattr(self, 'diffractometerdialog'):
565
+ self.diffractometerdialog.show()
566
+ else:
567
+ self.diffractometerdialog = QDiffractometerImageDialog()
568
+ self.diffractometerdialog.show()
569
+
570
+ def _onToggleExcludeImage(self, exclude):
571
+ currentimgno = self.scanSelector.slider.value()
572
+ data = self.excludedImagesDialog.getData()
573
+ imgno_in_excudearray = currentimgno in data
574
+
575
+ if imgno_in_excudearray and exclude:
576
+ return
577
+ if not imgno_in_excudearray and exclude:
578
+ data = np.hstack([data, currentimgno])
579
+ self.excludedImagesDialog.updateArrayData(data)
580
+ else:
581
+ data = data[data != currentimgno]
582
+ self.excludedImagesDialog.updateArrayData(data)
583
+
584
+ def _onSelectCPUcount(self):
585
+ maxavail = os.cpu_count() if os.cpu_count() is not None else 1
586
+ if 'SLURM_CPUS_ON_NODE' in os.environ:
587
+ maxavail = int(os.environ['SLURM_CPUS_ON_NODE'])
588
+
589
+ cpus, success = qt.QInputDialog.getInt(self,"CPU count",
590
+ "CPU count (detected: %s)" % maxavail,
591
+ self.numberthreads,1)
592
+ if success:
593
+ self.numberthreads = cpus
594
+
595
+
596
+ def calcBraggRefl(self):
597
+ if self.fscan is not None and self.reflectionSel.showBraggReflections:
598
+ if self.fscan.axisname != 'th':
599
+ raise NotImplementedError("Calculation of available Bragg reflections is not implemented for %s - scans" % self.fscan.axisname)
600
+ try:
601
+ xtal = self.ubcalc.crystal
602
+ ommin = np.deg2rad(np.amin(self.fscan.omega))
603
+ ommax = np.deg2rad(np.amax(self.fscan.omega))
604
+ dc = self.ubcalc.detectorCal
605
+ mu = self.ubcalc.mu
606
+ ub = self.ubcalc.ubCal
607
+ chi = self.ubcalc.chi
608
+ phi = self.ubcalc.phi
609
+ xtal.setEnergy(ub.getEnergy()*1e3)
610
+ hkls, yx, angles = rn.thscanBragg(xtal,ub,mu,dc,(ommin,ommax), chi=chi, phi=phi)
611
+ self.reflectionSel.setBraggReflections(hkls, yx, angles)
612
+ except Exception:
613
+ qutils.warning_detailed_message(self, "Cannot calculate Bragg reflections", "Cannot calculate Bragg reflections", traceback.format_exc())
614
+ #qt.QMessageBox.critical(self,"Cannot calculate Bragg reflections", "Cannot calculate Bragg reflections:\n%s" % traceback.format_exc())
615
+
616
+
617
+ def saveBraggRefl(self):
618
+ try:
619
+ hkls, yx, angles = self.reflectionSel.getBraggReflections()
620
+ except ValueError:
621
+ if self.fscan is not None:
622
+ try:
623
+ xtal = self.ubcalc.crystal
624
+ ommin = np.deg2rad(np.amin(self.fscan.omega))
625
+ ommax = np.deg2rad(np.amax(self.fscan.omega))
626
+ dc = self.ubcalc.detectorCal
627
+ mu = self.ubcalc.mu
628
+ ub = self.ubcalc.ubCal
629
+ chi = self.ubcalc.chi
630
+ phi = self.ubcalc.phi
631
+ xtal.setEnergy(ub.getEnergy()*1e3)
632
+ hkls, yx, angles = rn.thscanBragg(xtal,ub,mu,dc,(ommin,ommax), chi=chi, phi=phi)
633
+
634
+
635
+ #self.reflectionSel.setBraggReflections(hkls, yx, angles)
636
+ except Exception:
637
+ qutils.warning_detailed_message(self, "Cannot calculate Bragg reflections", "Cannot calculate Bragg reflections", traceback.format_exc())
638
+ #qt.QMessageBox.critical(self,"Cannot calculate Bragg reflections", "Cannot calculate Bragg reflections:\n%s" % traceback.format_exc())
639
+ return
640
+ else:
641
+ qt.QMessageBox.critical(self,"Cannot calculate Bragg reflections", "Cannot calculate Bragg reflections:\nNo scan loaded.")
642
+ return
643
+
644
+ hkm = np.concatenate((hkls, yx[:,::-1], np.rad2deg(angles)), axis=1)
645
+
646
+ sio = StringIO()
647
+ np.savetxt(sio,hkm,fmt="%.3f", delimiter='\t',header="H K L x y alpha delta gamma omega chi phi")
648
+
649
+ #Question dialog for saving the possible CTR locations
650
+ msgbox = qt.QMessageBox(qt.QMessageBox.Question,'Saving Bragg reflection ...',
651
+ 'Found possible Bragg reflections. Do you want to save the following positions?',
652
+ qt.QMessageBox.Yes | qt.QMessageBox.No, self)
653
+
654
+ msgbox.setDetailedText(sio.getvalue())
655
+
656
+ clickedbutton = msgbox.exec()
657
+ #Question dialog for saving the possible CTR locations
658
+ #clickedbutton=qt.QMessageBox.question(self, 'Saving CTR locations...', 'Do you want to save the following positions: \n' + hkstring +"?");
659
+
660
+ if clickedbutton==qt.QMessageBox.Yes:
661
+ #File saving
662
+ fileTypeDict = {'dat Files (*.dat)': '.dat', 'txt Files (*.txt)': '.txt', 'All files (*)': '', }
663
+ fileTypeFilter = ""
664
+ for f in fileTypeDict:
665
+ fileTypeFilter += f + ";;"
666
+
667
+ filename, filetype = qt.QFileDialog.getSaveFileName(self,"Save reflections",
668
+ self.filedialogdir,
669
+ fileTypeFilter[:-2])
670
+ if filename == '':
671
+ return
672
+
673
+ self.filedialogdir = os.path.splitext(filename)[0]
674
+ filename += fileTypeDict[filetype]
675
+ np.savetxt(filename,hkm,fmt="%.3f",header="H K L x y alpha delta gamma omega chi phi")
676
+
677
+ def calculateAvailableCTR(self):
678
+ if self.fscan is None:
679
+ raise Exception("No scan selected!")
680
+ if self.fscan.axisname != 'th':
681
+ raise NotImplementedError("Calculation of available CTRs is not implemented for %s - scans" % self.fscan.axisname)
682
+ xtal = self.ubcalc.crystal
683
+ ommin = np.deg2rad(np.amin(self.fscan.omega))
684
+ ommax = np.deg2rad(np.amax(self.fscan.omega))
685
+ dc = self.ubcalc.detectorCal
686
+ mu = self.ubcalc.mu
687
+ chi = self.ubcalc.chi
688
+ phi = self.ubcalc.phi
689
+ ub = self.ubcalc.ubCal
690
+ xtal.setEnergy(ub.getEnergy()*1e3)
691
+ hk, xmirror = rn.thscanCTRs(xtal,ub,mu,dc,(ommin,ommax), chi=chi, phi=phi)
692
+ xmirror = np.array(xmirror).astype(np.float64)
693
+ #making the hk list of arrays into a reasonable string
694
+ hkm = np.concatenate((np.array(hk), xmirror.reshape((1,xmirror.size)).T), axis=1)
695
+ return hkm
696
+
697
+ def _onCalcAvailableCTR(self):
698
+ try:
699
+ hkm = self.calculateAvailableCTR()
700
+ except Exception:
701
+ qutils.warning_detailed_message(self, "Cannot calculate CTR locatons", "Cannot calculate CTR locatons", traceback.format_exc())
702
+ #qt.QMessageBox.critical(self,"Cannot calculate CTR locatons", "Cannot calculate CTR locatons:\n%s" % traceback.format_exc())
703
+ return
704
+ sio = StringIO()
705
+ np.savetxt(sio,hkm,fmt="%.3f", delimiter='\t',header="H K detectorRight")
706
+
707
+ #Question dialog for saving the possible CTR locations
708
+ msgbox = qt.QMessageBox(qt.QMessageBox.Question,'Saving CTR locations...',
709
+ 'Found CTRs. Do you want to save the following positions?',
710
+ qt.QMessageBox.Yes | qt.QMessageBox.No, self)
711
+ msgbox.setDetailedText(sio.getvalue())
712
+
713
+ clickedbutton = msgbox.exec()
714
+ #Question dialog for saving the possible CTR locations
715
+ #clickedbutton=qt.QMessageBox.question(self, 'Saving CTR locations...', 'Do you want to save the following positions: \n' + hkstring +"?");
716
+
717
+ if clickedbutton==qt.QMessageBox.Yes:
718
+ #File saving
719
+ fileTypeDict = {'dat Files (*.dat)': '.dat', 'txt Files (*.txt)': '.txt', 'All files (*)': '', }
720
+ fileTypeFilter = ""
721
+ for f in fileTypeDict:
722
+ fileTypeFilter += f + ";;"
723
+
724
+ filename, filetype = qt.QFileDialog.getSaveFileName(self,"Save reflections",
725
+ self.filedialogdir,
726
+ fileTypeFilter[:-2])
727
+ if filename == '':
728
+ return
729
+
730
+ self.filedialogdir = os.path.splitext(filename)[0]
731
+ filename += fileTypeDict[filetype]
732
+ np.savetxt(filename,hkm,fmt="%.3f",header="H K mirror")
733
+
734
+
735
+ def getReflections(self):
736
+ hkls = []
737
+ angles = []
738
+ for refl in self.reflectionSel.reflections:
739
+ #print(refl.xy)
740
+ gamma, delta = self.ubcalc.detectorCal.surfaceAnglesPoint(np.array([refl.xy[1]]),np.array([refl.xy[0]]),self.ubcalc.mu)
741
+ delta = float(delta); gamma = float(gamma)
742
+ try:
743
+ pos = np.array([self.ubcalc.mu,delta,gamma,self.imageNoToOmega(refl.imageno),self.ubcalc.chi,self.ubcalc.phi])
744
+ except:
745
+ from IPython import embed; embed()
746
+ raise
747
+ #print(pos)
748
+ hkls.append(refl.hkl)
749
+ angles.append(pos)
750
+ return np.array(hkls), np.array(angles)
751
+
752
+
753
+ def _onPlotMachineParams(self, enable=None):
754
+ #[cp,azimxy,polax] = paramslist
755
+ if enable is None:
756
+ enable = self.showMachineParamsAct.isChecked()
757
+ if enable:
758
+ fit2DCal = self.ubcalc.detectorCal.getFit2D()
759
+ cp = fit2DCal['centerX'], fit2DCal['centerY']
760
+ gam_p,_ = self.ubcalc.detectorCal.rangegamdel_p
761
+ azimy,azimx = self.ubcalc.detectorCal.pixelsPrimeBeam(gam_p[1]/5, 0 )[0]
762
+ self.centralPlot.addMarker(cp[0],cp[1],legend="CentralPixel",text="CP",color='yellow',symbol='+')
763
+ self.centralPlot.addMarker(azimx,azimy,legend="azimuth",text="Azim",color='yellow',symbol='+')
764
+ else:
765
+ self.centralPlot.removeMarker("CentralPixel")
766
+ self.centralPlot.removeMarker("azimuth")
767
+
768
+ def searchPixelCoordHKL(self, hkl):
769
+ refldict = self.ubcalc.calcReflection(hkl)
770
+ axisname = self.fscan.axisname
771
+ dc = self.ubcalc.detectorCal
772
+
773
+ if self.fscan.axisname == 'mu':
774
+ angle_idx = 0
775
+ sign = 1.
776
+ elif self.fscan.axisname == 'th':
777
+ angle_idx = 3
778
+ sign = -1.
779
+ else:
780
+ qt.QMessageBox.warning(self,"Cannot calculate reflection","Cannot calculate reflection.\n%s is no supported scan axis." % self.fscan.axisname)
781
+ return
782
+ try:
783
+ imageno1 = self.axisToImageNo(np.rad2deg(refldict['angles_1'][angle_idx]) * sign)
784
+ refldict['imageno_1'] = imageno1
785
+ except:
786
+ imageno1 = None
787
+ xy = refldict['xy_1']
788
+ onDetector = (xy[0] >= 0 and xy[0] < dc.detector.shape[1]) and \
789
+ (xy[1] >= 0 and xy[1] < dc.detector.shape[0])
790
+ if onDetector:
791
+ refldict['selectable_1'] = True
792
+ else:
793
+ refldict['selectable_1'] = False
794
+
795
+ try:
796
+ imageno2 = self.axisToImageNo(np.rad2deg(refldict['angles_2'][angle_idx]) * sign)
797
+ refldict['imageno_2'] = imageno2
798
+ except:
799
+ imageno2 = None
800
+ xy = refldict['xy_2']
801
+ onDetector = (xy[0] >= 0 and xy[0] < dc.detector.shape[1]) and \
802
+ (xy[1] >= 0 and xy[1] < dc.detector.shape[0])
803
+ if onDetector:
804
+ refldict['selectable_2'] = True
805
+ else:
806
+ refldict['selectable_2'] = False
807
+ return refldict
808
+
809
+ def onSearchHKLforStaticROI(self, hkl):
810
+ try:
811
+ refldict = self.searchPixelCoordHKL(hkl)
812
+ except Exception as e:
813
+ qutils.warning_detailed_message(self, "Cannot calculate location of reflection", "Cannot calculate position of reflection:\n%s" % e, traceback.format_exc())
814
+ return
815
+ refl_dialog = QReflectionAnglesDialog(refldict,"Select reflection location", self)
816
+ if qt.QDialog.Accepted == refl_dialog.exec():
817
+ for i, cb in enumerate(refl_dialog.checkboxes,1):
818
+ if cb.isChecked():
819
+ xy = refldict['xy_%s' % i]
820
+ self.scanSelector.set_xy_static_loc(xy[0], xy[1])
821
+ return
822
+
823
+ def _onNewReflection(self,refldict):
824
+ axisname = self.fscan.axisname
825
+ dc = self.ubcalc.detectorCal
826
+
827
+ if self.fscan.axisname == 'mu':
828
+ angle_idx = 0
829
+ sign = 1.
830
+ elif self.fscan.axisname == 'th':
831
+ angle_idx = 3
832
+ sign = -1.
833
+ else:
834
+ qt.QMessageBox.warning(self,"Cannot calculate reflection","Cannot calculate reflection.\n%s is no supported scan axis." % self.fscan.axisname)
835
+ return
836
+ try:
837
+ imageno1 = self.axisToImageNo(np.rad2deg(refldict['angles_1'][angle_idx]) * sign)
838
+ refldict['imageno_1'] = imageno1
839
+ xy = refldict['xy_1']
840
+ onDetector = (xy[0] >= 0 and xy[0] < dc.detector.shape[1]) and \
841
+ (xy[1] >= 0 and xy[1] < dc.detector.shape[0])
842
+ if onDetector:
843
+ refldict['selectable_1'] = True
844
+ else:
845
+ refldict['selectable_1'] = False
846
+ except:
847
+ imageno1 = None
848
+ refldict['selectable_1'] = False
849
+ try:
850
+ imageno2 = self.axisToImageNo(np.rad2deg(refldict['angles_2'][angle_idx]) * sign)
851
+ refldict['imageno_2'] = imageno2
852
+ xy = refldict['xy_2']
853
+ onDetector = (xy[0] >= 0 and xy[0] < dc.detector.shape[1]) and \
854
+ (xy[1] >= 0 and xy[1] < dc.detector.shape[0])
855
+ if onDetector:
856
+ refldict['selectable_2'] = True
857
+ else:
858
+ refldict['selectable_2'] = False
859
+ except:
860
+ imageno2 = None
861
+ refldict['selectable_2'] = False
862
+
863
+ refl_dialog = QReflectionAnglesDialog(refldict,"Select reflections to add into list of reference reflections", self)
864
+ if qt.QDialog.Accepted == refl_dialog.exec():
865
+ for i, cb in enumerate(refl_dialog.checkboxes,1):
866
+ if cb.isChecked():
867
+ xy = refldict['xy_%s' % i]
868
+ eventdict = {'x' : xy[0], 'y': xy[1]}
869
+ self.reflectionSel.addReflection(eventdict,refldict['imageno_%s' % i],refldict['hkl'])
870
+
871
+ """
872
+ try:
873
+ imageno = self.omegaToImageNo(omega)
874
+ except:
875
+ warnings.warn("Not xmirrored: Didn't find the corresponding image")
876
+ [hkl,x,y,omega] = self.ubcalc.calcReflection(hkl,True)
877
+ mirrored = [hkl,x,y,omega]
878
+ try:
879
+ imageno = self.omegaToImageNo(omega)
880
+ except Exception as e:
881
+ errormsg = "[hkl, x, y, om]\nnot mirrored: %s\nmirrored: %s" % (notmirrored,mirrored)
882
+ qutils.warning_detailed_message(self, "Could not find reflection","Didn't find the corresponding reflection on any image.\nError: %s\nShould be at location%s" % (str(e),errormsg), traceback.format_exc())
883
+ #qt.QMessageBox.warning(self,"Could not find reflection","Didn't find the corresponding reflection on any image.\nError: %s\nShould be at location%s" % (str(e),errormsg))
884
+ return
885
+ eventdict = {'x' : x, 'y': y}
886
+ self.reflectionSel.addReflection(eventdict,imageno,hkl)
887
+ """
888
+
889
+ def newXyHKLConverter(self):
890
+ def xyToHKL(x,y):
891
+ #print("xytoHKL:")
892
+ #print("x,y = %s, %s" % (x,y))
893
+ if self.fscan is None:
894
+ return np.array([np.nan,np.nan,np.nan, np.nan, np.nan])
895
+ mu, om = self.getMuOm(self.imageno)
896
+ gamma, delta = self.ubcalc.detectorCal.surfaceAnglesPoint(np.array([y]),np.array([x]), mu)
897
+ #print(self.ubcalc.detectorCal)
898
+ #print(x,y)
899
+ #print(self.ubcalc.detectorCal.tth(np.array([y]),np.array([x])))
900
+ pos = [mu,delta[0],gamma[0],om,self.ubcalc.chi,self.ubcalc.phi]
901
+ pos = HKLVlieg.crystalAngles(pos,self.ubcalc.n)
902
+ hkl = np.concatenate((np.array(self.ubcalc.angles.anglesToHkl(*pos)),np.rad2deg([delta[0],gamma[0]])))
903
+ return hkl
904
+ return xyToHKL
905
+
906
+ def getMuOm(self, imageno=None):
907
+ if imageno is not None:
908
+ if self.fscan.axisname == 'th':
909
+ mu = self.ubcalc.mu
910
+ om = -1 * np.deg2rad(self.imageNoToAxis(imageno))
911
+ elif self.fscan.axisname == 'mu':
912
+ mu = np.deg2rad(self.imageNoToAxis(imageno))
913
+ om = -1 * np.deg2rad(self.fscan.th)
914
+ if len(np.asarray(om).shape) > 0:
915
+ om = om[0]
916
+ else:
917
+ mu = self.ubcalc.mu
918
+ om = -1 * np.deg2rad(self.fscan.th)
919
+ if len(np.asarray(om).shape) > 0:
920
+ om = om[0]
921
+ return mu, om
922
+ else:
923
+ if self.fscan.axisname == 'th':
924
+ mu = self.ubcalc.mu
925
+ om = -1 * np.deg2rad(self.fscan.axis)
926
+ elif self.fscan.axisname == 'mu':
927
+ mu = np.deg2rad(self.fscan.axis)
928
+ om = -1 * np.deg2rad(self.fscan.th)
929
+ else:
930
+ mu = self.ubcalc.mu
931
+ om = -1 * np.deg2rad(self.fscan.th)
932
+ return mu, om
933
+
934
+ def omegaToImageNo(self,omega):
935
+ if self.fscan is not None:
936
+ omrad = np.deg2rad(self.fscan.omega)
937
+ ommax = np.amax(omrad)
938
+ ommin = np.amin(omrad)
939
+ #print(ommin,omega,ommax)
940
+ if omega < ommin or omega > ommax:
941
+ omdeg = np.rad2deg([ommin,omega,ommax])
942
+ raise Exception("omega not in range: %s < %s < %s" % tuple(omdeg))
943
+ return np.argmin(np.abs(omrad -omega))
944
+ else:
945
+ raise Exception("No Scan selected")
946
+
947
+ def imageNoToOmega(self,imageno):
948
+ if self.fscan is not None:
949
+ return np.deg2rad(self.fscan.omega[imageno])
950
+ else:
951
+ return 0.
952
+
953
+ def imageNoToAxis(self,imageno):
954
+ if self.fscan is not None:
955
+ return self.fscan.axis[imageno]
956
+ else:
957
+ return 0.
958
+
959
+ def axisToImageNo(self,axisval):
960
+ if self.fscan is not None:
961
+ #axis = np.deg2rad(self.fscan.axis)
962
+ axismax = np.amax(self.fscan.axis)
963
+ axismin = np.amin(self.fscan.axis)
964
+ #print(ommin,omega,ommax)
965
+ if axisval < axismin or axisval > axismax:
966
+ axisrange = [axismin,axisval,axismax]
967
+ raise Exception("Value of scan axis \"%s\" not in range: %s < %s < %s" % tuple([self.fscan.axisname]+axisrange))
968
+ return np.argmin(np.abs(self.fscan.axis - axisval))
969
+ else:
970
+ raise Exception("No Scan selected")
971
+
972
+ def _onCreateScan(self):
973
+ try:
974
+ mu, om = self.getMuOm(self.imageno)
975
+ except:
976
+ mu = self.ubcalc.mu
977
+ om = 0.
978
+ th = om*-1.
979
+ muTh = np.rad2deg([mu,th]) #defaults if fixed
980
+ diag = QScanCreator(muTh)
981
+ diag.shape1.setValue(self.ubcalc.detectorCal.detector.shape[0])
982
+ diag.shape2.setValue(self.ubcalc.detectorCal.detector.shape[1])
983
+ if diag.exec() == qt.QDialog.Accepted:
984
+ shape = (diag.shape1.value(), diag.shape2.value())
985
+ self.ubcalc.detectorCal.detector.shape = shape
986
+ try:
987
+ axis = diag.scanaxis.currentText()
988
+ if axis == 'theta':
989
+ axis = 'th'
990
+ elif axis == 'mu':
991
+ pass
992
+ fscan = SimulationScan(shape, diag.omstart.value(),
993
+ diag.omend.value(),
994
+ diag.no.value(),
995
+ axis, diag.fixedAngle.value())
996
+ self._onScanChanged(fscan)
997
+ except MemoryError:
998
+ qutils.warning_detailed_message(self, "Can not create simulation scan","Can not create simualtion scan. Memory is insufficient for the scan size. See details for further information.", traceback.format_exc())
999
+
1000
+ def _onLoadScanFromImages(self):
1001
+ # generates a scan from a selected folder containing raw detector images
1002
+
1003
+ # generate file source selection GUI
1004
+
1005
+ # create filter of scan image formats (following code is copied from silx view)
1006
+ extensions = {}
1007
+ for description, ext in silx.io.supported_extensions().items():
1008
+ extensions[description] = " ".join(sorted(list(ext)))
1009
+
1010
+ extensions["NeXus layout from EDF files"] = "*.edf"
1011
+ extensions["NeXus layout from TIFF image files"] = "*.tif *.tiff"
1012
+ extensions["NeXus layout from CBF files"] = "*.cbf"
1013
+ extensions["NeXus layout from MarCCD image files"] = "*.mccd"
1014
+
1015
+ all_supported_extensions = set()
1016
+ for name, exts in extensions.items():
1017
+ exts = exts.split(" ")
1018
+ all_supported_extensions.update(exts)
1019
+ all_supported_extensions = sorted(list(all_supported_extensions))
1020
+
1021
+ filters = []
1022
+ filters.append("All supported files (%s)" % " ".join(all_supported_extensions))
1023
+ for name, extension in extensions.items():
1024
+ filters.append("%s (%s)" % (name, extension))
1025
+ filters.append("All files (*)")
1026
+
1027
+ fileTypeFilter = ""
1028
+ for f in filters:
1029
+ fileTypeFilter += f + ";;"
1030
+
1031
+ # call dialog
1032
+ filename,_ = qt.QFileDialog.getOpenFileName(self,"Open data source",'',fileTypeFilter[:-2])
1033
+
1034
+ # Qt dialog returns '' if cancelled
1035
+ if filename == '':
1036
+ qt.QMessageBox.warning(self,"Error - Open data source","No data source selected")
1037
+ return
1038
+
1039
+ # search files using ImportImagesScan backend
1040
+ importedscan = universalScanLoader.ImportImagesScan(filename)
1041
+ [imagePrefix, found_scanfiles] = importedscan.inpath
1042
+
1043
+ # generate dialog with list of files and frames
1044
+ nrofFilesfound = len(found_scanfiles)
1045
+ messageStr = 'Found ' + str(nrofFilesfound) + ' files in selected directory'
1046
+
1047
+ if importedscan.FramesPerFile > 1:
1048
+
1049
+ if nrofFilesfound == 0:
1050
+ messageStr = 'No images found!!!'
1051
+ fullStr = messageStr
1052
+ elif 0 < nrofFilesfound < 4:
1053
+ messageStr += ':\n'
1054
+ for i in range(nrofFilesfound-1):
1055
+ messageStr += imagePrefix + found_scanfiles[i] + ': ' + str(importedscan.FramesPerFile) + ' frames' ### mark expected nr when file not actually loaded
1056
+ if i > 0:
1057
+ messageStr += ' (expected)'
1058
+ messageStr += '\n'
1059
+ messageStr += imagePrefix + found_scanfiles[nrofFilesfound-1] + ': ' + str(importedscan.FramesLastFile) + ' frames\n' + str(importedscan.nopoints) + ' frames in total.'
1060
+ fullStr = messageStr
1061
+ else:
1062
+ messageStr += ':\n'
1063
+ for i in range(0,3):
1064
+ messageStr += imagePrefix + found_scanfiles[i] + ': ' + str(importedscan.FramesPerFile) + ' frames'
1065
+ if i > 0:
1066
+ messageStr += ' (expected)'
1067
+ messageStr += '\n'
1068
+ fullStr = messageStr
1069
+ for i in range(3,nrofFilesfound-1):
1070
+ fullStr += imagePrefix + found_scanfiles[i] + ': ' + str(importedscan.FramesPerFile) + ' frames (expected) \n'
1071
+
1072
+ messageStr += '...' + '\n' + imagePrefix + found_scanfiles[nrofFilesfound-1] + ': ' + str(importedscan.FramesLastFile) + ' frames\n' + str(importedscan.nopoints) + ' frames in total.'
1073
+ fullStr += imagePrefix + found_scanfiles[nrofFilesfound-1] + ': ' + str(importedscan.FramesLastFile) + ' frames\n' + str(importedscan.nopoints) + ' frames in total.'
1074
+
1075
+
1076
+ else:
1077
+
1078
+ if nrofFilesfound == 0:
1079
+ messageStr = 'No images found!!!'
1080
+ fullStr = messageStr
1081
+ elif 0 < nrofFilesfound < 4:
1082
+ messageStr += ':\n'
1083
+ for i in range(nrofFilesfound-1):
1084
+ messageStr += imagePrefix + found_scanfiles[i] + '\n'
1085
+ messageStr += imagePrefix + found_scanfiles[nrofFilesfound-1]
1086
+ fullStr = messageStr
1087
+ else:
1088
+ messageStr += ':\n'
1089
+ for i in range(0,3):
1090
+ messageStr += imagePrefix + found_scanfiles[i] + '\n'
1091
+ fullStr = messageStr
1092
+ for i in range(3,nrofFilesfound):
1093
+ fullStr += imagePrefix + found_scanfiles[i] + '\n'
1094
+ messageStr += '...' + '\n' + imagePrefix + found_scanfiles[nrofFilesfound-1]
1095
+ fullStr += '\n' + str(importedscan.nopoints) + ' frames in total.'
1096
+
1097
+
1098
+
1099
+ msg0 = qt.QMessageBox(self)
1100
+ msg0.setWindowTitle("Manual scan import")
1101
+ msg0.setText(messageStr)
1102
+ msg0.setDetailedText(fullStr)
1103
+ msg0.exec()
1104
+
1105
+ # angle conversions
1106
+ try:
1107
+ mu, om = self.getMuOm(self.imageno)
1108
+ except:
1109
+ mu = self.ubcalc.mu
1110
+ om = 0.
1111
+ th = om*-1.
1112
+ muTh = np.rad2deg([mu,th]) #defaults if fixed
1113
+
1114
+ # open scan creator GUI to let the user insert missing scan angles
1115
+ diag = QImportScanCreator(muTh)
1116
+ # detector pixel nr and frame nr is adapted from opened image file
1117
+ diag.shape1.setValue(importedscan.shape[0])
1118
+ diag.shape2.setValue(importedscan.shape[1])
1119
+ diag.no.setValue(importedscan.nopoints)
1120
+
1121
+ if diag.exec() == qt.QDialog.Accepted:
1122
+ shape = (diag.shape1.value(), diag.shape2.value())
1123
+ self.ubcalc.detectorCal.detector.shape = shape
1124
+ try:
1125
+ axis = diag.scanaxis.currentText()
1126
+ if axis == 'theta':
1127
+ axis = 'th'
1128
+ elif axis == 'mu':
1129
+ pass
1130
+ # pass inserted angles to scan object
1131
+ importedscan.set_axis(diag.omstart.value(),diag.omend.value(),axis,diag.fixedAngle.value())
1132
+ self._onScanChanged(importedscan)
1133
+ except MemoryError:
1134
+ qutils.warning_detailed_message(self, "Can not create scan","Can not create scan. Memory is insufficient for the scan size. See details for further information.", traceback.format_exc())
1135
+
1136
+ def _onScanChanged(self,sel_list):
1137
+ self.resetZoom = True
1138
+ print(sel_list)
1139
+ self.activescanname = "scan"
1140
+ if isinstance(sel_list,list):
1141
+ self.sel_list = sel_list
1142
+ if len(sel_list):
1143
+ self.specfile = sel_list[0]['SourceName']
1144
+ try:
1145
+ self.scanno = int(float(sel_list[0]['Key']))-1
1146
+ self.fscan = Fastscan(self.specfile,self.scanno)
1147
+ self.imageno = 0
1148
+ except Exception:
1149
+ self.scanno = 0
1150
+ self.fscan = FioFastsweep(self.specfile)
1151
+ self.imageno = 0
1152
+ self.reflectionSel.setImage(self.imageno)
1153
+ if self.imagepath != '':
1154
+ self.fscan.set_image_folder(self.imagepath)
1155
+ self.plotImage()
1156
+ self.scanSelector.setAxis(self.fscan.axis, self.fscan.axisname)
1157
+
1158
+ else:
1159
+ self.scanSelector.setRange(0,0)
1160
+ self.imageno = 0
1161
+ self.reflectionSel.setImage(self.imageno)
1162
+ #print(self.centralPlot._callback)
1163
+
1164
+ elif isinstance(sel_list,universalScanLoader.ImportImagesScan):
1165
+ self.scanno = 1
1166
+ self.fscan = sel_list
1167
+ self.imageno = 0
1168
+ self.plotImage()
1169
+ self.scanSelector.setAxis(self.fscan.axis, self.fscan.axisname)
1170
+ self.activescanname = "%s-sim %s-%s" % (self.fscan.axisname, np.amin(self.fscan.axis),np.amax(self.fscan.axis))
1171
+
1172
+ self.images_loaded = False
1173
+ if self.fscan is not None and self.autoLoadAct.isChecked():
1174
+ self.loadAll()
1175
+ self.scanSelector.showMaxAct.setChecked(False)
1176
+ self.scanSelector.showMaxAct.setChecked(True)
1177
+
1178
+ elif isinstance(sel_list,SimulationScan):
1179
+ self.scanno = 1
1180
+ self.fscan = sel_list
1181
+ self.imageno = 0
1182
+ self.plotImage()
1183
+ self.scanSelector.setAxis(self.fscan.axis, self.fscan.axisname)
1184
+ self.activescanname = "%s-sim %s-%s" % (self.fscan.axisname, np.amin(self.fscan.axis),np.amax(self.fscan.axis))
1185
+ else:
1186
+ if 'name' in sel_list:
1187
+ self.activescanname = sel_list['name']
1188
+ else:
1189
+ self.activescanname = "scan"
1190
+ self.hdffile = sel_list['file']
1191
+ #self.scanname = sel_list['name'].strip("/")
1192
+ try:
1193
+ msg = qt.QMessageBox(self)
1194
+ msg.setWindowTitle("Loading Scan")
1195
+ msg.setText("Loading Scan. This might take a while...")
1196
+ msg.setStandardButtons(qt.QMessageBox.Cancel)
1197
+ msg.setModal(True)
1198
+ msg.show()
1199
+ if 'beamtime' in sel_list:
1200
+ self.fscan = backends.openScan(sel_list['beamtime'], sel_list)
1201
+ else:
1202
+ self.fscan = backends.openScan(self.scanSelector.btid.currentText(), sel_list)
1203
+
1204
+ self.plotImage()
1205
+ self.scanSelector.setAxis(self.fscan.axis, self.fscan.axisname)
1206
+ msg.hide()
1207
+ self.images_loaded = False
1208
+ if self.fscan is not None and self.autoLoadAct.isChecked():
1209
+ self.loadAll()
1210
+ self.scanSelector.showMaxAct.setChecked(False)
1211
+ self.scanSelector.showMaxAct.setChecked(True)
1212
+ except Exception:
1213
+ msg.hide()
1214
+ qutils.warning_detailed_message(self, "Cannot open scan", "Cannot open scan" , traceback.format_exc())
1215
+ #qt.QMessageBox.critical(self,"Cannot open scan", "Cannot open scan:\n%s" % traceback.format_exc())
1216
+
1217
+
1218
+
1219
+
1220
+ def _onImagePathChanged(self,path):
1221
+ #print("newpath %s" % path)
1222
+ self.imagepath = path
1223
+ if self.fscan is not None:
1224
+ self.fscan.set_image_folder(self.imagepath)
1225
+ self.plotImage()
1226
+ self.scanSelector.setAxis(self.fscan.axis, self.fscan.axisname)
1227
+ #self.scanSelector.slider.setMinimum(0)
1228
+ #self.scanSelector.slider.setMaximum(self.fscan.nopoints-1)
1229
+ else:
1230
+ self.scanSelector.setRange(0,0)
1231
+ self.imageno = 0
1232
+ self.reflectionSel.setImage(self.imageno)
1233
+ #print(self.centralPlot._callback)
1234
+
1235
+ def _onChangeImage(self,imageno):
1236
+ if self.fscan is not None:
1237
+ self.scanSelector.slider.setValue(imageno)
1238
+ self.plotImage(self.scanSelector.slider.value())
1239
+
1240
+ def _onSliderValueChanged(self,value):
1241
+ if self.fscan is not None:
1242
+ self.plotImage(value)
1243
+ #print(self.centralPlot._callback)
1244
+
1245
+
1246
+ def _onLoadAll(self):
1247
+ self.images_loaded = False
1248
+ if self.fscan is not None:
1249
+ self.loadAll()
1250
+ self.scanSelector.showMaxAct.setChecked(False)
1251
+ self.scanSelector.showMaxAct.setChecked(True)
1252
+
1253
+ def loadAll(self):
1254
+ try:
1255
+ image = self.fscan.get_raw_img(0)
1256
+ except Exception as e:
1257
+ print("no images found! %s" % e)
1258
+ return
1259
+ self.allimgsum = np.zeros_like(image.img)
1260
+ self.allimgmax = np.zeros_like(image.img)
1261
+ progress = qt.QProgressDialog("Reading images","abort",0,len(self.fscan),self)
1262
+ progress.setWindowModality(qt.Qt.WindowModal)
1263
+ #tasks = queue.Queue()
1264
+ #[tasks.put(i) for i in range(len(self.fscan))]
1265
+ lock = threading.Lock()
1266
+ self.images_loaded = True
1267
+ with concurrent.futures.ThreadPoolExecutor(max_workers=self.numberthreads) as executor: # speedup only for the file reads
1268
+ futures = {}
1269
+ def readfile_max(imgno):
1270
+ if imgno in self.excludedImagesDialog.getData(): # skip if excluded
1271
+ return imgno
1272
+ image = self.fscan.get_raw_img(imgno) # here speedup during file read
1273
+ with lock:
1274
+ self.allimgsum += image.img
1275
+ self.allimgmax = np.maximum(self.allimgmax,image.img)
1276
+ return imgno
1277
+ for i in range(len(self.fscan)):
1278
+ futures[executor.submit(readfile_max, i)] = i
1279
+
1280
+ for f in concurrent.futures.as_completed(futures):
1281
+ try:
1282
+ imgno = f.result()
1283
+ progress.setValue(imgno)
1284
+ except concurrent.futures.CancelledError:
1285
+ pass
1286
+ except Exception as e:
1287
+ print("Cannot read image:\n%s" % traceback.format_exc())
1288
+
1289
+ if progress.wasCanceled():
1290
+ [f.cancel() for f in futures]
1291
+ self.images_loaded = False
1292
+ break
1293
+
1294
+ progress.setValue(len(self.fscan))
1295
+
1296
+ def _onMaxToggled(self,value):
1297
+ if self.scanSelector.showSumAct.isChecked():
1298
+ self.scanSelector.showSumAct.setChecked(False)
1299
+ if value:
1300
+ if not self.images_loaded and self.fscan is not None:
1301
+ btn = qt.QMessageBox.question(self,"Incomplete sum / max image", "Sum/Max image was not loaded completely. Displayed maximum image will be incomplete! Do you want to load all images?",qt.QMessageBox.Yes | qt.QMessageBox.No | qt.QMessageBox.Cancel)
1302
+ if btn == qt.QMessageBox.Yes:
1303
+ self.loadAll()
1304
+ elif btn == qt.QMessageBox.Cancel:
1305
+ self.scanSelector.showMaxAct.setChecked(False)
1306
+ return
1307
+ if self.allimgmax is not None:
1308
+ self.currentAddImageLabel = self.centralPlot.addImage(self.allimgmax,legend="special",
1309
+ replace=False,resetzoom=False,copy=True,z=1)
1310
+ self.centralPlot.setActiveImage(self.currentAddImageLabel)
1311
+ self.scanSelector.alphaslider.setLegend(self.currentAddImageLabel)
1312
+ else:
1313
+ self.scanSelector.showMaxAct.setChecked(False)
1314
+ else:
1315
+ if self.currentAddImageLabel is not None:
1316
+ self.centralPlot.setActiveImage(self.currentImageLabel)
1317
+ self.centralPlot.removeImage(self.currentAddImageLabel)
1318
+ self.currentAddImageLabel = None
1319
+
1320
+
1321
+ def _onSumToggled(self,value):
1322
+ if self.scanSelector.showMaxAct.isChecked():
1323
+ self.scanSelector.showMaxAct.setChecked(False)
1324
+ if value:
1325
+ if not self.images_loaded and self.fscan is not None:
1326
+ btn = qt.QMessageBox.question(self,"Incomplete sum / max image", "Sum/Max image was not loaded completely. Displayed sum image will be incomplete! Do you want to load all images?",qt.QMessageBox.Yes | qt.QMessageBox.No | qt.QMessageBox.Cancel)
1327
+ if btn == qt.QMessageBox.Yes:
1328
+ self.loadAll()
1329
+ elif btn == qt.QMessageBox.Cancel:
1330
+ self.scanSelector.showSumAct.setChecked(False)
1331
+ return
1332
+ if self.allimgsum is not None:
1333
+ self.currentAddImageLabel = self.centralPlot.addImage(self.allimgsum,legend="special",
1334
+ replace=False,resetzoom=False,copy=True,z=1)
1335
+ self.centralPlot.setActiveImage(self.currentAddImageLabel)
1336
+ self.scanSelector.alphaslider.setLegend(self.currentAddImageLabel)
1337
+ else:
1338
+ self.scanSelector.showSumAct.setChecked(False)
1339
+ else:
1340
+ if self.currentAddImageLabel is not None:
1341
+ self.centralPlot.setActiveImage(self.currentImageLabel)
1342
+ self.centralPlot.removeImage(self.currentAddImageLabel)
1343
+ self.currentAddImageLabel = None
1344
+
1345
+
1346
+
1347
+
1348
+ def plotImage(self,key=0):
1349
+ try:
1350
+ image = self.fscan.get_raw_img(key)
1351
+ #if self.currentImageLabel is not None:
1352
+ # self.centralPlot.removeImage(self.currentImageLabel)
1353
+
1354
+ self.currentImageLabel = self.centralPlot.addImage(image.img,legend="scan_image",
1355
+ replace=False,resetzoom=self.resetZoom,copy=True)
1356
+ if self.currentAddImageLabel is None:
1357
+ self.centralPlot.setActiveImage(self.currentImageLabel)
1358
+ self.resetZoom = False
1359
+ self.imageno = key
1360
+ self.reflectionSel.setImage(self.imageno)
1361
+ self.updateROI()
1362
+ self.updateReflections()
1363
+
1364
+ mu, om = self.getMuOm(self.imageno)
1365
+ self.ubcalc.uedit.setAngles(mu, self.ubcalc.chi, self.ubcalc.phi, om)
1366
+
1367
+ self.scanSelector.excludeImageAct.blockSignals(True)
1368
+ self.scanSelector.excludeImageAct.setChecked(key in self.excludedImagesDialog.getData())
1369
+ self.scanSelector.excludeImageAct.blockSignals(False)
1370
+
1371
+ except Exception as e:
1372
+ print(traceback.format_exc())
1373
+ print("no image %s" % e)
1374
+
1375
+
1376
+ def updateReflections(self):
1377
+ if not self.reflectionsVisible:
1378
+ self.centralPlot.removeCurve('all_image_reflections')
1379
+ return
1380
+ H_0, H_1 = self.reflectionsToDisplay
1381
+ #H_0 = np.array([[1,0,0], [1,1,0]])
1382
+ #H_1 = np.array([[0,0,1], [0,0,1]])
1383
+
1384
+ hkl_del_gam_1, hkl_del_gam_2 = self.getROIloc(self.imageno, H_0, H_1, intersect=True)
1385
+
1386
+ mask1 = hkl_del_gam_1[:,-1].nonzero()
1387
+ mask2 = hkl_del_gam_2[:,-1].nonzero()
1388
+
1389
+ masked_hkl_del_gam = np.vstack((hkl_del_gam_1[mask1],hkl_del_gam_2[mask2]))
1390
+
1391
+ self.centralPlot.addCurve(masked_hkl_del_gam[:,-3],masked_hkl_del_gam[:,-2],legend='all_image_reflections',
1392
+ linestyle=' ', symbol='.', color='y',resetzoom=False)
1393
+
1394
+
1395
+
1396
+ def updateROI(self):
1397
+ #dc = self.ubcalc.detectorCal
1398
+ #mu = self.ubcalc.mu
1399
+ #angles = self.ubcalc.angles
1400
+
1401
+ #H_1 = np.array([h.value() for h in self.scanSelector.H_1])
1402
+ #H_0 = np.array([h.value() for h in self.scanSelector.H_0])
1403
+ try:
1404
+ hkl_del_gam_1, hkl_del_gam_2 = self.getROIloc(self.imageno)
1405
+ except:
1406
+ for roi in self.rois:
1407
+ roi.setVisible(False)
1408
+ self.centralPlot.removeMarker('main_croi_loc')
1409
+ return
1410
+
1411
+
1412
+ """
1413
+ hkl_del_gam_1, hkl_del_gam_2 = angles.anglesIntersectLineEwald(H_0, H_1, mu,self.imageNoToOmega(self.imageno),self.ubcalc.phi,self.ubcalc.chi)
1414
+
1415
+ delta1 = hkl_del_gam_1[...,3]
1416
+ delta2 = hkl_del_gam_2[...,3]
1417
+ gam1 = hkl_del_gam_1[...,4]
1418
+ gam2 = hkl_del_gam_2[...,4]
1419
+
1420
+ yx1 = dc.pixelsSurfaceAngles(gam1, delta1, mu)
1421
+ yx2 = dc.pixelsSurfaceAngles(gam2, delta2, mu)
1422
+
1423
+ ymask1 = np.logical_and(yx1[...,0] >= 0, yx1[...,0] < dc.detector.shape[0])
1424
+ xmask1 = np.logical_and(yx1[...,1] >= 0, yx1[...,1] < dc.detector.shape[1])
1425
+ yxmask1 = np.logical_and(xmask1,ymask1)
1426
+
1427
+ ymask2 = np.logical_and(yx2[...,0] >= 0, yx2[...,0] < dc.detector.shape[0])
1428
+ xmask2 = np.logical_and(yx2[...,1] >= 0, yx2[...,1] < dc.detector.shape[1])
1429
+ yxmask2 = np.logical_and(xmask2,ymask2)
1430
+ """
1431
+ if not self.roivisible:
1432
+ for roi in self.rois:
1433
+ roi.setVisible(False)
1434
+ self.roiManager._roisUpdated()
1435
+ self.centralPlot.removeMarker('main_croi_loc')
1436
+
1437
+
1438
+ if hkl_del_gam_1[0,-1] or hkl_del_gam_2[0,-1]:
1439
+ if hkl_del_gam_1[0,-1]:
1440
+ if self.roivisible:
1441
+ self.plotROI(hkl_del_gam_1[0,6:8])
1442
+ for i, spinbox in enumerate(self.scanSelector.hkl_static):
1443
+ spinbox.setValue(hkl_del_gam_1[0,i])
1444
+
1445
+ if hkl_del_gam_2[0,-1]:
1446
+ if self.roivisible:
1447
+ self.plotROI(hkl_del_gam_2[0,6:8])
1448
+ for i, spinbox in enumerate(self.scanSelector.hkl_static):
1449
+ spinbox.setValue(hkl_del_gam_1[0,i])
1450
+ else:
1451
+ for roi in self.rois:
1452
+ roi.setVisible(False)
1453
+ self.centralPlot.removeMarker('main_croi_loc')
1454
+
1455
+ def getROIloc(self, imageno=None, H_0=None, H_1=None, **kwargs):
1456
+ if self.fscan is None:
1457
+ raise Exception("No scan loaded!")
1458
+
1459
+
1460
+ mu, om = self.getMuOm(imageno)
1461
+ mu_cryst = HKLVlieg.crystalAngles_singleArray(mu, self.ubcalc.n)
1462
+ dc = self.ubcalc.detectorCal
1463
+ #mu = self.ubcalc.mu
1464
+ angles = self.ubcalc.angles
1465
+
1466
+ """
1467
+ gamma, delta = self.ubcalc.detectorCal.surfaceAnglesPoint(np.array([y]),np.array([x]), mu)
1468
+ #print(self.ubcalc.detectorCal)
1469
+ #print(x,y)
1470
+ #print(self.ubcalc.detectorCal.tth(np.array([y]),np.array([x])))
1471
+ pos = [mu,delta[0],gamma[0],om,self.ubcalc.chi,self.ubcalc.phi]
1472
+ pos = HKLVlieg.crystalAngles(pos,self.ubcalc.n)
1473
+ hkl = np.concatenate((np.array(self.ubcalc.angles.anglesToHkl(*pos)),np.rad2deg([delta[0],gamma[0]])))
1474
+ """
1475
+ #print(self.scanSelector.scanstab.currentIndex())
1476
+ if self.scanSelector.scanstab.currentIndex() == 1 and not kwargs.get('intersect', False):
1477
+ if imageno is None:
1478
+ hkl_del_gam_1 = np.ones((len(self.fscan),6),dtype=np.float64)
1479
+ x = np.full(len(self.fscan),self.scanSelector.xy_static[0].value())
1480
+ y = np.full(len(self.fscan),self.scanSelector.xy_static[1].value())
1481
+
1482
+ gamma, delta, alpha = self.ubcalc.detectorCal.crystalAnglesPoint(y, x, mu, self.ubcalc.n)
1483
+ s = np.arange(len(self.fscan))
1484
+
1485
+ if len(np.asarray(om).shape) == 0:
1486
+ om = np.full(len(self.fscan),om)
1487
+
1488
+ if len(np.asarray(alpha).shape) == 0:
1489
+ alpha = np.full(len(self.fscan),alpha)
1490
+
1491
+ yx1 = np.vstack((y,x)).T
1492
+ yx2 = np.full_like(yx1, np.inf)
1493
+
1494
+ for i in range(len(self.fscan)):
1495
+
1496
+ pos = [alpha[i],delta[i],gamma[i],
1497
+ om[i],
1498
+ self.ubcalc.chi,
1499
+ self.ubcalc.phi]
1500
+ #pos = np.vstack(pos).T
1501
+ hkl = np.array(self.ubcalc.angles.anglesToHkl(*pos))
1502
+ hkl_del_gam_1[i, :3] = hkl
1503
+ hkl_del_gam_1[:, 3] = delta
1504
+ hkl_del_gam_1[:, 4] = gamma
1505
+ hkl_del_gam_1[:, 5] = self.fscan.axis
1506
+ hkl_del_gam_2 = np.full_like(hkl_del_gam_1, -1)
1507
+ else:
1508
+ hkl_del_gam_1 = np.ones(6,dtype=np.float64)
1509
+ x = self.scanSelector.xy_static[0].value()
1510
+ y = self.scanSelector.xy_static[1].value()
1511
+ yx1 = np.zeros((1,2))
1512
+ yx1[0][0] = y
1513
+ yx1[0][1] = x
1514
+ yx2 = np.full_like(yx1, np.inf)
1515
+
1516
+ if len(np.asarray(om).shape) > 0:
1517
+ om = om[imageno]
1518
+ if len(np.asarray(mu).shape) > 0:
1519
+ mu = mu[imageno]
1520
+ gamma, delta, alpha = self.ubcalc.detectorCal.crystalAnglesPoint(np.array([y]),np.array([x]), mu, self.ubcalc.n)
1521
+ pos = [alpha,delta,gamma,om,self.ubcalc.chi,self.ubcalc.phi]
1522
+ hkl_del_gam_1[:3] = np.concatenate(self.ubcalc.angles.anglesToHkl(*pos))
1523
+ hkl_del_gam_1[3] = delta
1524
+ hkl_del_gam_1[4] = gamma
1525
+ hkl_del_gam_1[5] = self.fscan.axis[imageno]
1526
+ hkl_del_gam_2 = np.full_like(hkl_del_gam_1, -1)
1527
+
1528
+ else:
1529
+ if H_0 is None or H_1 is None:
1530
+ H_1 = np.array([h.value() for h in self.scanSelector.H_1])
1531
+ H_0 = np.array([h.value() for h in self.scanSelector.H_0])
1532
+
1533
+ hkl_del_gam_1, hkl_del_gam_2, Qa_1, Qa_2 = angles.anglesIntersectLineEwald(H_0, H_1, mu_cryst, om, self.ubcalc.phi,self.ubcalc.chi, Qalpha=True)
1534
+ # H, K, L ,delta_1, gamma_1, HKL_Q1[-1]=s
1535
+
1536
+ delta1 = hkl_del_gam_1[...,3]
1537
+ delta2 = hkl_del_gam_2[...,3]
1538
+ gam1 = hkl_del_gam_1[...,4]
1539
+ gam2 = hkl_del_gam_2[...,4]
1540
+
1541
+ Qmin, Qmax = dc.Qrange
1542
+ Qa_1_n = np.linalg.norm(Qa_1, axis=-1)
1543
+ Qa_2_n = np.linalg.norm(Qa_2, axis=-1)
1544
+
1545
+
1546
+ mask1 = np.logical_and(Qmin <= Qa_1_n , Qmax >= Qa_1_n)
1547
+ mask2 = np.logical_and(Qmin <= Qa_2_n , Qmax >= Qa_2_n)
1548
+
1549
+ yx1 = dc.pixelsCrystalAngles(gam1, delta1, mu, self.ubcalc.n)
1550
+ yx2 = dc.pixelsCrystalAngles(gam2, delta2, mu, self.ubcalc.n)
1551
+ yx1[~mask1] = np.inf
1552
+ yx2[~mask2] = np.inf
1553
+
1554
+ ymask1 = np.logical_and(yx1[...,0] >= 0, yx1[...,0] < dc.detector.shape[0])
1555
+ xmask1 = np.logical_and(yx1[...,1] >= 0, yx1[...,1] < dc.detector.shape[1])
1556
+ yxmask1 = np.logical_and(xmask1,ymask1)
1557
+
1558
+ ymask2 = np.logical_and(yx2[...,0] >= 0, yx2[...,0] < dc.detector.shape[0])
1559
+ xmask2 = np.logical_and(yx2[...,1] >= 0, yx2[...,1] < dc.detector.shape[1])
1560
+ yxmask2 = np.logical_and(xmask2,ymask2)
1561
+
1562
+ xy1 = yx1[...,::-1]
1563
+ xy2 = yx2[...,::-1]
1564
+
1565
+ if not kwargs.get('intersect', False):
1566
+ xoffset = self.scanSelector.offsetx.value()
1567
+ yoffset = self.scanSelector.offsety.value()
1568
+
1569
+ if xoffset != 0. or yoffset != 0.:
1570
+ warnings.warn("Nonzero pixel offset selected. Experimental feature! Angles and hkl are incorrect!!!")
1571
+ xy1[..., 0] += xoffset
1572
+ xy2[..., 0] += xoffset
1573
+ xy1[..., 1] += yoffset
1574
+ xy2[..., 1] += yoffset
1575
+
1576
+ return np.concatenate((np.atleast_2d(hkl_del_gam_1), xy1, yxmask1[...,np.newaxis]),axis=-1),\
1577
+ np.concatenate((np.atleast_2d(hkl_del_gam_2), xy2, yxmask2[...,np.newaxis]),axis=-1)
1578
+
1579
+ def plotROI(self, loc):
1580
+
1581
+ key = self.intkey(loc)
1582
+ bkgkey = self.bkgkeys(loc)
1583
+ for roi in self.rois:
1584
+ roi.setVisible(True)
1585
+
1586
+ #print([(roi, roi.isEditable()) for roi in self.rois])
1587
+
1588
+ #croi:
1589
+ self.rois[4].setGeometry(origin=(key[0].start, key[1].start), size=(key[0].stop - key[0].start, key[1].stop - key[1].start))
1590
+ #self.rois[4].setVisible(True)
1591
+ for i,k in enumerate(bkgkey,0):
1592
+ self.rois[i].setGeometry(origin=(k[0].start, k[1].start), size=( k[0].stop - k[0].start, k[1].stop - k[1].start))
1593
+
1594
+ self.roiManager._roisUpdated()
1595
+
1596
+ #print([str(r) for r in self.roiManager.getRois()])
1597
+ self.centralPlot.addMarker(loc[0],loc[1],legend='main_croi_loc')
1598
+
1599
+ def integrateROI(self):
1600
+ try:
1601
+ image = self.fscan.get_raw_img(0)
1602
+ except Exception as e:
1603
+ print("no images found! %s" % e)
1604
+ return
1605
+ if self.database.nxfile is None:
1606
+ print("No database available")
1607
+ return
1608
+ dc = self.ubcalc.detectorCal
1609
+ #mu = self.ubcalc.mu
1610
+ angles = self.ubcalc.angles
1611
+
1612
+ H_1 = np.array([h.value() for h in self.scanSelector.H_1])
1613
+ H_0 = np.array([h.value() for h in self.scanSelector.H_0])
1614
+
1615
+ imgmask = None
1616
+
1617
+ if self.scanSelector.useMaskBox.isChecked():
1618
+ if self.centralPlot.getMaskToolsDockWidget().getSelectionMask() is None:
1619
+ btn = qt.QMessageBox.question(self,"No mask available","""No mask was selected with the masking tool.
1620
+ Do you want to continue without mask?""")
1621
+ if btn != qt.QMessageBox.Yes:
1622
+ return
1623
+ else:
1624
+ imgmask = self.centralPlot.getMaskToolsDockWidget().getSelectionMask() > 0.
1625
+
1626
+ corr = self.scanSelector.useSolidAngleBox.isChecked() or\
1627
+ self.scanSelector.usePolarizationBox.isChecked()
1628
+
1629
+ if corr:
1630
+ C_arr = np.ones(dc.detector.shape,dtype=np.float64)
1631
+ if self.scanSelector.useSolidAngleBox.isChecked():
1632
+ C_arr /= dc.solidAngleArray()
1633
+ if self.scanSelector.usePolarizationBox.isChecked():
1634
+ C_arr /= dc.polarization(factor=dc._polFactor,axis_offset=dc._polAxis)
1635
+
1636
+
1637
+ hkl_del_gam_s1, hkl_del_gam_s2 = self.getROIloc()
1638
+
1639
+ nodatapoints = len(self.fscan)
1640
+ #print(hkl_del_gam_1s.shape)
1641
+
1642
+ if hkl_del_gam_s1.shape[0] == 1:
1643
+ hkl_del_gam_1 = np.zeros((nodatapoints,hkl_del_gam_s1.shape[1]), dtype=np.float64)
1644
+ hkl_del_gam_2 = np.zeros((nodatapoints,hkl_del_gam_s1.shape[1]), dtype=np.float64)
1645
+ hkl_del_gam_1[:] = hkl_del_gam_s1[0]
1646
+ hkl_del_gam_2[:] = hkl_del_gam_s2[0]
1647
+ else:
1648
+ hkl_del_gam_1, hkl_del_gam_2 = hkl_del_gam_s1, hkl_del_gam_s2
1649
+
1650
+
1651
+ dataavail = np.logical_or(hkl_del_gam_1[:,-1],hkl_del_gam_2[:,-1])
1652
+
1653
+ croi1_a = np.zeros_like(dataavail,dtype=np.float64)
1654
+ cpixel1_a = np.zeros_like(dataavail,dtype=np.float64)
1655
+ bgroi1_a = np.zeros_like(dataavail,dtype=np.float64)
1656
+ bgpixel1_a = np.zeros_like(dataavail,dtype=np.float64)
1657
+ x_coord1_a = hkl_del_gam_1[:,6]
1658
+ y_coord1_a = hkl_del_gam_1[:,7]
1659
+
1660
+ croi2_a = np.zeros_like(dataavail,dtype=np.float64)
1661
+ cpixel2_a = np.zeros_like(dataavail,dtype=np.float64)
1662
+ bgroi2_a = np.zeros_like(dataavail,dtype=np.float64)
1663
+ bgpixel2_a = np.zeros_like(dataavail,dtype=np.float64)
1664
+ x_coord2_a = hkl_del_gam_2[:,6]
1665
+ y_coord2_a = hkl_del_gam_2[:,7]
1666
+
1667
+ progress = qt.QProgressDialog("Integrating images","abort",0,len(self.fscan),self)
1668
+ progress.setWindowModality(qt.Qt.WindowModal)
1669
+
1670
+ def sumImage(i):
1671
+ if not dataavail[i]:
1672
+ croi1 = np.nan; croi2 = np.nan
1673
+ cpixel1 = np.nan; cpixel2 = np.nan
1674
+ bgroi1 = np.nan; bgroi2 = np.nan
1675
+ bgpixel1 = np.nan; bgpixel2 = np.nan
1676
+ else:
1677
+ image = self.fscan.get_raw_img(i).img.astype(np.float64)
1678
+ if imgmask is not None:
1679
+ image[imgmask] = np.nan
1680
+ pixelavail = (~imgmask).astype(np.float64)
1681
+ else:
1682
+ pixelavail = np.ones_like(image)
1683
+ if corr:
1684
+ image *= C_arr
1685
+
1686
+ if hkl_del_gam_1[i,-1]:
1687
+ key = self.intkey(hkl_del_gam_1[i,6:8])
1688
+ bkgkey = self.bkgkeys(hkl_del_gam_1[i,6:8])
1689
+
1690
+ cimg = image[key[::-1]]
1691
+
1692
+ # !!!!!!!!!! add mask here !!!!!!!!!
1693
+ croi1 = np.nansum(cimg)
1694
+ cpixel1 = np.nansum(pixelavail[key[::-1]])
1695
+ bgroi1 = 0.
1696
+ bgpixel1 = 0.
1697
+ for bg in bkgkey:
1698
+ bgimg = image[bg[::-1]]
1699
+ bgroi1 += np.nansum(bgimg)
1700
+ bgpixel1 += np.nansum(pixelavail[bg[::-1]])
1701
+ else:
1702
+ croi1 = np.nan
1703
+ cpixel1 = np.nan
1704
+ bgroi1 = np.nan
1705
+ bgpixel1 = np.nan
1706
+
1707
+ if hkl_del_gam_2[i,-1]:
1708
+ key = self.intkey(hkl_del_gam_2[i,6:8])
1709
+ bkgkey = self.bkgkeys(hkl_del_gam_2[i,6:8])
1710
+
1711
+ cimg = image[key[::-1]]
1712
+ # !!!!!!!!!! add mask here !!!!!!!!!
1713
+ croi2 = np.nansum(cimg)
1714
+ cpixel2 = np.nansum(pixelavail[key[::-1]])
1715
+ bgroi2 = 0.
1716
+ bgpixel2 = 0.
1717
+ for bg in bkgkey:
1718
+ bgimg = image[bg[::-1]]
1719
+ bgroi2 += np.nansum(bgimg)
1720
+ bgpixel2 += np.nansum(pixelavail[bg[::-1]])
1721
+
1722
+ else:
1723
+ croi2 = np.nan
1724
+ cpixel2 = np.nan
1725
+ bgroi2 = np.nan
1726
+ bgpixel2 = np.nan
1727
+
1728
+ return (croi1, cpixel1, bgroi1, bgpixel1), (croi2, cpixel2, bgroi2, bgpixel2)
1729
+
1730
+
1731
+ with concurrent.futures.ThreadPoolExecutor(max_workers=self.numberthreads) as executor: # speedup only for the file reads
1732
+ futures = {}
1733
+ for i in range(len(self.fscan)):
1734
+ futures[executor.submit(sumImage, i)] = i
1735
+
1736
+ for f in concurrent.futures.as_completed(futures):
1737
+ try:
1738
+ (croi1, cpixel1, bgroi1, bgpixel1), (croi2, cpixel2, bgroi2, bgpixel2) = f.result()
1739
+ i = futures[f]
1740
+ croi1_a[i] = croi1
1741
+ cpixel1_a[i] = cpixel1
1742
+ bgroi1_a[i] = bgroi1
1743
+ bgpixel1_a[i] = bgpixel1
1744
+ croi2_a[i] = croi2
1745
+ cpixel2_a[i] = cpixel2
1746
+ bgroi2_a[i] = bgroi2
1747
+ bgpixel2_a[i] = bgpixel2
1748
+
1749
+ progress.setValue(futures[f])
1750
+ except concurrent.futures.CancelledError:
1751
+ pass
1752
+ except Exception as e:
1753
+ print("Cannot read image:\n%s" % traceback.format_exc())
1754
+
1755
+ if progress.wasCanceled():
1756
+ [f.cancel() for f in futures]
1757
+ break
1758
+
1759
+
1760
+ progress.setValue(len(self.fscan))
1761
+
1762
+ if np.any(bgpixel1_a):
1763
+ croibg1_a = croi1_a - (cpixel1_a/bgpixel1_a) * bgroi1_a
1764
+ croibg1_err_a = np.sqrt(croi1_a + ((cpixel1_a/bgpixel1_a)**2) * bgroi1_a)
1765
+ else:
1766
+ croibg1_a = croi1_a
1767
+ croibg1_err_a = np.sqrt(croi1_a)
1768
+
1769
+ if np.any(bgpixel2_a):
1770
+ croibg2_a = croi2_a - (cpixel2_a/bgpixel2_a) * bgroi2_a
1771
+ croibg2_err_a = np.sqrt(croi2_a + ((cpixel2_a/bgpixel2_a)**2) * bgroi2_a)
1772
+ else:
1773
+ croibg2_a = croi2_a
1774
+ croibg2_err_a = np.sqrt(croi2_a)
1775
+
1776
+ rod_mask1 = np.isfinite(croibg1_a)
1777
+ rod_mask2 = np.isfinite(croibg2_a)
1778
+
1779
+ s1_masked = hkl_del_gam_1[:,5][rod_mask1]
1780
+ s2_masked = hkl_del_gam_2[:,5][rod_mask2]
1781
+
1782
+ croibg1_a_masked = croibg1_a[rod_mask1]
1783
+ croibg2_a_masked = croibg2_a[rod_mask2]
1784
+
1785
+ croibg1_err_a_masked = croibg1_err_a[rod_mask1]
1786
+ croibg2_err_a_masked = croibg2_err_a[rod_mask2]
1787
+
1788
+ #name = str(H_1) + "*s+" + str(H_0)
1789
+ if self.scanSelector.scanstab.currentIndex() == 1:
1790
+ x = self.scanSelector.xy_static[0].value()
1791
+ y = self.scanSelector.xy_static[1].value()
1792
+ name1 = "pixloc[%.2f %.2f]" % (x,y)
1793
+ name2 = "pixloc[%.2f %.2f]_2" % (x,y) # does not exist, Just for compatibility
1794
+ traj1 = {
1795
+ "@NX_class": u"NXcollection",
1796
+ "@direction" : u"Fixed pixel coordinates",
1797
+ "s" : hkl_del_gam_1[:,5]
1798
+ }
1799
+ traj2 = {
1800
+ "@NX_class": u"NXcollection",
1801
+ "@direction" : u"Fixed pixel coordinates",
1802
+ "s" : hkl_del_gam_2[:,5]
1803
+ }
1804
+ else:
1805
+ name1 = str(H_1) + "*s1+" + str(H_0)
1806
+ name2 = str(H_1) + "*s2+" + str(H_0)
1807
+ traj1 = {
1808
+ "@NX_class": u"NXcollection",
1809
+ "@direction" : u"Intergrated along H_1*s + H_0 in reciprocal space",
1810
+ "H_1" : H_1,
1811
+ "H_0" : H_0,
1812
+ "s" : hkl_del_gam_1[:,5]
1813
+ }
1814
+ traj2 = {
1815
+ "@NX_class": u"NXcollection",
1816
+ "@direction" : u"Intergrated along H_1*s + H_0 in reciprocal space",
1817
+ "H_1" : H_1,
1818
+ "H_0" : H_0,
1819
+ "s" : hkl_del_gam_2[:,5]
1820
+ }
1821
+
1822
+
1823
+ defaultS1 = croibg1_a_masked.size > croibg2_a_masked.size
1824
+
1825
+ if hasattr(self.fscan, "title"):
1826
+ title = str(self.fscan.title)
1827
+ else:
1828
+ title = u"%s-scan" % self.fscan.axisname
1829
+
1830
+ mu, om = self.getMuOm()
1831
+ if len(np.asarray(om).shape) == 0:
1832
+ om = np.full_like(mu,om)
1833
+ if len(np.asarray(mu).shape) == 0:
1834
+ mu = np.full_like(om,mu)
1835
+
1836
+ suffix = ''
1837
+ i = 0
1838
+
1839
+ while(self.activescanname + "/measurement/" + name1 + suffix in self.database.nxfile):
1840
+ suffix = "_%s" % i
1841
+ i += 1
1842
+ availname1 = name1 + suffix
1843
+
1844
+ suffix = ''
1845
+ i = 0
1846
+ while(self.activescanname + "/measurement/" + name2 + suffix in self.database.nxfile):
1847
+ suffix = "_%s" % i
1848
+ i += 1
1849
+
1850
+ availname2 = name2 + suffix
1851
+
1852
+ auxcounters = {"@NX_class": u"NXcollection"}
1853
+ for auxname in backends.auxillary_counters:
1854
+ if hasattr(self.fscan, auxname):
1855
+ cntr = getattr(self.fscan, auxname)
1856
+ if cntr is not None:
1857
+ auxcounters[auxname] = cntr
1858
+
1859
+
1860
+ datas1 = {
1861
+ "@NX_class": u"NXdata",
1862
+ "sixc_angles": {
1863
+ "@NX_class": u"NXpositioner",
1864
+ "alpha" : np.rad2deg(mu),
1865
+ "omega" : np.rad2deg(om),
1866
+ "theta" : np.rad2deg(-1*om),
1867
+ "delta" : np.rad2deg(hkl_del_gam_1[:,3]),
1868
+ "gamma" : np.rad2deg(hkl_del_gam_1[:,4]),
1869
+ "chi" : np.rad2deg(self.ubcalc.chi),
1870
+ "phi" : np.rad2deg(self.ubcalc.phi),
1871
+ "@unit" : u"deg"
1872
+ },
1873
+ "hkl": {
1874
+ "@NX_class": u"NXcollection",
1875
+ "h" : hkl_del_gam_1[:,0],
1876
+ "k" : hkl_del_gam_1[:,1],
1877
+ "l" : hkl_del_gam_1[:,2]
1878
+ },
1879
+ "counters":{
1880
+ "@NX_class": u"NXdetector",
1881
+ "croibg" : croibg1_a,
1882
+ "croibg_errors" : croibg1_err_a,
1883
+ "croi" : croi1_a,
1884
+ "bgroi" : bgroi1_a,
1885
+ "croi_pix" : cpixel1_a,
1886
+ "bgroi_pix" : bgpixel1_a
1887
+ },
1888
+ "pixelcoord": {
1889
+ "@NX_class": u"NXdetector",
1890
+ "x" : x_coord1_a,
1891
+ "y" : y_coord1_a
1892
+ },
1893
+ "trajectory" : traj1,
1894
+ "@signal" : u"counters/croibg",
1895
+ "@axes": u"trajectory/s",
1896
+ "@title": self.activescanname + "_" + availname1,
1897
+ "@orgui_meta": u"roi"
1898
+ }
1899
+
1900
+ datas2 = {
1901
+ "@NX_class": u"NXdata",
1902
+ "sixc_angles": {
1903
+ "@NX_class": u"NXpositioner",
1904
+ "alpha" : np.rad2deg(mu),
1905
+ "omega" : np.rad2deg(om),
1906
+ "theta" : np.rad2deg(-1*om),
1907
+ "delta" : np.rad2deg(hkl_del_gam_2[:,3]),
1908
+ "gamma" : np.rad2deg(hkl_del_gam_2[:,4]),
1909
+ "chi" : np.rad2deg(self.ubcalc.chi),
1910
+ "phi" : np.rad2deg(self.ubcalc.phi),
1911
+ "@unit" : u"deg"
1912
+ },
1913
+ "hkl": {
1914
+ "@NX_class": u"NXcollection",
1915
+ "h" : hkl_del_gam_2[:,0],
1916
+ "k" : hkl_del_gam_2[:,1],
1917
+ "l" : hkl_del_gam_2[:,2]
1918
+ },
1919
+ "counters":{
1920
+ "@NX_class": u"NXdetector",
1921
+ "croibg" : croibg2_a,
1922
+ "croibg_errors" : croibg2_err_a,
1923
+ "croi" : croi2_a,
1924
+ "bgroi" : bgroi2_a,
1925
+ "croi_pix" : cpixel2_a,
1926
+ "bgroi_pix" : bgpixel2_a
1927
+ },
1928
+ "pixelcoord": {
1929
+ "@NX_class": u"NXdetector",
1930
+ "x" : x_coord2_a,
1931
+ "y" : y_coord2_a
1932
+ },
1933
+ "trajectory" : traj2,
1934
+ "@signal" : u"counters/croibg",
1935
+ "@axes": u"trajectory/s",
1936
+ "@title": self.activescanname + "_" + availname2,
1937
+ "@orgui_meta": u"roi"
1938
+ }
1939
+
1940
+ data = {self.activescanname:{
1941
+ "instrument": {
1942
+ "@NX_class": u"NXinstrument",
1943
+ "positioners": {
1944
+ "@NX_class": u"NXcollection",
1945
+ self.fscan.axisname: self.fscan.axis
1946
+ }
1947
+ },
1948
+ "auxillary" : auxcounters,
1949
+ "measurement": {
1950
+ "@NX_class": u"NXentry",
1951
+ "@default": availname1 if defaultS1 else availname2,
1952
+ },
1953
+ "title":u"%s" % title,
1954
+ "@NX_class": u"NXentry",
1955
+ "@default": u"measurement/%s" % (availname1 if defaultS1 else availname2),
1956
+ "@orgui_meta": u"scan"
1957
+ }
1958
+ }
1959
+
1960
+ if np.any(cpixel1_a > 0.):
1961
+
1962
+ self.integrdataPlot.addCurve(s1_masked,croibg1_a_masked,legend=self.activescanname + "_" + availname1,
1963
+ xlabel="trajectory/s", ylabel="counters/croibg", yerror=croibg1_err_a_masked)
1964
+
1965
+ data[self.activescanname]["measurement"][availname1] = datas1
1966
+ if np.any(cpixel2_a > 0.):
1967
+
1968
+ self.integrdataPlot.addCurve(s2_masked,croibg2_a_masked,legend=self.activescanname + "_" + availname2,
1969
+ xlabel="trajectory/s", ylabel="counters/croibg", yerror=croibg2_err_a_masked)
1970
+
1971
+ data[self.activescanname]["measurement"][availname2] = datas2
1972
+
1973
+ self.database.add_nxdict(data)
1974
+
1975
+
1976
+
1977
+
1978
+ def _graphCallback(self,eventdict):
1979
+ #print(eventdict)
1980
+ if eventdict['event'] == 'mouseDoubleClicked':
1981
+ #newReflection = np.array([1,1,1,self.imageno,eventdict['x'],eventdict['y']])
1982
+ if self.scanSelector.select_roi_action.isChecked():
1983
+ self.scanSelector.set_xy_static_loc(eventdict['x'], eventdict['y'])
1984
+ self.scanSelector.select_roi_action.setChecked(False)
1985
+ else:
1986
+ hkl = self.centralPlot.xyHKLConverter(eventdict['x'],eventdict['y'])[:3]
1987
+ self.reflectionSel.addReflection(eventdict,self.imageno,hkl)
1988
+
1989
+ if eventdict['event'] == 'markerMoved':
1990
+ self.reflectionSel.moveReflection(eventdict['label'],[eventdict['x'],eventdict['y']])
1991
+ self.reflectionSel.setReflectionActive(eventdict['label'])
1992
+ if eventdict['event'] == 'markerClicked':
1993
+ self.reflectionSel.setReflectionActive(eventdict['label'])
1994
+
1995
+ def intkey(self, coords):
1996
+
1997
+ vsize = int(self.scanSelector.vsize.value())
1998
+ hsize = int(self.scanSelector.hsize.value())
1999
+
2000
+ detvsize, dethsize = self.ubcalc.detectorCal.detector.shape
2001
+
2002
+ coord_restr = np.clip( np.asarray(coords), [0,0], [dethsize, detvsize])
2003
+
2004
+
2005
+ vhalfsize = vsize // 2
2006
+ hhalfsize = hsize // 2
2007
+ fromcoords = np.round(np.asarray(coord_restr) - np.array([hhalfsize, vhalfsize]))
2008
+ tocoords = np.round(np.asarray(coord_restr) + np.array([hhalfsize, vhalfsize]))
2009
+
2010
+ if hsize % 2:
2011
+ if coord_restr[0] % 1 < 0.5:
2012
+ tocoords[0] += 1
2013
+ else:
2014
+ fromcoords[0] -= 1
2015
+ if vsize % 2:
2016
+ if coord_restr[1] % 1 < 0.5:
2017
+ tocoords[1] += 1
2018
+ else:
2019
+ fromcoords[1] -= 1
2020
+
2021
+ fromcoords = np.clip( np.asarray(fromcoords), [0,0], [dethsize, detvsize])
2022
+ tocoords = np.clip( np.asarray(tocoords), [0,0], [dethsize, detvsize])
2023
+
2024
+ loc = tuple(slice(int(fromcoord), int(tocoord)) for fromcoord, tocoord in zip(fromcoords,tocoords))
2025
+
2026
+ #from IPython import embed; embed()
2027
+
2028
+ return loc
2029
+
2030
+ def bkgkeys(self, coords):
2031
+
2032
+ left = int(self.scanSelector.left.value())
2033
+ right = int(self.scanSelector.right.value())
2034
+ top = int(self.scanSelector.top.value())
2035
+ bottom = int(self.scanSelector.bottom.value())
2036
+
2037
+ detvsize, dethsize = self.ubcalc.detectorCal.detector.shape
2038
+
2039
+ croi = self.intkey(coords)
2040
+ hcroikey = croi[0]
2041
+ vcroikey = croi[1]
2042
+
2043
+ leftkey = (slice(int(np.clip(croi[0].start - left, 0, dethsize)), croi[0].start), croi[1])
2044
+ rightkey = (slice(croi[0].stop,int(np.clip(croi[0].stop + right, 0, dethsize))), croi[1])
2045
+
2046
+ topkey = (croi[0], slice(int(np.clip(croi[1].start - top, 0, detvsize)), croi[1].start))
2047
+ bottomkey = (croi[0], slice(croi[1].stop, int(np.clip(croi[1].stop + bottom,0,detvsize)) ))
2048
+ return leftkey, rightkey, topkey, bottomkey
2049
+
2050
+ def closeEvent(self,event):
2051
+ self.database.close()
2052
+ super().closeEvent(event)
2053
+
2054
+
2055
+ class Plot2DHKL(silx.gui.plot.PlotWindow):
2056
+ sigKeyPressDelete = qt.pyqtSignal()
2057
+
2058
+ def __init__(self,xyHKLConverter,parent=None,backend=None):
2059
+ self.xyHKLConverter = xyHKLConverter
2060
+
2061
+
2062
+ posInfo = [
2063
+ ('X', lambda x, y: x),
2064
+ ('Y', lambda x, y: y),
2065
+ ('H', lambda x, y: self.xyHKLConverter(x,y)[0]),
2066
+ ('K', lambda x, y: self.xyHKLConverter(x,y)[1]),
2067
+ ('L', lambda x, y: self.xyHKLConverter(x,y)[2]),
2068
+ ('del', lambda x, y: self.xyHKLConverter(x,y)[3]),
2069
+ ('gam', lambda x, y: self.xyHKLConverter(x,y)[4]),
2070
+ ('Data', WeakMethodProxy(self._getImageValue))]
2071
+
2072
+ super(Plot2DHKL, self).__init__(parent=parent, backend=backend,
2073
+ resetzoom=True, autoScale=False,
2074
+ logScale=False, grid=False,
2075
+ curveStyle=False, colormap=True,
2076
+ aspectRatio=True, yInverted=True,
2077
+ copy=True, save=True, print_=True,
2078
+ control=True, position=posInfo,
2079
+ roi=False, mask=True)
2080
+
2081
+ if parent is None:
2082
+ self.setWindowTitle('Plot2D')
2083
+ self.getXAxis().setLabel('Columns')
2084
+ self.getYAxis().setLabel('Rows')
2085
+
2086
+ #if silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION == 'downward':
2087
+ self.getYAxis().setInverted(True)
2088
+
2089
+
2090
+ self.profile = ProfileToolBar(plot=self)
2091
+ self.addToolBar(self.profile)
2092
+
2093
+ self.colorbarAction.setVisible(True)
2094
+ self.getColorBarWidget().setVisible(True)
2095
+
2096
+ # Put colorbar action after colormap action
2097
+ actions = self.toolBar().actions()
2098
+ for action in actions:
2099
+ if action is self.getColormapAction():
2100
+ break
2101
+
2102
+ self.sigActiveImageChanged.connect(self.__activeImageChanged)
2103
+
2104
+ def keyPressEvent(self, event):
2105
+ key = event.key()
2106
+ if key == qt.Qt.Key_Delete and not event.isAutoRepeat():
2107
+ self.sigKeyPressDelete.emit()
2108
+ super(Plot2DHKL, self).keyPressEvent(event)
2109
+
2110
+ def setXyHKLconverter(self,xyHKLConverter):
2111
+ self.xyHKLConverter = xyHKLConverter
2112
+
2113
+ def __activeImageChanged(self, previous, legend):
2114
+ """Handle change of active image
2115
+
2116
+ :param Union[str,None] previous: Legend of previous active image
2117
+ :param Union[str,None] legend: Legend of current active image
2118
+ """
2119
+ if previous is not None:
2120
+ item = self.getImage(previous)
2121
+ if item is not None:
2122
+ item.sigItemChanged.disconnect(self.__imageChanged)
2123
+
2124
+ if legend is not None:
2125
+ item = self.getImage(legend)
2126
+ item.sigItemChanged.connect(self.__imageChanged)
2127
+
2128
+ positionInfo = self.getPositionInfoWidget()
2129
+ if positionInfo is not None:
2130
+ positionInfo.updateInfo()
2131
+
2132
+ def __imageChanged(self, event):
2133
+ """Handle update of active image item
2134
+
2135
+ :param event: Type of changed event
2136
+ """
2137
+ if event == items.ItemChangedType.DATA:
2138
+ positionInfo = self.getPositionInfoWidget()
2139
+ if positionInfo is not None:
2140
+ positionInfo.updateInfo()
2141
+
2142
+ def _getImageValue(self, x, y):
2143
+ """Get status bar value of top most image at position (x, y)
2144
+
2145
+ :param float x: X position in plot coordinates
2146
+ :param float y: Y position in plot coordinates
2147
+ :return: The value at that point or '-'
2148
+ """
2149
+ value = '-'
2150
+ valueZ = -float('inf')
2151
+ mask = 0
2152
+ maskZ = -float('inf')
2153
+
2154
+ for image in self.getAllImages():
2155
+ data = image.getData(copy=False)
2156
+ isMask = isinstance(image, items.MaskImageData)
2157
+ if isMask:
2158
+ zIndex = maskZ
2159
+ else:
2160
+ zIndex = valueZ
2161
+ if image.getZValue() >= zIndex:
2162
+ # This image is over the previous one
2163
+ ox, oy = image.getOrigin()
2164
+ sx, sy = image.getScale()
2165
+ row, col = (y - oy) / sy, (x - ox) / sx
2166
+ if row >= 0 and col >= 0:
2167
+ # Test positive before cast otherwise issue with int(-0.5) = 0
2168
+ row, col = int(row), int(col)
2169
+ if (row < data.shape[0] and col < data.shape[1]):
2170
+ v, z = data[row, col], image.getZValue()
2171
+ if not isMask:
2172
+ value = v
2173
+ valueZ = z
2174
+ else:
2175
+ mask = v
2176
+ maskZ = z
2177
+ if maskZ > valueZ and mask > 0:
2178
+ return value, "Masked"
2179
+ return value
2180
+
2181
+ def _getImageDims(self, *args):
2182
+ activeImage = self.getActiveImage()
2183
+ if (activeImage is not None and
2184
+ activeImage.getData(copy=False) is not None):
2185
+ dims = activeImage.getData(copy=False).shape[1::-1]
2186
+ return 'x'.join(str(dim) for dim in dims)
2187
+ else:
2188
+ return '-'
2189
+
2190
+ def getProfileToolbar(self):
2191
+ """Profile tools attached to this plot
2192
+
2193
+ See :class:`silx.gui.plot.Profile.ProfileToolBar`
2194
+ """
2195
+ return self.profile
2196
+
2197
+ #@deprecated(replacement="getProfilePlot", since_version="0.5.0")
2198
+ def getProfileWindow(self):
2199
+ return self.getProfilePlot()
2200
+
2201
+ def getProfilePlot(self):
2202
+ """Return plot window used to display profile curve.
2203
+
2204
+ :return: :class:`Plot1D`
2205
+ """
2206
+ return self.profile.getProfilePlot()
2207
+
2208
+ class QImportScanCreator(qt.QDialog):
2209
+
2210
+ def __init__(self,defaultMuTh, parent=None):
2211
+ qt.QDialog.__init__(self, parent)
2212
+ self.defaultMuTh = defaultMuTh
2213
+
2214
+ layout = qt.QGridLayout()
2215
+
2216
+ layout.addWidget(qt.QLabel("scan axis:"),0,0)
2217
+ layout.addWidget(qt.QLabel("axis start:"),1,0)
2218
+ layout.addWidget(qt.QLabel("axis end:"),2,0)
2219
+ self.fixed_label = qt.QLabel("mu (fixed):")
2220
+ layout.addWidget(self.fixed_label,3,0)
2221
+ layout.addWidget(qt.QLabel("no frames:"),5,0)
2222
+ layout.addWidget(qt.QLabel("Det pixel1:"),6,0)
2223
+ layout.addWidget(qt.QLabel("Det pixel2:"),7,0)
2224
+
2225
+ self.scanaxis = qt.QComboBox()
2226
+ self.scanaxis.addItem("theta")
2227
+ self.scanaxis.addItem("mu")
2228
+ self.scanaxis.setCurrentIndex(0)
2229
+ self.scanaxis.currentIndexChanged.connect(self.onScanAxisChanged)
2230
+
2231
+ self.omstart = qt.QDoubleSpinBox()
2232
+ self.omstart.setRange(-180,180)
2233
+ self.omstart.setDecimals(4)
2234
+ self.omstart.setSuffix(u" °")
2235
+ self.omstart.setValue(-90)
2236
+
2237
+ self.omend = qt.QDoubleSpinBox()
2238
+ self.omend.setRange(-180,180)
2239
+ self.omend.setDecimals(4)
2240
+ self.omend.setSuffix(u" °")
2241
+ self.omend.setValue(90)
2242
+
2243
+ self.no = qt.QSpinBox()
2244
+ self.no.setReadOnly(True)
2245
+ self.no.setRange(1,1000000000)
2246
+ self.no.setValue(180)
2247
+
2248
+ self.fixedAngle = qt.QDoubleSpinBox()
2249
+ self.fixedAngle.setRange(-180,180)
2250
+ self.fixedAngle.setValue(self.defaultMuTh[0])
2251
+
2252
+ self.shape1 = qt.QSpinBox()
2253
+ self.shape1.setReadOnly(True)
2254
+ self.shape1.setRange(1,1000000000)
2255
+ self.shape1.setValue(1)
2256
+
2257
+ self.shape2 = qt.QSpinBox()
2258
+ self.shape2.setReadOnly(True)
2259
+ #self.shape2.lineEdit().setReadOnly(True)
2260
+ self.shape2.setRange(1,1000000000)
2261
+ self.shape2.setValue(1)
2262
+
2263
+ layout.addWidget(self.scanaxis,0,1)
2264
+ layout.addWidget(self.omstart,1,1)
2265
+ layout.addWidget(self.omend,2,1)
2266
+ layout.addWidget(self.no,5,1)
2267
+ layout.addWidget(self.fixedAngle,3,1)
2268
+
2269
+ layout.addWidget(self.shape1,6,1)
2270
+ layout.addWidget(self.shape2,7,1)
2271
+
2272
+ buttons = qt.QDialogButtonBox(qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel)
2273
+ layout.addWidget(buttons,8,0,-1,-1)
2274
+
2275
+ test = qt.QLabel("Parameters determined from loaded scan:")
2276
+ layout.addWidget(test,4,0,1,2)
2277
+
2278
+ buttons.button(qt.QDialogButtonBox.Ok).clicked.connect(self.accept)
2279
+ buttons.button(qt.QDialogButtonBox.Cancel).clicked.connect(self.reject)
2280
+
2281
+ self.setLayout(layout)
2282
+
2283
+ def onScanAxisChanged(self, index):
2284
+ if index == 0:
2285
+ self.omstart.setValue(-90.)
2286
+ self.omend.setValue(90.)
2287
+ self.fixed_label.setText("mu (fixed):")
2288
+ self.fixedAngle.setValue(self.defaultMuTh[0])
2289
+
2290
+ elif index == 1:
2291
+ self.omstart.setValue(0.)
2292
+ self.omend.setValue(15.)
2293
+ self.fixed_label.setText("theta (fixed):")
2294
+ self.fixedAngle.setValue(self.defaultMuTh[1])
2295
+
2296
+ class QScanCreator(qt.QDialog):
2297
+
2298
+ def __init__(self,defaultMuTh, parent=None):
2299
+ qt.QDialog.__init__(self, parent)
2300
+ self.defaultMuTh = defaultMuTh
2301
+
2302
+ layout = qt.QGridLayout()
2303
+
2304
+ layout.addWidget(qt.QLabel("scan axis:"),0,0)
2305
+ layout.addWidget(qt.QLabel("axis start:"),1,0)
2306
+ layout.addWidget(qt.QLabel("axis end:"),2,0)
2307
+ layout.addWidget(qt.QLabel("no points:"),3,0)
2308
+ self.fixed_label = qt.QLabel("mu (fixed):")
2309
+ layout.addWidget(self.fixed_label,4,0)
2310
+ layout.addWidget(qt.QLabel("Det pixel1:"),5,0)
2311
+ layout.addWidget(qt.QLabel("Det pixel2:"),6,0)
2312
+
2313
+ self.scanaxis = qt.QComboBox()
2314
+ self.scanaxis.addItem("theta")
2315
+ self.scanaxis.addItem("mu")
2316
+ self.scanaxis.setCurrentIndex(0)
2317
+ self.scanaxis.currentIndexChanged.connect(self.onScanAxisChanged)
2318
+
2319
+ self.omstart = qt.QDoubleSpinBox()
2320
+ self.omstart.setRange(-180,180)
2321
+ self.omstart.setDecimals(4)
2322
+ self.omstart.setSuffix(u" °")
2323
+ self.omstart.setValue(-90)
2324
+
2325
+ self.omend = qt.QDoubleSpinBox()
2326
+ self.omend.setRange(-180,180)
2327
+ self.omend.setDecimals(4)
2328
+ self.omend.setSuffix(u" °")
2329
+ self.omend.setValue(90)
2330
+
2331
+ self.no = qt.QSpinBox()
2332
+ self.no.setRange(1,1000000000)
2333
+ self.no.setValue(180)
2334
+
2335
+ self.fixedAngle = qt.QDoubleSpinBox()
2336
+ self.fixedAngle.setRange(-180,180)
2337
+ self.fixedAngle.setValue(self.defaultMuTh[0])
2338
+
2339
+ self.shape1 = qt.QSpinBox()
2340
+ self.shape1.setRange(1,1000000000)
2341
+ self.shape1.setValue(1)
2342
+
2343
+ self.shape2 = qt.QSpinBox()
2344
+ self.shape2.setRange(1,1000000000)
2345
+ self.shape2.setValue(1)
2346
+
2347
+ layout.addWidget(self.scanaxis,0,1)
2348
+ layout.addWidget(self.omstart,1,1)
2349
+ layout.addWidget(self.omend,2,1)
2350
+ layout.addWidget(self.no,3,1)
2351
+ layout.addWidget(self.fixedAngle,4,1)
2352
+
2353
+ layout.addWidget(self.shape1,5,1)
2354
+ layout.addWidget(self.shape2,6,1)
2355
+
2356
+ buttons = qt.QDialogButtonBox(qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel)
2357
+ layout.addWidget(buttons,7,0,-1,-1)
2358
+
2359
+ buttons.button(qt.QDialogButtonBox.Ok).clicked.connect(self.accept)
2360
+ buttons.button(qt.QDialogButtonBox.Cancel).clicked.connect(self.reject)
2361
+
2362
+ self.setLayout(layout)
2363
+
2364
+ def onScanAxisChanged(self, index):
2365
+ if index == 0:
2366
+ self.omstart.setValue(-90.)
2367
+ self.omend.setValue(90.)
2368
+ self.fixed_label.setText("mu (fixed):")
2369
+ self.fixedAngle.setValue(self.defaultMuTh[0])
2370
+
2371
+ elif index == 1:
2372
+ self.omstart.setValue(0.)
2373
+ self.omend.setValue(15.)
2374
+ self.fixed_label.setText("theta (fixed):")
2375
+ self.fixedAngle.setValue(self.defaultMuTh[1])
2376
+
2377
+ class QRockingScanCreator(qt.QDialog):
2378
+
2379
+ def __init__(self, parent=None):
2380
+ qt.QDialog.__init__(self, parent)
2381
+
2382
+ layout = qt.QGridLayout()
2383
+
2384
+ hkl_layout = qt.QGridLayout()
2385
+
2386
+ self.selectedH = qt.QDoubleSpinBox()
2387
+ self.selectedH.setRange(-3,3)
2388
+ self.selectedH.setValue(0)
2389
+
2390
+ self.selectedK = qt.QDoubleSpinBox()
2391
+ self.selectedK.setRange(-3,3)
2392
+ self.selectedK.setValue(0)
2393
+
2394
+ self.Lmin = qt.QDoubleSpinBox()
2395
+ self.Lmin.setRange(0,20)
2396
+ self.Lmin.setDecimals(1)
2397
+ self.Lmin.setValue(1)
2398
+
2399
+ self.Lmax = qt.QDoubleSpinBox()
2400
+ self.Lmax.setRange(0,30)
2401
+ self.Lmax.setDecimals(1)
2402
+ self.Lmax.setValue(2)
2403
+
2404
+ self.interval = qt.QDoubleSpinBox()
2405
+ self.interval.setRange(0,10)
2406
+ self.interval.setDecimals(2)
2407
+ self.interval.setValue(0.1)
2408
+
2409
+ layout.addWidget(qt.QLabel("Select H,K,L of the CTR rocking scan"),0,0,1,-1)
2410
+
2411
+ layout.addWidget(qt.QLabel("H:"),1,0)
2412
+ layout.addWidget(self.selectedH,1,1)
2413
+ layout.addWidget(qt.QLabel("K:"),1,2)
2414
+ layout.addWidget(self.selectedK,1,3)
2415
+ layout.addWidget(qt.QLabel("L min:"),2,0)
2416
+ layout.addWidget(self.Lmin,2,1)
2417
+ layout.addWidget(qt.QLabel("L max:"),2,2)
2418
+ layout.addWidget(self.Lmax,2,3)
2419
+
2420
+ layout.addWidget(qt.QLabel("scan interval:"),3,0,1,-1)
2421
+ layout.addWidget(self.interval,3,3)
2422
+
2423
+ #layout.addLayout(hkl_layout,1,0)
2424
+
2425
+ buttons = qt.QDialogButtonBox(qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel)
2426
+ layout.addWidget(buttons,5,0,-1,-1)
2427
+
2428
+ buttons.button(qt.QDialogButtonBox.Ok).clicked.connect(self.accept)
2429
+ buttons.button(qt.QDialogButtonBox.Cancel).clicked.connect(self.reject)
2430
+
2431
+ self.setLayout(layout)
2432
+
2433
+ class QDiffractometerImageDialog(qt.QDialog):
2434
+ def __init__(self, parent=None):
2435
+ qt.QDialog.__init__(self, parent)
2436
+ verticalLayout = qt.QVBoxLayout(self)
2437
+ verticalLayout.setContentsMargins(0, 0, 0, 0)
2438
+ img = AspectRatioPixmapLabel(self)
2439
+ pixmp = qt.QPixmap(resources.getDiffractometerPath())
2440
+ #img.setScaledContents(False)
2441
+ img.setPixmap(pixmp)
2442
+
2443
+ verticalLayout.addWidget(img)
2444
+
2445
+ #reader = qt.QImageReader()
2446
+ #img = reader.read()
2447
+ #view = qt.QGraphicsView(self)
2448
+ #svg = qt.QSvgWidget(self)
2449
+ #svg.load(resources.getDiffractometerPath())
2450
+
2451
+ #verticalLayout.addWidget(svg)
2452
+ self.setLayout(verticalLayout)
2453
+
2454
+ class AspectRatioPixmapLabel(qt.QLabel):
2455
+ def __init__(self, parent=None):
2456
+ qt.QLabel.__init__(self, parent)
2457
+ self.setMinimumSize(1,1)
2458
+ self.setScaledContents(False)
2459
+ self.pix = None
2460
+
2461
+ def setPixmap(self, p):
2462
+ self.pix = p
2463
+ super().setPixmap(self.scaledPixmap())
2464
+
2465
+ def scaledPixmap(self):
2466
+ return self.pix.scaled(self.size(), qt.Qt.KeepAspectRatio, qt.Qt.SmoothTransformation)
2467
+
2468
+ def heightForWidth(self, width):
2469
+ if self.pix is None:
2470
+ return self.height()
2471
+ else:
2472
+ return int(( self.pix.height()* width) /self.pix.width())
2473
+
2474
+ def sizeHint(self):
2475
+ app = qt.QApplication.instance()
2476
+ desktopWidget = app.desktop()
2477
+ screenGeometry = desktopWidget.screenGeometry()
2478
+ w = int(screenGeometry.width()/3)
2479
+ w_s = self.width()
2480
+ return qt.QSize( max(w, w_s), self.heightForWidth(w))
2481
+
2482
+ def resizeEvent(self,e):
2483
+ if self.pix is not None:
2484
+ super().setPixmap(self.scaledPixmap())
2485
+
2486
+
2487
+
2488
+ class QRockingScanROI(qt.QDialog):
2489
+
2490
+ def __init__(self,roi_l,parent=None):
2491
+ qt.QDialog.__init__(self, parent)
2492
+
2493
+ layout = qt.QGridLayout()
2494
+
2495
+ hkl_layout = qt.QGridLayout()
2496
+
2497
+ self.roi_hsize = qt.QDoubleSpinBox()
2498
+ self.roi_hsize.setRange(1,500)
2499
+ self.roi_hsize.setValue(8)
2500
+
2501
+ self.roi_vsize = qt.QDoubleSpinBox()
2502
+ self.roi_vsize.setRange(1,500)
2503
+ self.roi_vsize.setValue(roi_l)
2504
+
2505
+ self.roi_hsize_bg = qt.QDoubleSpinBox()
2506
+ self.roi_hsize_bg.setRange(0,500)
2507
+ self.roi_hsize_bg.setValue(8)
2508
+
2509
+ self.roi_vsize_bg = qt.QDoubleSpinBox()
2510
+ self.roi_vsize_bg.setRange(0,500)
2511
+ self.roi_vsize_bg.setValue(8)
2512
+
2513
+
2514
+
2515
+ layout.addWidget(qt.QLabel("ROI parameters"),0,0,1,-1)
2516
+
2517
+ layout.addWidget(qt.QLabel("h-size:"),1,0)
2518
+ layout.addWidget(self.roi_hsize,1,1)
2519
+ layout.addWidget(qt.QLabel("v-size:"),1,2)
2520
+ layout.addWidget(self.roi_vsize,1,3)
2521
+ layout.addWidget(qt.QLabel("bg h-size:"),2,0)
2522
+ layout.addWidget(self.roi_hsize_bg,2,1)
2523
+ layout.addWidget(qt.QLabel("bg v-size:"),2,2)
2524
+ layout.addWidget(self.roi_vsize_bg,2,3)
2525
+
2526
+
2527
+ buttons = qt.QDialogButtonBox(qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel)
2528
+ layout.addWidget(buttons,3,0,-1,-1)
2529
+
2530
+ buttons.button(qt.QDialogButtonBox.Ok).clicked.connect(self.accept)
2531
+ buttons.button(qt.QDialogButtonBox.Cancel).clicked.connect(self.reject)
2532
+
2533
+ self.setLayout(layout)
2534
+
2535
+
2536
+
2537
+ class UncaughtHook(qt.QObject):
2538
+ #_exception_caught = qt.Signal(object)
2539
+
2540
+ def __init__(self, *args, **kwargs):
2541
+ super(UncaughtHook, self).__init__(*args, **kwargs)
2542
+
2543
+ # this registers the exception_hook() function as hook with the Python interpreter
2544
+ sys.excepthook = self.exception_hook
2545
+
2546
+ self.orgui = None
2547
+
2548
+ # connect signal to execute the message box function always on main thread
2549
+ #self._exception_caught.connect(show_exception_box)
2550
+
2551
+ def set_orgui(self,orgui):
2552
+ self.orgui = orgui
2553
+
2554
+ def exception_hook(self, exc_type, exc_value, exc_traceback):
2555
+ """Function handling uncaught exceptions.
2556
+ It is triggered each time an uncaught exception occurs.
2557
+ """
2558
+ if issubclass(exc_type, KeyboardInterrupt):
2559
+ # ignore keyboard interrupt to support console applications
2560
+ sys.__excepthook__(exc_type, exc_value, exc_traceback)
2561
+ else:
2562
+ exc_info = (exc_type, exc_value, exc_traceback)
2563
+ log_msg = '\n'.join([''.join(traceback.format_tb(exc_traceback)),
2564
+ '{0}: {1}'.format(exc_type.__name__, exc_value)])
2565
+ print("Uncaught exception:\n {0}".format(log_msg))# exc_info=exc_info)
2566
+
2567
+ # trigger message box show
2568
+ #self._exception_caught.emit(log_msg)
2569
+
2570
+ if qt.QApplication.instance() is not None:
2571
+ if self.orgui is None:
2572
+ errorbox = qt.QMessageBox(qt.QMessageBox.Critical,
2573
+ "Uncaught Exception",
2574
+ "An unexpected error occured. The program will terminate now:\n{0}".format(log_msg),
2575
+ qt.QMessageBox.Ok)
2576
+ errorbox.exec()
2577
+ sys.exit(1)
2578
+ else:
2579
+ resBtn = qutils.critical_detailed_message(self.orgui, "Uncaught Exception", "An unexpected error has occured.\norGUI will terminate now.\nDo you want to try to save the database before terminating?" ,log_msg, qt.QMessageBox.Save | qt.QMessageBox.Discard)
2580
+ #errorbox = qt.QMessageBox(qt.QMessageBox.Critical,
2581
+ # "Uncaught Exception",
2582
+ # "An unexpected error occured:\n{0}\nDo you want to try to save the data before terminating?".format(log_msg),
2583
+ # qt.QMessageBox.Save | qt.QMessageBox.Discard)
2584
+
2585
+ #resBtn = errorbox.exec()
2586
+
2587
+ if resBtn == qt.QMessageBox.Save:
2588
+ try:
2589
+ self.orgui.database.onSaveDBFile()
2590
+
2591
+ except Exception:
2592
+ print("Fatal error: Cannot save database:\n%s" % traceback.format_exc())
2593
+ qutils.critical_detailed_message(self.orgui, "Fatal error", "Cannot save database." ,traceback.format_exc())
2594
+ self.orgui.database.close()
2595
+ else:
2596
+ print("No QApplication instance available.")
2597
+ sys.exit(1)
2598
+
2599
+ def main(configfile):
2600
+
2601
+ a = qt.QApplication(['orGUI'])
2602
+
2603
+ qt_exception_hook = UncaughtHook()
2604
+
2605
+ mainWindow = orGUI(configfile)
2606
+ qt_exception_hook.set_orgui(mainWindow)
2607
+ mainWindow.show()
2608
+ #a.lastWindowClosed.connect(a.quit)
2609
+ return a.exec_()
2610
+
2611
+
2612
+ if __name__ == '__main__':
2613
+ main("./config")