orGUI 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. orGUI-1.0.1.dist-info/LICENSE +21 -0
  2. orGUI-1.0.1.dist-info/METADATA +147 -0
  3. orGUI-1.0.1.dist-info/RECORD +83 -0
  4. orGUI-1.0.1.dist-info/WHEEL +5 -0
  5. orGUI-1.0.1.dist-info/entry_points.txt +2 -0
  6. orGUI-1.0.1.dist-info/top_level.txt +1 -0
  7. orgui/__init__.py +36 -0
  8. orgui/app/ArrayTableDialog.py +433 -0
  9. orgui/app/QReflectionSelector.py +538 -0
  10. orgui/app/QScanSelector.py +692 -0
  11. orgui/app/QUBCalculator.py +1210 -0
  12. orgui/app/__init__.py +36 -0
  13. orgui/app/database.py +487 -0
  14. orgui/app/orGUI.py +2613 -0
  15. orgui/app/qutils.py +51 -0
  16. orgui/backend/__init__.py +32 -0
  17. orgui/backend/backends.py +157 -0
  18. orgui/backend/beamline/ID31DiffractLinTilt.py +77 -0
  19. orgui/backend/beamline/P212_tools.py +577 -0
  20. orgui/backend/beamline/__init__.py +36 -0
  21. orgui/backend/beamline/fio_reader.py +110 -0
  22. orgui/backend/beamline/id31_tools.py +651 -0
  23. orgui/backend/scans.py +95 -0
  24. orgui/backend/udefaults.py +163 -0
  25. orgui/backend/universalScanLoader.py +105 -0
  26. orgui/datautils/__init__.py +32 -0
  27. orgui/datautils/util.py +705 -0
  28. orgui/datautils/xrayutils/CTRcalc.py +3022 -0
  29. orgui/datautils/xrayutils/CTRopt.py +623 -0
  30. orgui/datautils/xrayutils/CTRplotutil.py +904 -0
  31. orgui/datautils/xrayutils/DetectorCalibration.py +685 -0
  32. orgui/datautils/xrayutils/HKLVlieg.py +1360 -0
  33. orgui/datautils/xrayutils/ReciprocalNavigation.py +401 -0
  34. orgui/datautils/xrayutils/_CTRcalc_accel.py +181 -0
  35. orgui/datautils/xrayutils/__init__.py +46 -0
  36. orgui/datautils/xrayutils/element_data.py +213 -0
  37. orgui/datautils/xrayutils/test/__init__.py +57 -0
  38. orgui/datautils/xrayutils/test/test_CTRcalc.py +152 -0
  39. orgui/datautils/xrayutils/test/test_DetectorCalibration.py +336 -0
  40. orgui/datautils/xrayutils/test/test_HKLcalc.py +88 -0
  41. orgui/datautils/xrayutils/unitcells/Fe3O4(100).bul +59 -0
  42. orgui/datautils/xrayutils/unitcells/Pt100.bul +7 -0
  43. orgui/datautils/xrayutils/unitcells/Pt100_small.bul +5 -0
  44. orgui/datautils/xrayutils/unitcells/Pt110.bul +5 -0
  45. orgui/datautils/xrayutils/unitcells/Pt111.bul +6 -0
  46. orgui/datautils/xrayutils/unitcells/Pt310.bul +13 -0
  47. orgui/datautils/xrayutils/unitcells/Pt3O4(100).bul +19 -0
  48. orgui/datautils/xrayutils/unitcells/PtO(001).bul +9 -0
  49. orgui/datautils/xrayutils/unitcells/PtO(010).bul +9 -0
  50. orgui/datautils/xrayutils/unitcells/PtO(100).bul +9 -0
  51. orgui/datautils/xrayutils/unitcells/__init__.py +67 -0
  52. orgui/datautils/xrayutils/unitcells/a-PtO2(0001).bul +6 -0
  53. orgui/main.py +101 -0
  54. orgui/resources/__init__.py +40 -0
  55. orgui/resources/icons/alpha.png +0 -0
  56. orgui/resources/icons/alpha.svg +67 -0
  57. orgui/resources/icons/diffractometer_v3.png +0 -0
  58. orgui/resources/icons/disable-image.png +0 -0
  59. orgui/resources/icons/disable-image.svg +68 -0
  60. orgui/resources/icons/document-nx-open.png +0 -0
  61. orgui/resources/icons/document-nx-open.svg +152 -0
  62. orgui/resources/icons/document-nx-save.png +0 -0
  63. orgui/resources/icons/document-nx-save.svg +73 -0
  64. orgui/resources/icons/logo.png +0 -0
  65. orgui/resources/icons/logo.svg +808 -0
  66. orgui/resources/icons/max_image.png +0 -0
  67. orgui/resources/icons/max_image.svg +77 -0
  68. orgui/resources/icons/max_image2.png +0 -0
  69. orgui/resources/icons/max_image2.svg +83 -0
  70. orgui/resources/icons/search-image.png +0 -0
  71. orgui/resources/icons/search-image.svg +94 -0
  72. orgui/resources/icons/search-reflection.png +0 -0
  73. orgui/resources/icons/search-reflection.svg +126 -0
  74. orgui/resources/icons/search.png +0 -0
  75. orgui/resources/icons/search.svg +91 -0
  76. orgui/resources/icons/select-image.png +0 -0
  77. orgui/resources/icons/select-image.svg +60 -0
  78. orgui/resources/icons/set-reflection.png +0 -0
  79. orgui/resources/icons/set-reflection.svg +91 -0
  80. orgui/resources/icons/sum_image.png +0 -0
  81. orgui/resources/icons/sum_image.svg +63 -0
  82. orgui/resources/icons/sum_image2.png +0 -0
  83. orgui/resources/icons/sum_image2.svg +75 -0
