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.
- orGUI-1.0.1.dist-info/LICENSE +21 -0
- orGUI-1.0.1.dist-info/METADATA +147 -0
- orGUI-1.0.1.dist-info/RECORD +83 -0
- orGUI-1.0.1.dist-info/WHEEL +5 -0
- orGUI-1.0.1.dist-info/entry_points.txt +2 -0
- orGUI-1.0.1.dist-info/top_level.txt +1 -0
- orgui/__init__.py +36 -0
- orgui/app/ArrayTableDialog.py +433 -0
- orgui/app/QReflectionSelector.py +538 -0
- orgui/app/QScanSelector.py +692 -0
- orgui/app/QUBCalculator.py +1210 -0
- orgui/app/__init__.py +36 -0
- orgui/app/database.py +487 -0
- orgui/app/orGUI.py +2613 -0
- orgui/app/qutils.py +51 -0
- orgui/backend/__init__.py +32 -0
- orgui/backend/backends.py +157 -0
- orgui/backend/beamline/ID31DiffractLinTilt.py +77 -0
- orgui/backend/beamline/P212_tools.py +577 -0
- orgui/backend/beamline/__init__.py +36 -0
- orgui/backend/beamline/fio_reader.py +110 -0
- orgui/backend/beamline/id31_tools.py +651 -0
- orgui/backend/scans.py +95 -0
- orgui/backend/udefaults.py +163 -0
- orgui/backend/universalScanLoader.py +105 -0
- orgui/datautils/__init__.py +32 -0
- orgui/datautils/util.py +705 -0
- orgui/datautils/xrayutils/CTRcalc.py +3022 -0
- orgui/datautils/xrayutils/CTRopt.py +623 -0
- orgui/datautils/xrayutils/CTRplotutil.py +904 -0
- orgui/datautils/xrayutils/DetectorCalibration.py +685 -0
- orgui/datautils/xrayutils/HKLVlieg.py +1360 -0
- orgui/datautils/xrayutils/ReciprocalNavigation.py +401 -0
- orgui/datautils/xrayutils/_CTRcalc_accel.py +181 -0
- orgui/datautils/xrayutils/__init__.py +46 -0
- orgui/datautils/xrayutils/element_data.py +213 -0
- orgui/datautils/xrayutils/test/__init__.py +57 -0
- orgui/datautils/xrayutils/test/test_CTRcalc.py +152 -0
- orgui/datautils/xrayutils/test/test_DetectorCalibration.py +336 -0
- orgui/datautils/xrayutils/test/test_HKLcalc.py +88 -0
- orgui/datautils/xrayutils/unitcells/Fe3O4(100).bul +59 -0
- orgui/datautils/xrayutils/unitcells/Pt100.bul +7 -0
- orgui/datautils/xrayutils/unitcells/Pt100_small.bul +5 -0
- orgui/datautils/xrayutils/unitcells/Pt110.bul +5 -0
- orgui/datautils/xrayutils/unitcells/Pt111.bul +6 -0
- orgui/datautils/xrayutils/unitcells/Pt310.bul +13 -0
- orgui/datautils/xrayutils/unitcells/Pt3O4(100).bul +19 -0
- orgui/datautils/xrayutils/unitcells/PtO(001).bul +9 -0
- orgui/datautils/xrayutils/unitcells/PtO(010).bul +9 -0
- orgui/datautils/xrayutils/unitcells/PtO(100).bul +9 -0
- orgui/datautils/xrayutils/unitcells/__init__.py +67 -0
- orgui/datautils/xrayutils/unitcells/a-PtO2(0001).bul +6 -0
- orgui/main.py +101 -0
- orgui/resources/__init__.py +40 -0
- orgui/resources/icons/alpha.png +0 -0
- orgui/resources/icons/alpha.svg +67 -0
- orgui/resources/icons/diffractometer_v3.png +0 -0
- orgui/resources/icons/disable-image.png +0 -0
- orgui/resources/icons/disable-image.svg +68 -0
- orgui/resources/icons/document-nx-open.png +0 -0
- orgui/resources/icons/document-nx-open.svg +152 -0
- orgui/resources/icons/document-nx-save.png +0 -0
- orgui/resources/icons/document-nx-save.svg +73 -0
- orgui/resources/icons/logo.png +0 -0
- orgui/resources/icons/logo.svg +808 -0
- orgui/resources/icons/max_image.png +0 -0
- orgui/resources/icons/max_image.svg +77 -0
- orgui/resources/icons/max_image2.png +0 -0
- orgui/resources/icons/max_image2.svg +83 -0
- orgui/resources/icons/search-image.png +0 -0
- orgui/resources/icons/search-image.svg +94 -0
- orgui/resources/icons/search-reflection.png +0 -0
- orgui/resources/icons/search-reflection.svg +126 -0
- orgui/resources/icons/search.png +0 -0
- orgui/resources/icons/search.svg +91 -0
- orgui/resources/icons/select-image.png +0 -0
- orgui/resources/icons/select-image.svg +60 -0
- orgui/resources/icons/set-reflection.png +0 -0
- orgui/resources/icons/set-reflection.svg +91 -0
- orgui/resources/icons/sum_image.png +0 -0
- orgui/resources/icons/sum_image.svg +63 -0
- orgui/resources/icons/sum_image2.png +0 -0
- 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")
|