@@ -0,0 +1,1210 @@
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
+ __copyright__ = "Copyright 2020-2024 Timo Fuchs"
27
+ __license__ = "MIT License"
28
+ __version__ = "1.0.0"
29
+ __maintainer__ = "Timo Fuchs"
30
+ __email__ = "fuchs@physik.uni-kiel.de"
31
+
32
+ from io import StringIO
33
+ from silx.gui import qt
34
+ import pyFAI
35
+ import numpy as np
36
+
37
+ import traceback
38
+ from ..datautils.xrayutils import HKLVlieg, CTRcalc
39
+ from ..datautils.xrayutils import DetectorCalibration
40
+ from ..datautils.xrayutils import unitcells
41
+ import warnings
42
+ import configparser
43
+ import os
44
+ import copy
45
+ from contextlib import contextmanager
46
+
47
+ from .ArrayTableDialog import ArrayEditWidget
48
+
49
+ from ..backend import udefaults
50
+ from .. import resources
51
+ from . import qutils
52
+
53
+ @contextmanager
54
+ def blockSignals(qobjects):
55
+ try:
56
+ for obj in qobjects:
57
+ obj.blockSignals(True)
58
+ yield
59
+ for obj in qobjects:
60
+ obj.blockSignals(False)
61
+ except TypeError:
62
+ qobject.blockSignals(True)
63
+ yield
64
+ qobject.blockSignals(False)
65
+
66
+
67
+
68
+ # reflectionhandler must implement the method getReflections
69
+
70
+ class QUBCalculator(qt.QSplitter):
71
+ sigNewReflection = qt.pyqtSignal(dict)
72
+ sigPlottableMachineParamsChanged = qt.pyqtSignal()
73
+ sigReplotRequest = qt.pyqtSignal(bool)
74
+ #sigQueryImageChange = qt.pyqtSignal(int)
75
+ #sigImagePathChanged = qt.pyqtSignal(object)
76
+ #sigImageNoChanged = qt.pyqtSignal(object)
77
+ def __init__(self,configfile, parent):
78
+ qt.QSplitter.__init__(self, parent)
79
+ self.setOrientation(qt.Qt.Vertical)
80
+
81
+ self.mainGui = parent
82
+
83
+ self.configdir = os.getcwd()
84
+ #self.mainLayout = qt.QVBoxLayout()
85
+
86
+ self.setChildrenCollapsible(False)
87
+
88
+ self.reflectionWidget = qt.QToolBar()
89
+ self.reflectionWidget.setFloatable(False)
90
+ self.reflectionWidget.setMovable(False)
91
+ #self.reflectionWidget.setChildrenCollapsible(False)
92
+ self.reflectionWidget.setOrientation(qt.Qt.Horizontal)
93
+ label = qt.QLabel("H:")
94
+ self.reflectionWidget.addWidget(label)
95
+ self.Hbox = qt.QDoubleSpinBox()
96
+ self.Hbox.setRange(-100,100)
97
+ self.Hbox.setDecimals(3)
98
+ self.reflectionWidget.addWidget(self.Hbox)
99
+ label = qt.QLabel("K:")
100
+ self.reflectionWidget.addWidget(label)
101
+ self.Kbox = qt.QDoubleSpinBox()
102
+ self.Kbox.setRange(-100,100)
103
+ self.Kbox.setDecimals(3)
104
+ self.reflectionWidget.addWidget(self.Kbox)
105
+ label = qt.QLabel("L:")
106
+ self.reflectionWidget.addWidget(label)
107
+ self.Lbox = qt.QDoubleSpinBox()
108
+ self.Lbox.setRange(-100,100)
109
+ self.Lbox.setDecimals(3)
110
+ self.reflectionWidget.addWidget(self.Lbox)
111
+ searchReflAct = qt.QAction(resources.getQicon('search'), "search reflection", self)
112
+ self.reflectionWidget.addAction(searchReflAct)
113
+ #applyButton.setSizePolicy(qt.QSizePolicy(qt.QSizePolicy.Fixed, qt.QSizePolicy.Minimum))
114
+ searchReflAct.setToolTip("calculate position of the reflection with given HKL")
115
+
116
+ searchReflAct.triggered.connect(self._onCalcReflection)
117
+
118
+ self.addWidget(self.reflectionWidget)
119
+
120
+ umatrixsplitter = qt.QSplitter()
121
+ umatrixsplitter.setOrientation(qt.Qt.Horizontal)
122
+ umatrixsplitter.setChildrenCollapsible(False)
123
+
124
+ #self.Ueditor = qt.QTextEdit("")
125
+ #umatrixsplitter.addWidget(self.Ueditor)
126
+ self.calUButton = qt.QPushButton("calculate U")
127
+ self.calUButton.setToolTip("calculate orientation matrix based on the given reflections")
128
+
129
+ vertCalUSplitter = qt.QSplitter()
130
+ vertCalUSplitter.setOrientation(qt.Qt.Vertical)
131
+ vertCalUSplitter.setChildrenCollapsible(False)
132
+ fitUbox = qt.QGroupBox("fit options")
133
+ fitUbox.setToolTip("only available with enough reflections")
134
+
135
+ self.latnofit = qt.QRadioButton("don't fit lattice")
136
+ self.latnofit.setChecked(True)
137
+ self.latscale = qt.QRadioButton("fit scale of lattice")
138
+ self.latfitall = qt.QRadioButton("fit all lattice parameters")
139
+
140
+ fitUboxlayout = qt.QVBoxLayout()
141
+ fitUboxlayout.addWidget(self.latnofit)
142
+ fitUboxlayout.addWidget(self.latscale)
143
+ fitUboxlayout.addWidget(self.latfitall)
144
+ fitUboxlayout.addStretch(1)
145
+
146
+ fitUbox.setLayout(fitUboxlayout)
147
+
148
+
149
+ vertCalUSplitter.addWidget(fitUbox)
150
+
151
+ vertCalUSplitter.addWidget(self.calUButton)
152
+
153
+ self.calMiscutButton = qt.QPushButton("calculate miscut")
154
+ self.calMiscutButton.setToolTip("calculate miscut based on deviation from ideal orientation matrix")
155
+
156
+ vertCalUSplitter.addWidget(self.calMiscutButton)
157
+
158
+
159
+
160
+
161
+ umatrixsplitter.addWidget(vertCalUSplitter)
162
+
163
+ self.addWidget(umatrixsplitter)
164
+
165
+
166
+
167
+
168
+
169
+ self.calUButton.clicked.connect(self._onCalcU)
170
+ self.calMiscutButton.clicked.connect(self._onCalMiscut)
171
+
172
+ self.crystalparams = QCrystalParameter()
173
+
174
+
175
+ self.crystalparams.sigCrystalParamsChanged.connect(self._onCrystalParamsChanged)
176
+ self.machineParams = QMachineParameters()
177
+ self.machineParams.sigMachineParamsChanged.connect(self._onMachineParamsChanged)
178
+ self.machineParams.loadConfigButton.clicked.connect(self._onLoadConfig)
179
+
180
+ self.uedit = QUEdit()
181
+ self.ueditDialog = QUEditDialog(self.uedit)
182
+
183
+ self.uedit.sigResetRequest.connect(self._onResetU)
184
+ self.uedit.sigAlignRequest.connect(self._onAlignU)
185
+
186
+
187
+ self.machineDialog = QMachineParametersDialog(self.machineParams)
188
+ self.xtalDialog = QCrystalParameterDialog(self.crystalparams)
189
+
190
+
191
+ if configfile is not None:
192
+ if not self.readConfig(configfile):
193
+ self.toFallbackConfig()
194
+ else:
195
+ self.toFallbackConfig()
196
+
197
+ self.uedit.sigUChanged.connect(self._onUchanged)
198
+ """
199
+
200
+ editorSplitter = qt.QSplitter()
201
+ editorSplitter.setOrientation(qt.Qt.Horizontal)
202
+
203
+ self.refleditor = qt.QTextEdit("H\tK\tL\tx\ty\timageno\n")
204
+ editorSplitter.addWidget(self.refleditor)
205
+
206
+
207
+ fromEditorButton = qt.QPushButton("from editor",self.reflectionWidget)
208
+ #applyButton.setSizePolicy(qt.QSizePolicy(qt.QSizePolicy.Fixed, qt.QSizePolicy.Minimum))
209
+ fromEditorButton.setToolTip("take refelctions from editor")
210
+ fromEditorButton.clicked.connect(self.reflectionsFromEditor)
211
+ editorSplitter.addWidget(fromEditorButton)
212
+
213
+
214
+ self.addWidget(editorSplitter)
215
+ """
216
+
217
+
218
+ def calcReflection(self,hkl, axisname=None):
219
+ if self.mainGui.fscan is not None:
220
+ if axisname is None:
221
+ axisname = self.mainGui.fscan.axisname
222
+ mu_cryst = HKLVlieg.crystalAngles_singleArray(self.mu,self.n)
223
+
224
+ if axisname == 'th':
225
+ pos1 = self.angles.anglesZmode(hkl,mu_cryst,'in',self.chi,self.phi,mirrorx=False)
226
+ pos2 = self.angles.anglesZmode(hkl,mu_cryst,'in',self.chi,self.phi,mirrorx=True)
227
+ elif axisname == 'mu':
228
+ pos1 = self.angles.anglesZmode(hkl,mu_cryst,'eq',self.chi,self.phi,mirrorx=False)
229
+ pos2 = self.angles.anglesZmode(hkl,mu_cryst,'eq',self.chi,self.phi,mirrorx=True)
230
+ else:
231
+ raise Exception("No scan axis given or no scan loaded.")
232
+ alpha1, delta1, gamma1, omega1, chi1, phi1 = HKLVlieg.vacAngles(pos1,self.n)
233
+ alpha2, delta2, gamma2, omega2, chi2, phi2 = HKLVlieg.vacAngles(pos2,self.n)
234
+
235
+ y1,x1 = self.detectorCal.pixelsSurfaceAngles([gamma1],[delta1],alpha1)[0]
236
+ y2,x2 = self.detectorCal.pixelsSurfaceAngles([gamma2],[delta2],alpha2)[0]
237
+ di = {
238
+ 'hkl' : hkl,
239
+ 'xy_1' : [x1,y1],
240
+ 'xy_2' : [x2,y2],
241
+ 'angles_1' : [alpha1, delta1, gamma1, omega1, chi1, phi1],
242
+ 'angles_2' : [alpha2, delta2, gamma2, omega2, chi2, phi2]
243
+ }
244
+ return di
245
+
246
+
247
+ def _onCalcReflection(self):
248
+ hkl = [self.Hbox.value(),self.Kbox.value(),self.Lbox.value()]
249
+ try:
250
+ refl = self.calcReflection(hkl)
251
+ except Exception as e:
252
+ qutils.warning_detailed_message(self, "Cannot calculate reflection",
253
+ "Cannot calculate reflection:\n%s" % e,
254
+ traceback.format_exc())
255
+ return
256
+ self.sigNewReflection.emit(refl)
257
+
258
+ def _onUchanged(self, U):
259
+ self.ubCal.setU(U)
260
+ self.sigReplotRequest.emit(True)
261
+
262
+ def _onResetU(self, func):
263
+ func(self.ubCal)
264
+ self.uedit.setU(self.ubCal.getU())
265
+ self.sigReplotRequest.emit(True)
266
+
267
+ def _onAlignU(self, ddict):
268
+ angles = ddict['angles'] # ['alpha', 'chi', 'phi', 'theta']
269
+ pos = [angles[0], None, None, angles[3], angles[1], angles[2]]
270
+ if ddict['frame'] == 'surface':
271
+ self.ubCal.alignU_alpha(ddict['hkl'], pos, ddict['xyz'])
272
+ elif ddict['frame'] == 'lab':
273
+ self.ubCal.alignU_lab(ddict['hkl'], pos, ddict['xyz'])
274
+ self.uedit.setU(self.ubCal.getU())
275
+ self.sigReplotRequest.emit(True)
276
+
277
+ def _onCrystalParamsChanged(self,crystal,n):
278
+ #a,alpha,_,_ = crystal.getLatticeParameters()
279
+ #self.crystal.setLattice(a,np.rad2deg(alpha))
280
+
281
+ self.crystal = crystal
282
+ self.n = n
283
+ self.ubCal.setLattice(self.crystal)
284
+ #self.ubCal.defaultU()
285
+ self.sigReplotRequest.emit(True)
286
+
287
+ def _onMachineParamsChanged(self,params):
288
+ [E,mu,sdd,pixsize,cp,polax,polf,azim,chi,phi] = params
289
+ self.mu = mu
290
+ self.chi = chi
291
+ self.phi = phi
292
+ self.ubCal.setEnergy(E)
293
+ fit2DCal = self.detectorCal.getFit2D()
294
+ fit2DCal['centerX'] = cp[0]
295
+ fit2DCal['centerY'] = cp[1]
296
+ fit2DCal['directDist'] = sdd*1e3
297
+ f2d = [fit2DCal['directDist'],
298
+ fit2DCal['centerX'],
299
+ fit2DCal['centerY'],
300
+ fit2DCal['tilt'],
301
+ fit2DCal['tiltPlanRotation'],
302
+ pixsize*1e6,
303
+ pixsize*1e6,
304
+ fit2DCal['splineFile']]
305
+ self.detectorCal.setFit2D(*f2d)
306
+ self.detectorCal.set_wavelength(self.ubCal.getLambda()*1e-10)
307
+ self.detectorCal.setAzimuthalReference(azim)
308
+ self.azimuth = azim
309
+ self.detectorCal.setPolarization(polax,polf)
310
+ self.crystal.setEnergy(E*1e3)
311
+
312
+ angles_u = self.uedit.cached_angles
313
+
314
+ self.uedit.setAngles(mu, chi, phi, angles_u[-1])
315
+
316
+ try:
317
+ self.sigPlottableMachineParamsChanged.emit()
318
+ self.sigReplotRequest.emit(True)
319
+ except Exception as e:
320
+ # here is a bug with the init of the detector cal
321
+ print(traceback.format_exc())
322
+ #pass
323
+ #print(self.detectorCal.get_wavelength())
324
+ #print(self.detectorCal.getFit2D())
325
+
326
+ def _onLoadConfig(self):
327
+ fileTypeDict = {'config files (*)': '' }
328
+ fileTypeFilter = ""
329
+ for f in fileTypeDict:
330
+ fileTypeFilter += f + ";;"
331
+ filename, filetype = qt.QFileDialog.getOpenFileName(self,"Open config file",
332
+ self.configdir,
333
+ fileTypeFilter[:-2])
334
+ if filename == '':
335
+ return
336
+ self.configdir = os.path.splitext(filename)[0]
337
+ self.readConfig(filename)
338
+
339
+ def setReflectionHandler(self,refls):
340
+ self.reflections = refls
341
+
342
+ def readConfig(self,configfile):
343
+ config = configparser.ConfigParser()
344
+ try:
345
+ if os.path.isfile(configfile):
346
+ config.read(configfile)
347
+ else:
348
+ raise Exception("File does not exist")
349
+ except Exception as e:
350
+ qt.QMessageBox.warning(self,"Can not read config","Can not read config file:\nException occured during read of configfile %s,\nException:\n %s" % (configfile,e))
351
+ return False
352
+ try:
353
+ machine = config['Machine']
354
+ lattice = config['Lattice']
355
+ diffrac = config['Diffractometer']
356
+
357
+ self.azimuth = np.deg2rad(diffrac.getfloat('azimuthal_reference',0))
358
+ self.polaxis = np.deg2rad(diffrac.getfloat('polarization_axis',0))
359
+ self.polfactor = diffrac.getfloat('polarization_factor',0)
360
+
361
+ sdd = machine.getfloat('SDD',0.729) #m
362
+ E = machine.getfloat('E',78.0) #keV
363
+ pixelsize = machine.getfloat('pixelsize',172e-6) #m
364
+ cpx = machine.getfloat('cpx',731)
365
+ cpy = machine.getfloat('cpy',1587)
366
+ cp = [cpx,cpy]
367
+
368
+ self.mu = np.deg2rad(diffrac.getfloat('mu',0.05))
369
+ self.chi = np.deg2rad(diffrac.getfloat('chi',0.0))
370
+ self.phi = np.deg2rad(diffrac.getfloat('phi',0.0))
371
+
372
+
373
+ a1 = lattice.getfloat('a1',-1)
374
+ a2 = lattice.getfloat('a2',-1)
375
+ a3 = lattice.getfloat('a3',-1)
376
+ alpha1 = lattice.getfloat('alpha1',-1)
377
+ alpha2 = lattice.getfloat('alpha2',-1)
378
+ alpha3 = lattice.getfloat('alpha3',-1)
379
+ self.n = 1 - lattice.getfloat('refractionindex',0.0)
380
+
381
+ lat = np.array([a1,a2,a3])
382
+
383
+ latticeoverride = True
384
+ latangle = np.array([alpha1,alpha2,alpha3])
385
+ if np.any(lat < 0.) or np.any(latangle < 0):
386
+ latticeoverride = False
387
+ a1 = a2 = a3 = 1.
388
+ alpha1 = alpha2 = alpha3 = 90.
389
+ print("Fallback lattice vectors")
390
+
391
+
392
+ self.crystal = CTRcalc.UnitCell([a1,a2,a3],[alpha1,alpha2,alpha3])
393
+ self.crystal.addAtom('Pt',[0.,0.,0.],0.1,0.1,1.)
394
+ self.crystal.setEnergy(E*1e3)
395
+
396
+ self.ubCal = HKLVlieg.UBCalculator(self.crystal,E)
397
+ self.ubCal.defaultU()
398
+ self.uedit.setU(self.ubCal.getU())
399
+ self.angles = HKLVlieg.VliegAngles(self.ubCal)
400
+
401
+ if 'crystal' in lattice:
402
+ idx = self.crystalparams.crystalComboBox.findText(lattice['crystal'],qt.Qt.MatchFixedString)
403
+ if idx == -1:
404
+ qt.QMessageBox.warning(self,"Did not find crystal","Can not find crystal <%s> \nException occured during read of configfile %s,\nException:\n%s" % (unitcellsconfigfile,traceback.format_exc()))
405
+ else:
406
+ self.crystalparams.crystalComboBox.setCurrentIndex(idx)
407
+ self.crystalparams.onSwitchCrystal(idx)
408
+ #self.crystal = self.crystalparams.getCrystal()
409
+
410
+ if latticeoverride:
411
+ self.crystal.setLattice([a1,a2,a3],[alpha1,alpha2,alpha3])
412
+
413
+ self.detectorCal = DetectorCalibration.Detector2D_SXRD()
414
+ if 'poni' in machine:
415
+ if machine['poni']:
416
+ if os.path.isabs(machine['poni']):
417
+ ponipath = machine['poni']
418
+ else:
419
+ p = os.path.abspath(configfile)
420
+ ponipath = os.path.join(os.path.dirname(p), machine['poni'])
421
+ self.detectorCal.load(ponipath)
422
+ self.ubCal.setLambda(self.detectorCal.get_wavelength()*1e10)
423
+
424
+ else:
425
+ self.detectorCal.setFit2D(sdd*1e3,cpx,cpy,pixelX=pixelsize*1e6, pixelY=pixelsize*1e6)
426
+ self.detectorCal.set_wavelength(self.ubCal.getLambda()*1e-10)
427
+ self.detectorCal.detector.shape = (2880,2880) # Perkin
428
+
429
+ else:
430
+ self.detectorCal.setFit2D(sdd*1e3,cpx,cpy,pixelX=pixelsize*1e6, pixelY=pixelsize*1e6)
431
+ self.detectorCal.set_wavelength(self.ubCal.getLambda()*1e-10)
432
+ self.detectorCal.detector.shape = (2880,2880)
433
+
434
+ self.detectorCal.setAzimuthalReference(self.azimuth)
435
+ self.detectorCal.setPolarization(self.polaxis,self.polfactor)
436
+
437
+ fit2dCal = self.detectorCal.getFit2D()
438
+
439
+ paramlist = [self.ubCal.getEnergy(),self.mu,fit2dCal['directDist']/1e3,
440
+ fit2dCal['pixelX']*1e-6,[fit2dCal['centerX'],fit2dCal['centerY']],self.polaxis
441
+ ,self.polfactor,self.azimuth,self.chi,self.phi]
442
+ self.crystalparams.setValues(self.crystal,self.n)
443
+ self.machineParams.setValues(paramlist)
444
+ return True
445
+
446
+ except Exception as e:
447
+ qt.QMessageBox.warning(self,"Can not parse config","Can not parse config file:\nException occured during parsing of configfile %s,\nException:\n %s" % (configfile,traceback.format_exc()))
448
+ return False
449
+
450
+ def toFallbackConfig(self):
451
+ sdd = 0.729 #m
452
+ E = 78.
453
+ pixelsize = 172e-6
454
+ cp = [731.0,1587.856]
455
+ self.mu = np.deg2rad(0.05)
456
+ self.chi = 0.
457
+ self.phi = 0.
458
+ self.n = 1 - 1.1415e-06
459
+ self.crystal = CTRcalc.UnitCell([3.9242,3.9242,3.9242],[90.,90.,90.])
460
+ self.crystal.addAtom('Pt',[0.,0.,0.],0.1,0.1,1.)
461
+ self.crystal.setEnergy(E*1e3)
462
+
463
+ self.ubCal = HKLVlieg.UBCalculator(self.crystal,E)
464
+ self.ubCal.defaultU()
465
+ self.uedit.setU(self.ubCal.getU())
466
+ self.polaxis = 0
467
+ self.polfactor = 0
468
+ self.azimuth = 0
469
+ self.detectorCal = DetectorCalibration.Detector2D_SXRD()
470
+ self.detectorCal.detector = pyFAI.detector_factory("Pilatus2m")
471
+ self.detectorCal.setFit2D(sdd*1e3,cp[0],cp[1],pixelX=pixelsize*1e6, pixelY=pixelsize*1e6)
472
+ self.detectorCal.set_wavelength(self.ubCal.getLambda()*1e-10)
473
+
474
+ fit2dCal = self.detectorCal.getFit2D()
475
+ self.angles = HKLVlieg.VliegAngles(self.ubCal)
476
+ paramlist = [self.ubCal.getEnergy(),self.mu,fit2dCal['directDist']/1e3,
477
+ fit2dCal['pixelX']*1e-6,[fit2dCal['centerX'],fit2dCal['centerY']],self.polaxis,
478
+ self.polfactor,self.azimuth,self.chi,self.phi]
479
+ self.crystalparams.setValues(self.crystal,self.n)
480
+ self.machineParams.setValues(paramlist)
481
+
482
+
483
+
484
+ def _onCalcU(self):
485
+ hkls,angles = self.reflections()
486
+ if len(hkls) < 1:
487
+ qt.QMessageBox.warning(self,"Not enough reflections","You must select at least 1 reflection to calculate an orientation matrix")
488
+ return
489
+ elif len(hkls) == 1:
490
+ try:
491
+ self.ubCal.zmodeUSingleRefl(angles[0],hkls[0])
492
+ except Exception as e:
493
+ qt.QMessageBox.critical(self,"Cannot calculate UB matrix","Error during UB matrix calculation:\n%s" % traceback.format_exc())
494
+ return
495
+ else:
496
+ try:
497
+ self.ubCal.setPrimaryReflection(angles[0],hkls[0])
498
+ self.ubCal.setSecondayReflection(angles[1],hkls[1])
499
+ self.ubCal.calculateU()
500
+ except Exception as e:
501
+ qt.QMessageBox.critical(self,"Cannot calculate UB matrix","Error during UB matrix calculation:\n%s" % traceback.format_exc())
502
+ return
503
+
504
+ if len(hkls) > 2:
505
+ if self.latnofit.isChecked():
506
+ self.ubCal.refineU(hkls,angles)
507
+ #print(self.ubCal.getU())
508
+
509
+ if self.latscale.isChecked():
510
+ if len(hkls) > 3:
511
+ self.ubCal.refineULattice(hkls,angles,'scale')
512
+ else:
513
+ qt.QMessageBox.warning(self,"Not enough reflections","You must select at least 4 reflections to fit lattice scale and U")
514
+ if self.latfitall.isChecked():
515
+ if len(hkls) > 5:
516
+ self.ubCal.refineULattice(hkls,angles,'lat')
517
+ else:
518
+ qt.QMessageBox.warning(self,"Not enough reflections","You must select at least 6 reflections to fit lattice and U")
519
+ #print(self.ubCal.getU())
520
+ self.crystalparams.setValues(self.crystal,self.n)
521
+ #print(self.ubCal.getU())
522
+ self.uedit.setU(self.ubCal.getU())
523
+ self.sigReplotRequest.emit(False)
524
+ #self.Ueditor.setPlainText(str(self.ubCal.getU()))
525
+
526
+ def _onCalMiscut(self):
527
+ om, chi, phi = self.angles.anglesOrientationAlpha([0,0,1], [0,0,1])
528
+ chi, phi = float(chi), float(phi)
529
+ chi_displ = float(np.rad2deg(chi))
530
+ phi_displ = float(np.rad2deg(phi))
531
+ btn = qt.QMessageBox.question(self,"Miscut calcuated","The miscut is along\nphi = %.4f\nchi = %.4f\nReset chi and phi to negative these values?" % (phi_displ,chi_displ),qt.QMessageBox.Yes | qt.QMessageBox.No, qt.QMessageBox.No)
532
+ if btn == qt.QMessageBox.Yes:
533
+ self.chi = -chi
534
+ self.phi = -phi
535
+ angles_u = self.uedit.cached_angles
536
+ self.uedit.setAngles(angles_u[0], -chi, -phi, angles_u[-1])
537
+
538
+
539
+ class QCrystalParameter(qt.QSplitter):
540
+ sigCrystalParamsChanged = qt.pyqtSignal(HKLVlieg.Lattice,float)
541
+ def __init__(self,parent=None):
542
+ qt.QSplitter.__init__(self, parent=None)
543
+ self.setOrientation(qt.Qt.Vertical)
544
+
545
+ latticeParamsGroup = qt.QGroupBox("Lattice parameters")
546
+ latticeParamsLayout = qt.QGridLayout()
547
+
548
+ self.filedialogdir = '.'
549
+
550
+ self._uc = CTRcalc.UnitCell([3.9242,3.9242,3.9242],[90.,90.,90.])
551
+ self._uc.addAtom('Pt',[0.,0.,0.],0.1,0.1,1.)
552
+ self._uc.setEnergy(70000.)
553
+
554
+ self._n = 1.
555
+
556
+ latticeParamsLayout.addWidget(qt.QLabel("a1:"),0,0)
557
+ latticeParamsLayout.addWidget(qt.QLabel("a2:"),1,0)
558
+ latticeParamsLayout.addWidget(qt.QLabel("a3:"),2,0)
559
+ self.a1box = qt.QDoubleSpinBox()
560
+ self.a1box.setRange(0,100)
561
+ self.a1box.setDecimals(4)
562
+ self.a1box.setSuffix(u" \u212B")
563
+
564
+ latticeParamsLayout.addWidget(self.a1box,0,1)
565
+
566
+ self.a2box = qt.QDoubleSpinBox()
567
+ self.a2box.setRange(0,100)
568
+ self.a2box.setDecimals(4)
569
+ self.a2box.setSuffix(u" \u212B")
570
+
571
+ latticeParamsLayout.addWidget(self.a2box,1,1)
572
+
573
+ self.a3box = qt.QDoubleSpinBox()
574
+ self.a3box.setRange(0,100)
575
+ self.a3box.setDecimals(4)
576
+ self.a3box.setSuffix(u" \u212B")
577
+
578
+ latticeParamsLayout.addWidget(self.a3box,2,1)
579
+
580
+ latticeParamsLayout.addWidget(qt.QLabel("alpha1:"),0,2)
581
+ latticeParamsLayout.addWidget(qt.QLabel("alpha2:"),1,2)
582
+ latticeParamsLayout.addWidget(qt.QLabel("alpha3:"),2,2)
583
+ self.alpha1box = qt.QDoubleSpinBox()
584
+ self.alpha1box.setRange(0,180)
585
+ self.alpha1box.setDecimals(2)
586
+ self.alpha1box.setSuffix(" °")
587
+
588
+ latticeParamsLayout.addWidget(self.alpha1box,0,3)
589
+
590
+ self.alpha2box = qt.QDoubleSpinBox()
591
+ self.alpha2box.setRange(0,180)
592
+ self.alpha2box.setDecimals(2)
593
+ self.alpha2box.setSuffix(" °")
594
+
595
+ latticeParamsLayout.addWidget(self.alpha2box,1,3)
596
+
597
+ self.alpha3box = qt.QDoubleSpinBox()
598
+ self.alpha3box.setRange(0,180)
599
+ self.alpha3box.setDecimals(2)
600
+ self.alpha3box.setSuffix(" °")
601
+
602
+ latticeParamsLayout.addWidget(self.alpha3box,2,3)
603
+
604
+
605
+ latticeParamsGroup.setLayout(latticeParamsLayout)
606
+
607
+
608
+
609
+ refractionindexGroup = qt.QGroupBox("refraction index")
610
+ refractionindexLayout = qt.QHBoxLayout()
611
+ #refractionindexLayout.setOrientation(qt.Qt.Horizontal)
612
+
613
+
614
+ refractionindexLayout.addWidget(qt.QLabel("delta / 1e-6:"))
615
+ self.refractionIndexBox = qt.QDoubleSpinBox()
616
+
617
+ self.refractionIndexBox.setRange(0,1000)
618
+ self.refractionIndexBox.setDecimals(3)
619
+
620
+ refractionindexLayout.addWidget(self.refractionIndexBox)
621
+
622
+ refractionindexGroup.setLayout(refractionindexLayout)
623
+ #self.setValues(crystal,n)
624
+
625
+
626
+
627
+ crystalParamsGroup = qt.QGroupBox("Crystal")
628
+ crystalParamsLayout = qt.QGridLayout()
629
+
630
+ crystalParamsLayout.addWidget(qt.QLabel("Crystal:"),0,0)
631
+
632
+ self.crystalComboBox = qt.QComboBox()
633
+ crystalParamsLayout.addWidget(self.crystalComboBox,0,1)
634
+
635
+ for uc in unitcells.availablebulk:
636
+ self.crystalComboBox.addItem(uc, uc)
637
+
638
+ loadxtalbtn = qt.QPushButton("Load bulk file")
639
+ crystalParamsLayout.addWidget(loadxtalbtn,1,1)
640
+ loadxtalbtn.clicked.connect(self.onLoadXtal)
641
+
642
+ self.crystalComboBox.activated.connect(self.onSwitchCrystal)
643
+
644
+
645
+ crystalParamsGroup.setLayout(crystalParamsLayout)
646
+
647
+ self.addWidget(crystalParamsGroup)
648
+ self.addWidget(latticeParamsGroup)
649
+ self.addWidget(refractionindexGroup)
650
+
651
+
652
+
653
+ self.a1box.valueChanged.connect(self._onAnyValueChanged)
654
+ self.a2box.valueChanged.connect(self._onAnyValueChanged)
655
+ self.a3box.valueChanged.connect(self._onAnyValueChanged)
656
+ self.alpha1box.valueChanged.connect(self._onAnyValueChanged)
657
+ self.alpha2box.valueChanged.connect(self._onAnyValueChanged)
658
+ self.alpha3box.valueChanged.connect(self._onAnyValueChanged)
659
+ self.refractionIndexBox.valueChanged.connect(self._onAnyValueChanged)
660
+
661
+ def onLoadXtal(self):
662
+ fileTypeDict = {'bulk files (*.bul)': '.bul', 'Crystal Files (*.xtal)': '.txt', 'All files (*)': '', }
663
+ fileTypeFilter = ""
664
+ for f in fileTypeDict:
665
+ fileTypeFilter += f + ";;"
666
+
667
+ filename, filetype = qt.QFileDialog.getOpenFileName(self,"Open crystal file with atom locations",
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
+
676
+ if filetype == 'bulk files (*.bul)':
677
+ try:
678
+ uc_bulk = CTRcalc.UnitCell.fromBULfile(filename)
679
+ except Exception:
680
+ qt.QMessageBox.critical(self,"Cannot open xtal", "Cannot open:\n%s" % traceback.format_exc())
681
+ return
682
+ else:
683
+ qt.QMessageBox.critical(self,"Cannot open xtal", "File extension not understood")
684
+ return
685
+
686
+ uc_name = os.path.splitext(os.path.basename(filename) )[0]
687
+ self.crystalComboBox.addItem(uc_name, uc_bulk)
688
+ idx = self.crystalComboBox.findText(uc_name)
689
+ self.crystalComboBox.setCurrentIndex(idx)
690
+ self.onSwitchCrystal(idx)
691
+
692
+ def onSwitchCrystal(self, index):
693
+ selectiondata = self.crystalComboBox.itemData(index)
694
+ if isinstance(selectiondata, str):
695
+ uc = unitcells.unitcell(selectiondata)
696
+ self.crystalComboBox.setItemData(index,uc)
697
+ uc = copy.deepcopy(uc)
698
+ else:
699
+ uc = copy.deepcopy(selectiondata)
700
+ self.setValues(uc,self.getRefractionIndex())
701
+
702
+ def setValues(self,crystal,n):
703
+ [a1,a2,a3],alpha,_,_ = crystal.getLatticeParameters()
704
+ [alpha1,alpha2,alpha3] = np.rad2deg(alpha)
705
+ signList = [self.a1box, self.a2box, self.a3box,
706
+ self.alpha1box, self.alpha2box, self.alpha3box,
707
+ self.refractionIndexBox]
708
+ with blockSignals(signList):
709
+ self.a1box.setValue(a1)
710
+ self.a2box.setValue(a2)
711
+ self.a3box.setValue(a3)
712
+ self.alpha1box.setValue(alpha1)
713
+ self.alpha2box.setValue(alpha2)
714
+ self.alpha3box.setValue(alpha3)
715
+ self.refractionIndexBox.setValue((1.-n)*1e6)
716
+ #self.blockSignals(False)
717
+ self._uc = crystal
718
+ self._onAnyValueChanged()
719
+
720
+ def getCrystal(self):
721
+ a = np.array([self.a1box.value(),self.a2box.value(),self.a3box.value()])
722
+ alpha = np.array([self.alpha1box.value(),self.alpha2box.value(),self.alpha3box.value()])
723
+ if np.any(a == 0) or np.any(alpha == 0):
724
+ raise Exception("No crystal set")
725
+ self._uc.setLattice(a,alpha)
726
+ if len(self._uc.basis) < 1.:
727
+ self._uc.addAtom('Pt',[0.,0.,0.],0.1,0.1,1.)
728
+ return self._uc
729
+
730
+ def getRefractionIndex(self):
731
+ return 1 - self.refractionIndexBox.value()*1e-6
732
+
733
+ def _onAnyValueChanged(self):
734
+ try:
735
+ newCrystal = self.getCrystal()
736
+ n = self.getRefractionIndex()
737
+ self.sigCrystalParamsChanged.emit(newCrystal,n)
738
+ except Exception as e:
739
+ qt.QMessageBox.warning(self,"Can not calculate B Matrix","The B Matrix can not be calculated\nError: %s" % str(e))
740
+
741
+
742
+ class QUEdit(qt.QWidget):
743
+ sigUChanged = qt.pyqtSignal(np.ndarray)
744
+ sigResetRequest = qt.pyqtSignal(object)
745
+ sigAlignRequest = qt.pyqtSignal(object)
746
+
747
+ def __init__(self,parent=None):
748
+ qt.QWidget.__init__(self, parent=None)
749
+
750
+ alignGroup = qt.QGroupBox("Align hkl onto xyz")
751
+ orientationLayout = qt.QGridLayout()
752
+
753
+ self.hkl = []
754
+ for i, index in enumerate(['H', 'K', 'L']):
755
+ orientationLayout.addWidget(qt.QLabel("%s:" % index),i,0)
756
+ milleredit = qt.QDoubleSpinBox()
757
+ milleredit.setRange(-1000,1000)
758
+ milleredit.setDecimals(4)
759
+ orientationLayout.addWidget(milleredit,i,1)
760
+ milleredit.setValue(1. if i == 2 else 0.)
761
+ self.hkl.append(milleredit)
762
+
763
+ self.override_angles = qt.QCheckBox("Override angles")
764
+ self.override_angles.toggled.connect(self._onOverride)
765
+ orientationLayout.addWidget(self.override_angles, 3, 0, 1, 2)
766
+
767
+ self.cached_angles = [0. ,0., 0., 0.]
768
+ self.angles = []
769
+ for i, index in enumerate(['alpha', 'chi', 'phi', 'theta']):
770
+ orientationLayout.addWidget(qt.QLabel("%s:" % index),i,2)
771
+ edit = qt.QDoubleSpinBox()
772
+ edit.setRange(-360,360)
773
+ edit.setDecimals(4)
774
+ edit.setSuffix(u" °")
775
+ edit.setValue(0.)
776
+ edit.setEnabled(False)
777
+ orientationLayout.addWidget(edit,i,3)
778
+ self.angles.append(edit)
779
+
780
+ self.xyz = []
781
+ for i, index in enumerate(['x', 'y', 'z']):
782
+ orientationLayout.addWidget(qt.QLabel("%s:" % index),i,4)
783
+ edit = qt.QDoubleSpinBox()
784
+ edit.setRange(-1000,1000)
785
+ edit.setDecimals(4)
786
+ orientationLayout.addWidget(edit,i,5)
787
+ edit.setValue(1. if i == 2 else 0.)
788
+ self.xyz.append(edit)
789
+
790
+ alignGroup.setLayout(orientationLayout)
791
+
792
+ referenceGroup = qt.QGroupBox("Reference frame")
793
+ referenceLayout = qt.QVBoxLayout()
794
+ self.alphaFrame = qt.QRadioButton("surface")
795
+ self.alphaFrame.setChecked(True)
796
+ self.labFrame = qt.QRadioButton("laboratory")
797
+
798
+ referenceLayout.addWidget(self.alphaFrame)
799
+ referenceLayout.addWidget(self.labFrame)
800
+ referenceLayout.addStretch(1)
801
+ referenceGroup.setLayout(referenceLayout)
802
+
803
+ alignbtnlayout = qt.QVBoxLayout()
804
+ alignbtnlayout.addWidget(referenceGroup)
805
+
806
+ self.alignBtn = qt.QPushButton("Align")
807
+ self.alignBtn.clicked.connect(self.onAlignU)
808
+ alignbtnlayout.addWidget(self.alignBtn)
809
+
810
+
811
+ editLayout = qt.QHBoxLayout()
812
+
813
+ editLayout.addWidget(alignGroup)
814
+ editLayout.addLayout(alignbtnlayout)
815
+
816
+ mainLayout = qt.QVBoxLayout()
817
+ mainLayout.addLayout(editLayout)
818
+
819
+ bottomLayout = qt.QHBoxLayout()
820
+
821
+ uGroup = qt.QGroupBox("Orientation matrix")
822
+ self.uview = ArrayEditWidget(True, 1, False)
823
+ self.uview.model.dataChanged.connect(self.onUChanged)
824
+ self.uview.sigDataLoaded.connect(self.onUChanged)
825
+ la = qt.QVBoxLayout()
826
+ la.addWidget(self.uview)
827
+ uGroup.setLayout(la)
828
+
829
+ bottomLayout.addWidget(uGroup)
830
+
831
+ defaultGroup = qt.QGroupBox("Default geometries")
832
+
833
+ self.uDefaults = qt.QComboBox()
834
+ for i, geometry in enumerate(udefaults.u_defaults):
835
+ self.uDefaults.addItem(geometry, udefaults.u_defaults[geometry])
836
+ self.uDefaults.setItemData(i, udefaults.u_defaults[geometry].__doc__, qt.Qt.ToolTipRole)
837
+ udef = qt.QVBoxLayout()
838
+ udef.addWidget(self.uDefaults)
839
+ resetUbtn = qt.QPushButton("reset")
840
+ udef.addWidget(resetUbtn)
841
+ resetUbtn.clicked.connect(self.onResetU)
842
+
843
+ defaultGroup.setLayout(udef)
844
+
845
+ bottomLayout.addWidget(defaultGroup)
846
+
847
+ mainLayout.addLayout(bottomLayout)
848
+
849
+ self.setLayout(mainLayout)
850
+
851
+ def _onOverride(self, override):
852
+ if override:
853
+ for edit, val in zip(self.angles, self.cached_angles):
854
+ edit.setEnabled(True)
855
+ else:
856
+ for i, (edit, val) in enumerate(zip(self.angles, self.cached_angles)):
857
+ if i == 3:
858
+ edit.setValue(-np.rad2deg(val))
859
+ else:
860
+ edit.setValue(np.rad2deg(val))
861
+ edit.setEnabled(False)
862
+
863
+ def onAlignU(self):
864
+ hkl = np.array([edit.value() for edit in self.hkl])
865
+ angles = self.getAngles()
866
+ xyz = np.array([edit.value() for edit in self.xyz])
867
+ if self.alphaFrame.isChecked():
868
+ frame = 'surface'
869
+ elif self.labFrame.isChecked():
870
+ frame = 'lab'
871
+ ddict = {'hkl' : hkl,
872
+ 'xyz' : xyz,
873
+ 'angles' : angles,
874
+ 'frame' : frame}
875
+ self.sigAlignRequest.emit(ddict)
876
+
877
+ def setU(self, U):
878
+ self.uview.setArrayData(U, None, True, True)
879
+
880
+ def getU(self):
881
+ return self.uview.getData()
882
+
883
+ def setAngles(self, alpha, chi, phi, omega):
884
+ self.cached_angles = [alpha, chi, phi, omega]
885
+ if not self.override_angles.isChecked():
886
+ for i, (edit, val) in enumerate(zip(self.angles, self.cached_angles)):
887
+ if i == 3:
888
+ edit.setValue(-np.rad2deg(val))
889
+ else:
890
+ edit.setValue(np.rad2deg(val))
891
+
892
+ def getAngles(self):
893
+ ang = []
894
+ for i, edit in enumerate(self.angles):
895
+ if i == 3:
896
+ ang.append(-np.deg2rad(edit.value()))
897
+ else:
898
+ ang.append(np.deg2rad(edit.value()))
899
+ return np.array(ang)
900
+
901
+ def onResetU(self):
902
+ self.sigResetRequest.emit(self.uDefaults.currentData())
903
+
904
+ def onUChanged(self):
905
+ print("changed")
906
+ self.sigUChanged.emit(self.getU())
907
+
908
+
909
+ class QUEditDialog(qt.QDialog):
910
+ sigHide = qt.pyqtSignal()
911
+
912
+ def __init__(self,uedit,parent=None):
913
+ qt.QDialog.__init__(self, parent=None)
914
+ self.uedit = uedit
915
+ layout = qt.QVBoxLayout()
916
+ layout.addWidget(uedit)
917
+
918
+ self.savedU = self.uedit.getU()
919
+
920
+ buttons = qt.QDialogButtonBox(qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel | qt.QDialogButtonBox.Reset,
921
+ qt.Qt.Horizontal)
922
+ layout.addWidget(buttons)
923
+
924
+ okbtn = buttons.button(qt.QDialogButtonBox.Ok)
925
+ cancelbtn = buttons.button(qt.QDialogButtonBox.Cancel)
926
+ resetbtn = buttons.button(qt.QDialogButtonBox.Reset)
927
+
928
+ okbtn.clicked.connect(self.hide)
929
+ cancelbtn.clicked.connect(self.onCancel)
930
+ resetbtn.clicked.connect(self.resetParameters)
931
+
932
+ self.setLayout(layout)
933
+
934
+ def showEvent(self, event):
935
+ if event.spontaneous():
936
+ super().showEvent(event)
937
+ else:
938
+ self.savedU = self.uedit.getU()
939
+ super().showEvent(event)
940
+
941
+ def hideEvent(self, event):
942
+ self.sigHide.emit()
943
+ super().hideEvent(event)
944
+
945
+ def resetParameters(self):
946
+ self.uedit.setU(self.savedU)
947
+ self.uedit.onUChanged()
948
+
949
+ def onCancel(self):
950
+ self.resetParameters()
951
+ self.hide()
952
+
953
+
954
+
955
+
956
+ class QMachineParameters(qt.QWidget):
957
+ sigMachineParamsChanged = qt.pyqtSignal(list)
958
+ def __init__(self,parent=None):
959
+ qt.QWidget.__init__(self, parent=None)
960
+
961
+ #[E,mu,sdd,pixsize,cp,chi,phi] = params
962
+
963
+ mainLayout = qt.QGridLayout()
964
+
965
+ mainLayout.addWidget(qt.QLabel("Energy:"),0,0)
966
+ mainLayout.addWidget(qt.QLabel("SDD:"),1,0)
967
+ mainLayout.addWidget(qt.QLabel("mu:"),2,0)
968
+ mainLayout.addWidget(qt.QLabel("chi:"),3,0)
969
+ mainLayout.addWidget(qt.QLabel("azimuth:"),4,0)
970
+ mainLayout.addWidget(qt.QLabel("Pol factor:"),5,0)
971
+
972
+ mainLayout.addWidget(qt.QLabel("Centr X:"),0,2)
973
+ mainLayout.addWidget(qt.QLabel("Centr Y:"),1,2)
974
+ mainLayout.addWidget(qt.QLabel("pixel size:"),2,2)
975
+ mainLayout.addWidget(qt.QLabel("phi:"),3,2)
976
+ mainLayout.addWidget(qt.QLabel("polarization axis:"),4,2)
977
+
978
+ self.loadConfigButton = qt.QPushButton("load config",self)
979
+ self.loadConfigButton.setToolTip("load machine and crystal configuration from configfile,\naccepts poni file from pyFAI")
980
+ mainLayout.addWidget(self.loadConfigButton,5,2)
981
+
982
+ self.Ebox = qt.QDoubleSpinBox()
983
+ self.Ebox.setRange(0.01,1000)
984
+ self.Ebox.setDecimals(4)
985
+ self.Ebox.setSuffix(u" keV")
986
+
987
+ mainLayout.addWidget(self.Ebox,0,1)
988
+
989
+ self.SDDbox = qt.QDoubleSpinBox()
990
+ self.SDDbox.setRange(0.001,100)
991
+ self.SDDbox.setDecimals(4)
992
+ self.SDDbox.setSuffix(u" m")
993
+ self.SDDbox.setSingleStep(0.01)
994
+ mainLayout.addWidget(self.SDDbox,1,1)
995
+
996
+ self.mubox = qt.QDoubleSpinBox()
997
+ self.mubox.setRange(0,90)
998
+ self.mubox.setSingleStep(0.01)
999
+ self.mubox.setDecimals(4)
1000
+ self.mubox.setSuffix(u" °")
1001
+
1002
+ mainLayout.addWidget(self.mubox,2,1)
1003
+
1004
+ self.chibox = qt.QDoubleSpinBox()
1005
+ self.chibox.setRange(0,90)
1006
+ self.chibox.setDecimals(4)
1007
+ self.chibox.setSuffix(u" °")
1008
+
1009
+ mainLayout.addWidget(self.chibox,3,1)
1010
+
1011
+ self.azimbox = qt.QDoubleSpinBox()
1012
+ self.azimbox.setRange(0,360)
1013
+ self.azimbox.setDecimals(4)
1014
+ self.azimbox.setSuffix(u" °")
1015
+
1016
+ mainLayout.addWidget(self.azimbox,4,1)
1017
+
1018
+ self.polfbox = qt.QDoubleSpinBox()
1019
+ self.polfbox.setRange(-1,1)
1020
+ self.polfbox.setSingleStep(0.1)
1021
+ self.polfbox.setDecimals(4)
1022
+ #self.polfbox.setSuffix(u" °")
1023
+
1024
+ mainLayout.addWidget(self.polfbox,5,1)
1025
+
1026
+
1027
+ self.cpXbox = qt.QDoubleSpinBox()
1028
+ self.cpXbox.setRange(-100000,100000)
1029
+ self.cpXbox.setDecimals(4)
1030
+ #self.cpXbox.setSuffix(u" keV")
1031
+
1032
+ mainLayout.addWidget(self.cpXbox,0,3)
1033
+
1034
+ self.cpYbox = qt.QDoubleSpinBox()
1035
+ self.cpYbox.setRange(-100000,100000)
1036
+ self.cpYbox.setDecimals(4)
1037
+ #self.cpYbox.setSuffix(u" m")
1038
+
1039
+ mainLayout.addWidget(self.cpYbox,1,3)
1040
+
1041
+ self.pixsizebox = qt.QDoubleSpinBox()
1042
+ self.pixsizebox.setRange(0.000001,10)
1043
+ self.pixsizebox.setSingleStep(0.01)
1044
+ self.pixsizebox.setDecimals(5)
1045
+ self.pixsizebox.setSuffix(u" mm")
1046
+
1047
+ mainLayout.addWidget(self.pixsizebox,2,3)
1048
+
1049
+ self.phibox = qt.QDoubleSpinBox()
1050
+ self.phibox.setRange(0,90)
1051
+ self.phibox.setDecimals(4)
1052
+ self.phibox.setSuffix(u" °")
1053
+
1054
+ mainLayout.addWidget(self.phibox,3,3)
1055
+
1056
+ self.polaxbox = qt.QDoubleSpinBox()
1057
+ self.polaxbox.setRange(0,360)
1058
+ self.polaxbox.setDecimals(4)
1059
+ self.polaxbox.setSuffix(u" °")
1060
+
1061
+ mainLayout.addWidget(self.polaxbox,4,3)
1062
+
1063
+ #self.setValues(params)
1064
+
1065
+ self.Ebox.valueChanged.connect(self._onAnyValueChanged)
1066
+ self.mubox.valueChanged.connect(self._onAnyValueChanged)
1067
+ self.SDDbox.valueChanged.connect(self._onAnyValueChanged)
1068
+ self.cpXbox.valueChanged.connect(self._onAnyValueChanged)
1069
+ self.cpYbox.valueChanged.connect(self._onAnyValueChanged)
1070
+ self.chibox.valueChanged.connect(self._onAnyValueChanged)
1071
+ self.phibox.valueChanged.connect(self._onAnyValueChanged)
1072
+ self.pixsizebox.valueChanged.connect(self._onAnyValueChanged)
1073
+ self.polaxbox.valueChanged.connect(self._onAnyValueChanged)
1074
+ self.azimbox.valueChanged.connect(self._onAnyValueChanged)
1075
+ self.polfbox.valueChanged.connect(self._onAnyValueChanged)
1076
+
1077
+ self.setLayout(mainLayout)
1078
+
1079
+ def setValues(self,params):
1080
+ [E,mu,sdd,pixsize,cp,polax,polf,azim,chi,phi] = params
1081
+ signList = [self.Ebox, self.SDDbox, self.mubox,
1082
+ self.chibox, self.cpXbox, self.cpYbox,
1083
+ self.pixsizebox, self.phibox, self.polaxbox,
1084
+ self.azimbox, self.polfbox]
1085
+ with blockSignals(signList):
1086
+ self.Ebox.setValue(E)
1087
+ self.SDDbox.setValue(sdd)
1088
+ self.mubox.setValue(np.rad2deg(mu))
1089
+ self.chibox.setValue(np.rad2deg(chi))
1090
+ self.cpXbox.setValue(cp[0])
1091
+ self.cpYbox.setValue(cp[1])
1092
+ self.pixsizebox.setValue(pixsize*1e3)
1093
+ self.phibox.setValue(np.rad2deg(phi))
1094
+ self.polaxbox.setValue(np.rad2deg(polax))
1095
+ self.azimbox.setValue(np.rad2deg(azim))
1096
+ self.polfbox.setValue(polf)
1097
+ self._onAnyValueChanged()
1098
+
1099
+ def getParameters(self):
1100
+ E = self.Ebox.value()
1101
+ mu = np.deg2rad(self.mubox.value())
1102
+ sdd = self.SDDbox.value()
1103
+ pixsize = self.pixsizebox.value()*1e-3
1104
+ cp = [self.cpXbox.value(),self.cpYbox.value()]
1105
+ chi = np.deg2rad(self.chibox.value())
1106
+ phi = np.deg2rad(self.phibox.value())
1107
+ azim = np.deg2rad(self.azimbox.value())
1108
+ polax = np.deg2rad(self.polaxbox.value())
1109
+ polf = self.polfbox.value()
1110
+ return [E,mu,sdd,pixsize,cp,polax,polf,azim,chi,phi]
1111
+
1112
+ def _onAnyValueChanged(self):
1113
+ self.sigMachineParamsChanged.emit(self.getParameters())
1114
+
1115
+
1116
+
1117
+ class QMachineParametersDialog(qt.QDialog):
1118
+ sigHide = qt.pyqtSignal()
1119
+
1120
+ def __init__(self,machineparams,parent=None):
1121
+ qt.QDialog.__init__(self, parent=None)
1122
+ self.machineparams = machineparams
1123
+ layout = qt.QVBoxLayout()
1124
+ layout.addWidget(machineparams)
1125
+
1126
+ self.savedParams = self.machineparams.getParameters()
1127
+
1128
+ buttons = qt.QDialogButtonBox(qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel | qt.QDialogButtonBox.Reset,
1129
+ qt.Qt.Horizontal)
1130
+ layout.addWidget(buttons)
1131
+
1132
+ okbtn = buttons.button(qt.QDialogButtonBox.Ok)
1133
+ cancelbtn = buttons.button(qt.QDialogButtonBox.Cancel)
1134
+ resetbtn = buttons.button(qt.QDialogButtonBox.Reset)
1135
+
1136
+ okbtn.clicked.connect(self.hide)
1137
+ cancelbtn.clicked.connect(self.onCancel)
1138
+ resetbtn.clicked.connect(self.resetParameters)
1139
+
1140
+ self.setLayout(layout)
1141
+
1142
+ def showEvent(self, event):
1143
+ if event.spontaneous():
1144
+ super().showEvent(event)
1145
+ else:
1146
+ self.savedParams = self.machineparams.getParameters()
1147
+ super().showEvent(event)
1148
+
1149
+ def hideEvent(self, event):
1150
+ self.sigHide.emit()
1151
+ super().hideEvent(event)
1152
+
1153
+ def resetParameters(self):
1154
+ self.machineparams.setValues(self.savedParams)
1155
+ #self.machineparams._onAnyValueChanged()
1156
+
1157
+ def onCancel(self):
1158
+ self.resetParameters()
1159
+ self.hide()
1160
+
1161
+
1162
+ class QCrystalParameterDialog(qt.QDialog):
1163
+ sigHide = qt.pyqtSignal()
1164
+
1165
+ def __init__(self,crystalparams,parent=None):
1166
+ qt.QDialog.__init__(self, parent=None)
1167
+ self.crystalparams = crystalparams
1168
+ layout = qt.QVBoxLayout()
1169
+ layout.addWidget(crystalparams)
1170
+
1171
+ self.savedParams = None
1172
+
1173
+ buttons = qt.QDialogButtonBox(qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel | qt.QDialogButtonBox.Reset,
1174
+ qt.Qt.Horizontal)
1175
+ layout.addWidget(buttons)
1176
+
1177
+ okbtn = buttons.button(qt.QDialogButtonBox.Ok)
1178
+ cancelbtn = buttons.button(qt.QDialogButtonBox.Cancel)
1179
+ resetbtn = buttons.button(qt.QDialogButtonBox.Reset)
1180
+
1181
+ okbtn.clicked.connect(self.hide)
1182
+ cancelbtn.clicked.connect(self.onCancel)
1183
+ resetbtn.clicked.connect(self.resetParameters)
1184
+
1185
+ self.setLayout(layout)
1186
+
1187
+ def showEvent(self, event):
1188
+ if event.spontaneous():
1189
+ super().showEvent(event)
1190
+ else:
1191
+ try:
1192
+ self.savedParams = self.crystalparams.getCrystal(), self.crystalparams.getRefractionIndex()
1193
+ except Exception:
1194
+ self.savedParams = None
1195
+ super().showEvent(event)
1196
+
1197
+ def hideEvent(self, event):
1198
+ self.sigHide.emit()
1199
+ super().hideEvent(event)
1200
+
1201
+ def resetParameters(self):
1202
+ if self.savedParams is not None:
1203
+ self.crystalparams.setValues(*self.savedParams)
1204
+ #self.crystalparams._onAnyValueChanged()
1205
+
1206
+ def onCancel(self):
1207
+ self.resetParameters()
1208
+ self.hide()
1209
+
1210
+