xrdPlanner 2.2.1__tar.gz → 2.3.0__tar.gz
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.
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/PKG-INFO +2 -2
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/xrdPlanner/__init__.py +3 -3
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/xrdPlanner/classes.py +256 -108
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/xrdPlanner.egg-info/PKG-INFO +2 -2
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/LICENSE +0 -0
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/README.md +0 -0
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/pyproject.toml +0 -0
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/setup.cfg +0 -0
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/xrdPlanner/resources.py +0 -0
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/xrdPlanner/run_xrdPlanner.py +0 -0
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/xrdPlanner.egg-info/SOURCES.txt +0 -0
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/xrdPlanner.egg-info/dependency_links.txt +0 -0
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/xrdPlanner.egg-info/entry_points.txt +0 -0
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/xrdPlanner.egg-info/requires.txt +0 -0
- {xrdplanner-2.2.1 → xrdplanner-2.3.0}/xrdPlanner.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: xrdPlanner
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: A tool to project X-ray diffraction cones on a detector screen at different geometries (tilt, rotation, offset) and X-ray energies
|
|
5
5
|
Author-email: Lennard Krause <lkrause@chem.au.dk>
|
|
6
6
|
Project-URL: Homepage, https://github.com/LennardKrause/xrdPlanner
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
__version__ = '2.
|
|
1
|
+
__version__ = '2.3.0'
|
|
2
2
|
__author__ = 'Lennard Krause'
|
|
3
3
|
__authors__ = ['Lennard Krause', 'Frederik H. Gjørup', 'Mads R. V. Jørgensen']
|
|
4
4
|
__email__ = 'lkrause@chem.au.dk'
|
|
5
|
-
__date__ = '
|
|
6
|
-
__year__ = '
|
|
5
|
+
__date__ = '10.01.2025'
|
|
6
|
+
__year__ = '2025'
|
|
@@ -4,15 +4,13 @@ import json
|
|
|
4
4
|
import glob
|
|
5
5
|
import shutil
|
|
6
6
|
import numpy as np
|
|
7
|
+
from scipy.optimize import curve_fit
|
|
7
8
|
import pyqtgraph as pg
|
|
8
9
|
import Dans_Diffraction as dif
|
|
9
10
|
from PyQt6 import QtWidgets, QtCore, QtGui
|
|
10
11
|
from pyFAI import calibrant
|
|
11
12
|
import xrdPlanner.resources
|
|
12
13
|
|
|
13
|
-
# make cifs added to menu in init similar to calibrants
|
|
14
|
-
# store only the path and calculate the rest on load
|
|
15
|
-
|
|
16
14
|
class MainWindow(QtWidgets.QMainWindow):
|
|
17
15
|
def __init__(self, *args, **kwargs):
|
|
18
16
|
"""
|
|
@@ -351,6 +349,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
351
349
|
'bs_label':None,
|
|
352
350
|
'conic':[],
|
|
353
351
|
'reference':[],
|
|
352
|
+
'ref_hl_label':None,
|
|
353
|
+
'ref_hl_curve':None,
|
|
354
354
|
'labels':[],
|
|
355
355
|
'polar_grid':[]}
|
|
356
356
|
|
|
@@ -368,12 +368,27 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
368
368
|
|
|
369
369
|
# add empty plot per reference contour line
|
|
370
370
|
for i in range(self.plo.conic_ref_num):
|
|
371
|
-
ref =
|
|
371
|
+
ref = HoverableCurveItem(self, useCache=True)
|
|
372
372
|
self.ax.addItem(ref)
|
|
373
373
|
self.patches['reference'].append(ref)
|
|
374
|
-
self.patches['reference'][i].setClickable(True, width=self.plo.conic_ref_linewidth*2)
|
|
375
|
-
self.patches['reference'][i].sigClicked.connect(self.tooltip_hkl_show)
|
|
376
374
|
self.patches['reference'][i].name = None
|
|
375
|
+
self.patches['reference'][i].index = None
|
|
376
|
+
|
|
377
|
+
# add ref highlight curve
|
|
378
|
+
ref_hkl_curve = pg.PlotCurveItem(useCache=True,
|
|
379
|
+
pen=pg.mkPen(color=self.conic_highlight,
|
|
380
|
+
width=self.plo.conic_ref_linewidth*2))
|
|
381
|
+
ref_hkl_curve.setVisible(False)
|
|
382
|
+
self.patches['ref_hl_curve'] = ref_hkl_curve
|
|
383
|
+
self.ax.addItem(ref_hkl_curve)
|
|
384
|
+
|
|
385
|
+
# add hkl annotation label
|
|
386
|
+
ref_hkl_label = pg.TextItem(anchor=(0.5,1.0), color=self.unit_label_color)
|
|
387
|
+
ref_hkl_label.setFont(font)
|
|
388
|
+
ref_hkl_label.setVisible(False)
|
|
389
|
+
ref_hkl_label.setZValue(1) # place label on top of all other items
|
|
390
|
+
self.patches['ref_hl_label'] = ref_hkl_label
|
|
391
|
+
self.ax.addItem(ref_hkl_label)
|
|
377
392
|
|
|
378
393
|
# add empty plot per contour line
|
|
379
394
|
for i in range(self.plo.conic_tth_num):
|
|
@@ -394,17 +409,17 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
394
409
|
self.ax.addItem(bs_label)
|
|
395
410
|
|
|
396
411
|
# add poni scatter plot
|
|
397
|
-
self.patches['poni'] = pg.ScatterPlotItem(symbol
|
|
398
|
-
size
|
|
399
|
-
brush
|
|
400
|
-
pen
|
|
412
|
+
self.patches['poni'] = pg.ScatterPlotItem(symbol=self.plo.poni_marker,
|
|
413
|
+
size=self.plo.poni_size,
|
|
414
|
+
brush=pg.mkBrush(self.cont_cmap.map(0, mode='qcolor')),
|
|
415
|
+
pen=pg.mkPen(None))
|
|
401
416
|
self.ax.addItem(self.patches['poni'])
|
|
402
417
|
|
|
403
418
|
# add beam center scatter plot
|
|
404
|
-
self.patches['beamcenter'] = pg.ScatterPlotItem(symbol
|
|
405
|
-
size
|
|
406
|
-
brush
|
|
407
|
-
pen
|
|
419
|
+
self.patches['beamcenter'] = pg.ScatterPlotItem(symbol=self.plo.beamcenter_marker,
|
|
420
|
+
size=self.plo.beamcenter_size,
|
|
421
|
+
brush=pg.mkBrush(self.cont_cmap.map(0, mode='qcolor')),
|
|
422
|
+
pen=pg.mkPen(None))
|
|
408
423
|
self.ax.addItem(self.patches['beamcenter'])
|
|
409
424
|
|
|
410
425
|
self.patches['overlay'] = pg.ImageItem()
|
|
@@ -652,6 +667,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
652
667
|
# reference contour
|
|
653
668
|
self.conic_label_fill = QtGui.QColor(self.thm.dark_conic_label_fill)
|
|
654
669
|
self.conic_ref_color = QtGui.QColor(self.thm.dark_conic_ref_color)
|
|
670
|
+
self.conic_highlight = QtGui.QColor(self.thm.dark_conic_highlight)
|
|
655
671
|
self.det_module_color = QtGui.QColor(self.thm.dark_det_module_color)
|
|
656
672
|
self.det_module_fill = QtGui.QColor(self.thm.dark_det_module_fill)
|
|
657
673
|
# general
|
|
@@ -689,6 +705,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
689
705
|
# reference contour
|
|
690
706
|
self.conic_label_fill = QtGui.QColor(self.thm.light_conic_label_fill)
|
|
691
707
|
self.conic_ref_color = QtGui.QColor(self.thm.light_conic_ref_color)
|
|
708
|
+
self.conic_highlight = QtGui.QColor(self.thm.light_conic_highlight)
|
|
692
709
|
self.det_module_color = QtGui.QColor(self.thm.light_det_module_color)
|
|
693
710
|
self.det_module_fill = QtGui.QColor(self.thm.light_det_module_fill)
|
|
694
711
|
# general
|
|
@@ -1413,7 +1430,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
1413
1430
|
|
|
1414
1431
|
# calculate the maximum resolution for the given geometry
|
|
1415
1432
|
if self.plo.conic_tth_auto:
|
|
1416
|
-
theta_max = np.rad2deg(self.
|
|
1433
|
+
theta_max = np.rad2deg(self.calc_tth_max(scale=0.90))
|
|
1417
1434
|
# make new array of 2theta values
|
|
1418
1435
|
self.cont_geom_num = np.linspace(theta_max/self.plo.conic_tth_num, theta_max, self.plo.conic_tth_num)
|
|
1419
1436
|
|
|
@@ -1507,6 +1524,9 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
1507
1524
|
- self.conic_ref_color: Color for the reference contour lines.
|
|
1508
1525
|
- self.patches['reference']: Dictionary to store the reference contour line patches.
|
|
1509
1526
|
"""
|
|
1527
|
+
# remove highlighted curve and hkl label
|
|
1528
|
+
self.patches['ref_hl_curve'].setVisible(False)
|
|
1529
|
+
self.patches['ref_hl_label'].setVisible(False)
|
|
1510
1530
|
# plot reference contour lines
|
|
1511
1531
|
# standard contour lines are to be drawn
|
|
1512
1532
|
for _n in range(self.plo.conic_ref_num):
|
|
@@ -1554,10 +1574,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
1554
1574
|
#
|
|
1555
1575
|
# self.setStyleSheet('''QToolTip {... ) didn't work
|
|
1556
1576
|
self.patches['reference'][_n].name = f'({h: 2.0f} {k: 2.0f} {l: 2.0f})<br>{round(itot, 0):,.0f}'
|
|
1577
|
+
self.patches['reference'][_n].index = _n
|
|
1557
1578
|
else:
|
|
1558
1579
|
self.patches['reference'][_n].name = f'({h: 2.0f} {k: 2.0f} {l: 2.0f})'
|
|
1580
|
+
self.patches['reference'][_n].index = _n
|
|
1559
1581
|
else:
|
|
1560
1582
|
self.patches['reference'][_n].name = None
|
|
1583
|
+
self.patches['reference'][_n].index = None
|
|
1561
1584
|
|
|
1562
1585
|
# current fraction for colormap
|
|
1563
1586
|
if self.plo.colored_reference:
|
|
@@ -1831,13 +1854,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
1831
1854
|
plo.show_polarisation = True # [bool] Show polarisation overlay
|
|
1832
1855
|
plo.show_solidangle = False # [bool] Show solid angle overlay
|
|
1833
1856
|
plo.show_unit_hover = True # [bool] Show unit value on hover
|
|
1834
|
-
plo.show_grid = False
|
|
1857
|
+
plo.show_grid = False # [bool] Show azimuthal grid
|
|
1835
1858
|
plo.azimuth_num = 13 # [int] Number of azimuthal grid lines
|
|
1836
1859
|
plo.overlay_resolution = 300 # [int] Overlay resolution
|
|
1837
1860
|
plo.overlay_toggle_warn = True # [bool] Overlay warn color threshold
|
|
1838
1861
|
# - pxrd plot -
|
|
1839
1862
|
plo.pxrd_marker_symbol = 'arrow_up' # [marker] Symbol to mark peaks
|
|
1840
|
-
plo.pxrd_marker_offset = 0.
|
|
1863
|
+
plo.pxrd_marker_offset = 0.05 # [float] offset of marker from x-axis
|
|
1841
1864
|
# - extra functions -
|
|
1842
1865
|
plo.show_fwhm = False # [bool] Show delta_d/d function
|
|
1843
1866
|
plo.sensor_thickness = 1000e-6 # [float] Detector sensor thickness [m]
|
|
@@ -1905,6 +1928,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
1905
1928
|
# light mode
|
|
1906
1929
|
thm.light_conic_label_fill = '#FFFFFF' # [color] Contour label fill color
|
|
1907
1930
|
thm.light_conic_ref_color = '#DCDCDC' # [color] Reference contour color
|
|
1931
|
+
thm.light_conic_highlight = '#FF0000' # [color] Reference contour highlight color
|
|
1908
1932
|
thm.light_beamstop_color = '#80FF0000' # [color] Beamstop color
|
|
1909
1933
|
thm.light_beamstop_edge_color = '#FF0000' # [color] Beamstop edge color
|
|
1910
1934
|
thm.light_det_module_color = '#404040' # [color] Detector module border color
|
|
@@ -1921,6 +1945,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
1921
1945
|
# dark mode
|
|
1922
1946
|
thm.dark_conic_label_fill = '#000000' # [color] Contour label fill color
|
|
1923
1947
|
thm.dark_conic_ref_color = '#303030' # [color] Reference contour color
|
|
1948
|
+
thm.dark_conic_highlight = '#FF0000' # [color] Reference contour highlight color
|
|
1924
1949
|
thm.dark_beamstop_color = '#AAFF0000' # [color] Beamstop color
|
|
1925
1950
|
thm.dark_beamstop_edge_color = '#FF0000' # [color] Beamstop edge color
|
|
1926
1951
|
thm.dark_det_module_color = '#EEEEEE' # [color] Detector module border color
|
|
@@ -2600,66 +2625,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
2600
2625
|
rect_item.setOpacity(self.plo.det_module_alpha)
|
|
2601
2626
|
self.ax.addItem(rect_item)
|
|
2602
2627
|
|
|
2603
|
-
##################
|
|
2604
|
-
# HKL TOOLTIPS #
|
|
2605
|
-
##################
|
|
2606
|
-
def tooltip_hkl_show(self, widget, event):
|
|
2607
|
-
"""
|
|
2608
|
-
Displays a tooltip with the hkl value at the position of the given widget and highlights the widget.
|
|
2609
|
-
|
|
2610
|
-
Parameters:
|
|
2611
|
-
widget (QWidget): The widget for which the tooltip is to be shown. It should have a 'name' attribute and 'opts' dictionary.
|
|
2612
|
-
event (QEvent): The event that triggered the tooltip display. It should have a 'screenPos' method.
|
|
2613
|
-
|
|
2614
|
-
Behavior:
|
|
2615
|
-
- If the widget does not have a name or the contour reference hkl is not set, the event is ignored.
|
|
2616
|
-
- Otherwise, a tooltip is shown at the event's screen position with the widget's name.
|
|
2617
|
-
- The widget is highlighted by changing its pen width.
|
|
2618
|
-
- A timer is started to remove the highlight after a specified timeout.
|
|
2619
|
-
- The timer is added to a list to keep the reference alive until it times out.
|
|
2620
|
-
|
|
2621
|
-
Note:
|
|
2622
|
-
- The tooltip is displayed using QTextEdit to allow HTML formatting.
|
|
2623
|
-
- The highlight is removed by the 'tooltip_hkl_highlight' method.
|
|
2624
|
-
"""
|
|
2625
|
-
if not widget.name or not self.cont_ref_hkl:
|
|
2626
|
-
event.ignore()
|
|
2627
|
-
else:
|
|
2628
|
-
# show hkl tooltip at position
|
|
2629
|
-
text = QtWidgets.QTextEdit(str(widget.name))
|
|
2630
|
-
text.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
|
2631
|
-
pos = QtCore.QPoint(*map(int, event.screenPos()))# - QtCore.QPoint(10,20)
|
|
2632
|
-
QtWidgets.QToolTip.showText(pos, text.toHtml())
|
|
2633
|
-
# highlight the contour
|
|
2634
|
-
# store current pen as 'name' in widget.opts
|
|
2635
|
-
pen = widget.opts['pen']
|
|
2636
|
-
width = widget.opts['pen'].width()
|
|
2637
|
-
|
|
2638
|
-
timer = QtCore.QTimer()
|
|
2639
|
-
timer.setSingleShot(True)
|
|
2640
|
-
timer.timeout.connect(lambda: self.tooltip_hkl_highlight(widget, pen, timer))
|
|
2641
|
-
widget.setPen(pg.mkPen(self.beamstop_color, width=width))
|
|
2642
|
-
#widget.setPen(pg.mkPen(self.cont_cmap.map(0.0, mode='qcolor'), width=width))
|
|
2643
|
-
# add timer to self.list to keep pointers alive
|
|
2644
|
-
# remove -> tooltip_hkl_highlight
|
|
2645
|
-
self.highlight_timers.append(timer)
|
|
2646
|
-
timer.start(self.plo.conic_ref_timeout)
|
|
2647
|
-
|
|
2648
|
-
def tooltip_hkl_highlight(self, widget, pen, timer):
|
|
2649
|
-
"""
|
|
2650
|
-
Resets the contour color of the given widget and removes the specified timer from the highlight timers list.
|
|
2651
|
-
|
|
2652
|
-
Args:
|
|
2653
|
-
widget (QGraphicsItem): The widget whose contour color needs to be reset.
|
|
2654
|
-
width (int): The width of the pen to be used for resetting the contour color.
|
|
2655
|
-
timer (QTimer): The timer to be removed from the highlight timers list.
|
|
2656
|
-
"""
|
|
2657
|
-
# reset contour color
|
|
2658
|
-
widget.setPen(pen)
|
|
2659
|
-
# remove timer
|
|
2660
|
-
if timer in self.highlight_timers:
|
|
2661
|
-
self.highlight_timers.remove(timer)
|
|
2662
|
-
|
|
2663
2628
|
#######
|
|
2664
2629
|
# CIF #
|
|
2665
2630
|
#######
|
|
@@ -3199,9 +3164,35 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
3199
3164
|
self.fwhm_plot.setLabel(axis='left', text='FWHM [\u00B0]', color=self.palette().text().color())
|
|
3200
3165
|
self.fwhm_plot.scale(sx=2, sy=3)
|
|
3201
3166
|
self.fwhm_plot.addItem(self.fwhm_curve)
|
|
3167
|
+
# Thomas-Cox-Hastings curve
|
|
3168
|
+
self.tch_curve = pg.PlotCurveItem()
|
|
3169
|
+
self.tch_curve.setPen(pg.mkPen(color=self.palette().highlight().color(), width=6))
|
|
3170
|
+
self.fwhm_plot.addItem(self.tch_curve)
|
|
3202
3171
|
preview_box_layout.addWidget(self.fwhm_plot)
|
|
3203
3172
|
layout.addWidget(preview_box)
|
|
3204
|
-
|
|
3173
|
+
|
|
3174
|
+
# Thomas-Cox-Hastings
|
|
3175
|
+
tch_box = QtWidgets.QGroupBox('Estimate Thomas-Cox-Hastings parameters')
|
|
3176
|
+
tch_box_layout = QtWidgets.QHBoxLayout()
|
|
3177
|
+
tch_box.setLayout(tch_box_layout)
|
|
3178
|
+
tch_btn_est = QtWidgets.QPushButton('Estimate')
|
|
3179
|
+
tch_btn_est.clicked.connect(self.estimate_tch_parameters)
|
|
3180
|
+
tch_box_layout.addWidget(tch_btn_est)
|
|
3181
|
+
tch_box_layout.addSpacing(20)
|
|
3182
|
+
tch_label_U = QtWidgets.QLabel('U:', alignment=QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignVCenter)
|
|
3183
|
+
tch_box_layout.addWidget(tch_label_U)
|
|
3184
|
+
self.tch_value_U = QtWidgets.QLabel()
|
|
3185
|
+
tch_box_layout.addWidget(self.tch_value_U)
|
|
3186
|
+
tch_label_V = QtWidgets.QLabel('V:', alignment=QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignVCenter)
|
|
3187
|
+
tch_box_layout.addWidget(tch_label_V)
|
|
3188
|
+
self.tch_value_V = QtWidgets.QLabel()
|
|
3189
|
+
tch_box_layout.addWidget(self.tch_value_V)
|
|
3190
|
+
tch_label_W = QtWidgets.QLabel('W:', alignment=QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignVCenter)
|
|
3191
|
+
tch_box_layout.addWidget(tch_label_W)
|
|
3192
|
+
self.tch_value_W = QtWidgets.QLabel()
|
|
3193
|
+
tch_box_layout.addWidget(self.tch_value_W)
|
|
3194
|
+
layout.addWidget(tch_box)
|
|
3195
|
+
|
|
3205
3196
|
# add description
|
|
3206
3197
|
description = QtWidgets.QLabel('This feature is currently in <b>test phase</b>, feedback is very welcome!<br>\
|
|
3207
3198
|
The estimated FWHM (H, in degrees) is shown in the bottom right corner.')
|
|
@@ -3296,7 +3287,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
3296
3287
|
dist = self.geo.dist * 1e-3
|
|
3297
3288
|
tth = np.linspace(0, np.pi/2, 180)
|
|
3298
3289
|
# or use:
|
|
3299
|
-
# _current_tth_max = self.
|
|
3290
|
+
# _current_tth_max = self.calc_tth_max()
|
|
3300
3291
|
# to get max tth for the current setup
|
|
3301
3292
|
|
|
3302
3293
|
# H2, FWHM
|
|
@@ -3372,6 +3363,28 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
3372
3363
|
# save compressed array to target
|
|
3373
3364
|
np.savez_compressed(target, fwhm=np.flipud(_fwhm_grid))
|
|
3374
3365
|
|
|
3366
|
+
def estimate_tch_parameters(self):
|
|
3367
|
+
tth_max_rad = self.calc_tth_max()
|
|
3368
|
+
tth_min = 0.0
|
|
3369
|
+
tth_max = np.rad2deg(tth_max_rad)
|
|
3370
|
+
tth, fwhm = self.fwhm_curve.getData()
|
|
3371
|
+
tch_cond = (tth > tth_min) & (tth < tth_max)
|
|
3372
|
+
tch_tth = tth[tch_cond]
|
|
3373
|
+
instr_fwhm = fwhm[tch_cond]
|
|
3374
|
+
|
|
3375
|
+
def TCH_pv_fit(tth,*UVW):
|
|
3376
|
+
"""parser for the TCH pseudo-Voigt function"""
|
|
3377
|
+
fwhm,_ = self.calc_TCH_pV(tth,*UVW,0,0)
|
|
3378
|
+
return fwhm
|
|
3379
|
+
|
|
3380
|
+
UVW = 0, 0, instr_fwhm[0]**2
|
|
3381
|
+
[u,v,w], _ = curve_fit(TCH_pv_fit, tch_tth, instr_fwhm, p0=UVW, maxfev=10000)
|
|
3382
|
+
tch_fwhm,_ = self.calc_TCH_pV(tch_tth, u, v, w, 0, 0)
|
|
3383
|
+
self.tch_curve.setData(tch_tth, tch_fwhm)
|
|
3384
|
+
self.tch_value_U.setText(f'{u:.6f}')
|
|
3385
|
+
self.tch_value_V.setText(f'{v:.6f}')
|
|
3386
|
+
self.tch_value_W.setText(f'{w:.6f}')
|
|
3387
|
+
|
|
3375
3388
|
##########
|
|
3376
3389
|
# PXRD #
|
|
3377
3390
|
##########
|
|
@@ -3395,6 +3408,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
3395
3408
|
self.pxrd_win.close()
|
|
3396
3409
|
return
|
|
3397
3410
|
self.win_pxrd_update()
|
|
3411
|
+
self.pxrd_win.adjustSize()
|
|
3398
3412
|
self.pxrd_win.show()
|
|
3399
3413
|
return
|
|
3400
3414
|
|
|
@@ -3411,10 +3425,19 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
3411
3425
|
|
|
3412
3426
|
self.pxrd_curve = pg.PlotCurveItem()
|
|
3413
3427
|
self.pxrd_curve.setPen(pg.mkPen(color=self.palette().text().color()))
|
|
3414
|
-
self.pxrd_scatt =
|
|
3428
|
+
self.pxrd_scatt = ClickableScatterPlotItem(size=20, tip=None)
|
|
3415
3429
|
self.pxrd_scatt.setPen(pg.mkPen(color=self.palette().highlight().color()))
|
|
3430
|
+
self.pxrd_scatt.setBrush(pg.mkBrush(color=self.palette().highlight().color()))
|
|
3416
3431
|
self.pxrd_scatt.setSymbol(self.plo.pxrd_marker_symbol)
|
|
3417
|
-
self.pxrd_scatt.sigClicked.connect(self.
|
|
3432
|
+
self.pxrd_scatt.sigClicked.connect(self.win_pxrd_hkl_clicked)
|
|
3433
|
+
self.pxrd_scatt_highlighted = []
|
|
3434
|
+
|
|
3435
|
+
font = QtGui.QFont()
|
|
3436
|
+
font.setPixelSize(self.plo.conic_hkl_label_size)
|
|
3437
|
+
font.setBold(True)
|
|
3438
|
+
|
|
3439
|
+
self.pxrd_label = pg.TextItem(anchor=(0.5,0.9))
|
|
3440
|
+
self.pxrd_label.setFont(font)
|
|
3418
3441
|
self.pxrd_regio = pg.LinearRegionItem(pen=pg.mkPen(None))
|
|
3419
3442
|
self.pxrd_regio.setMovable(False)
|
|
3420
3443
|
|
|
@@ -3423,9 +3446,19 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
3423
3446
|
self.pxrd_plot.setMenuEnabled(False)
|
|
3424
3447
|
self.pxrd_plot.setLabel(axis='left', text='Intensity [arb. units]', color=self.palette().text().color())
|
|
3425
3448
|
self.pxrd_plot.showGrid(x=True, y=True, alpha=0.5)
|
|
3449
|
+
self.pxrd_plot.getPlotItem().getViewBox().setDefaultPadding(0.0)
|
|
3426
3450
|
self.pxrd_plot.addItem(self.pxrd_curve)
|
|
3427
|
-
|
|
3428
|
-
|
|
3451
|
+
# if points are not visible, e.g. outside of currentrange, the plot size will
|
|
3452
|
+
# not be adjusted properly and stays larger than expected.
|
|
3453
|
+
# ignoreBound allows the plot to autorange disregarding the 'invisble' points
|
|
3454
|
+
# however we need to increase the min y padding to make the scatterplot visible!
|
|
3455
|
+
self.pxrd_plot.addItem(self.pxrd_scatt, ignoreBounds=True)
|
|
3456
|
+
self.pxrd_plot.addItem(self.pxrd_label)
|
|
3457
|
+
# same as above, allow the plot to disregard the beamstop if out of bounds
|
|
3458
|
+
self.pxrd_plot.addItem(self.pxrd_regio, ignoreBounds=True)
|
|
3459
|
+
# this invisible line will do the padding for us -> thanks Frederik!
|
|
3460
|
+
self.pxrd_line = pg.InfiniteLine(pos=0, angle=0, pen=pg.mkPen(None))
|
|
3461
|
+
self.pxrd_plot.addItem(self.pxrd_line)
|
|
3429
3462
|
|
|
3430
3463
|
powder_box_layout.addWidget(self.pxrd_plot)
|
|
3431
3464
|
layout.addWidget(powder_box)
|
|
@@ -3468,6 +3501,9 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
3468
3501
|
if self.pxrd_win is None:
|
|
3469
3502
|
return
|
|
3470
3503
|
|
|
3504
|
+
# remove highlighting of hkl on update
|
|
3505
|
+
self.win_pxrd_lowlight()
|
|
3506
|
+
|
|
3471
3507
|
# change color if theme changed
|
|
3472
3508
|
self.pxrd_curve.setPen(self.palette().text().color())
|
|
3473
3509
|
self.pxrd_plot.setBackground(self.palette().base().color())
|
|
@@ -3524,7 +3560,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
3524
3560
|
max_res_r = np.nanmax(self._tth)
|
|
3525
3561
|
min_res_r = max(np.nanmin(self._tth), fwhm.mean()/10)
|
|
3526
3562
|
else:
|
|
3527
|
-
max_res_r = self.
|
|
3563
|
+
max_res_r = self.calc_tth_max()
|
|
3528
3564
|
min_res_r = fwhm.mean()/10
|
|
3529
3565
|
|
|
3530
3566
|
# add beamstop shadow
|
|
@@ -3547,37 +3583,62 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
3547
3583
|
self.pxrd_curve.setData(x=xval, y=gauss)
|
|
3548
3584
|
|
|
3549
3585
|
peak_xval = self.calc_unit(peak_ttr)
|
|
3586
|
+
offset = (gauss.max() + gauss.min()) * self.plo.pxrd_marker_offset
|
|
3587
|
+
self.pxrd_scatt.setData(x=peak_xval,
|
|
3588
|
+
y=np.zeros(len(peak_xval))-offset,
|
|
3589
|
+
data=hkl)
|
|
3550
3590
|
# remove peaks that are ouside of the detector screen
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
self.
|
|
3591
|
+
cond = (peak_xval <= xval.max()) & (peak_xval >= xval.min())
|
|
3592
|
+
self.pxrd_scatt.setPointsVisible(cond)
|
|
3593
|
+
self.pxrd_line.setPos(-offset*2)
|
|
3554
3594
|
|
|
3595
|
+
# add axis label
|
|
3555
3596
|
self.pxrd_plot.setLabel(axis='bottom', text=self.unit_names[self.geo.unit], color=self.palette().text().color())
|
|
3597
|
+
|
|
3556
3598
|
# flip axis for d-spacing
|
|
3557
3599
|
if self.geo.unit == 1:
|
|
3558
3600
|
self.pxrd_plot.getPlotItem().getViewBox().invertX(True)
|
|
3559
3601
|
else:
|
|
3560
3602
|
self.pxrd_plot.getPlotItem().getViewBox().invertX(False)
|
|
3561
3603
|
|
|
3562
|
-
def
|
|
3563
|
-
"""
|
|
3564
|
-
Displays the HKL (Miller indices) information in a tooltip when a point is clicked.
|
|
3565
|
-
|
|
3566
|
-
Parameters:
|
|
3567
|
-
widget (QtWidgets.QWidget): The widget that triggered the event.
|
|
3568
|
-
points (list): A list of points where the event occurred.
|
|
3569
|
-
event (QtGui.QMouseEvent): The mouse event that triggered the display.
|
|
3570
|
-
|
|
3571
|
-
Returns:
|
|
3572
|
-
None
|
|
3573
|
-
"""
|
|
3604
|
+
def win_pxrd_hkl_clicked(self, widget, points, event):
|
|
3574
3605
|
if not widget.name:
|
|
3575
3606
|
return
|
|
3576
3607
|
elif len(points) > 0:
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3608
|
+
point = points[0]
|
|
3609
|
+
if event.buttons() == QtCore.Qt.MouseButton.RightButton:
|
|
3610
|
+
self.patches['reference'][point.index()].lowlight()
|
|
3611
|
+
return
|
|
3612
|
+
self.win_pxrd_lowlight()
|
|
3613
|
+
point.setPen(pg.mkPen(color=self.conic_highlight))
|
|
3614
|
+
point.setBrush(pg.mkBrush(color=self.conic_highlight))
|
|
3615
|
+
self.pxrd_scatt_highlighted.append(point)
|
|
3616
|
+
self.win_pxrd_set_hkl_label(point)
|
|
3617
|
+
# highlight in main window
|
|
3618
|
+
self.patches['reference'][point.index()].highlight()
|
|
3619
|
+
|
|
3620
|
+
def win_pxrd_set_hkl_label(self, point):
|
|
3621
|
+
self.pxrd_label.setText(str(point.data()))
|
|
3622
|
+
self.pxrd_label.setPos(point.pos())
|
|
3623
|
+
self.pxrd_label.setVisible(True)
|
|
3624
|
+
|
|
3625
|
+
def win_pxrd_highlight(self, index):
|
|
3626
|
+
# highlight from main window
|
|
3627
|
+
self.win_pxrd_lowlight()
|
|
3628
|
+
point = self.pxrd_scatt.points()[index]
|
|
3629
|
+
point.setPen(pg.mkPen(self.conic_highlight))
|
|
3630
|
+
point.setBrush(pg.mkBrush(self.conic_highlight))
|
|
3631
|
+
self.pxrd_scatt_highlighted.append(point)
|
|
3632
|
+
self.win_pxrd_set_hkl_label(point)
|
|
3633
|
+
|
|
3634
|
+
def win_pxrd_lowlight(self):
|
|
3635
|
+
_pen = pg.mkPen(color=self.palette().highlight().color())
|
|
3636
|
+
_brush = pg.mkBrush(color=self.palette().highlight().color())
|
|
3637
|
+
for p in self.pxrd_scatt_highlighted:
|
|
3638
|
+
#p.resetPen()
|
|
3639
|
+
p.setPen(_pen)
|
|
3640
|
+
p.setBrush(_brush)
|
|
3641
|
+
self.pxrd_label.setVisible(False)
|
|
3581
3642
|
|
|
3582
3643
|
#############
|
|
3583
3644
|
# EXPORT #
|
|
@@ -4826,7 +4887,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
4826
4887
|
1.05395590e-03, 1.07113920e-03, 1.08845123e-03, 1.10583974e-03,
|
|
4827
4888
|
1.12333211e-03, 1.14094222e-03]}
|
|
4828
4889
|
|
|
4829
|
-
def
|
|
4890
|
+
def calc_tth_max(self, scale=1.0):
|
|
4830
4891
|
"""
|
|
4831
4892
|
Calculate the maximum 2theta angle for the given geometry
|
|
4832
4893
|
- used to generate 2theta values to draw conics
|
|
@@ -4838,8 +4899,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
4838
4899
|
float, maximum 2-theta in radians
|
|
4839
4900
|
"""
|
|
4840
4901
|
# make screen grid
|
|
4841
|
-
size_h = np.array([-self.xdim, self.xdim])*
|
|
4842
|
-
size_v = np.array([-self.ydim, self.ydim])*
|
|
4902
|
+
size_h = np.array([-self.xdim, self.xdim])*scale
|
|
4903
|
+
size_v = np.array([-self.ydim, self.ydim])*scale
|
|
4843
4904
|
_gx, _gy = np.meshgrid(size_h, size_v, sparse=True)
|
|
4844
4905
|
# build vector -> 3 x n x m
|
|
4845
4906
|
_vec = np.full((3, 2, 2), self.geo.dist)
|
|
@@ -4857,7 +4918,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
4857
4918
|
D_a = _res[2]
|
|
4858
4919
|
# 2theta - Angle between pixel, sample, and POBI
|
|
4859
4920
|
tth = np.arctan2(R_a, D_a)
|
|
4860
|
-
# 2theta max
|
|
4921
|
+
# 2theta max
|
|
4861
4922
|
return tth.max()
|
|
4862
4923
|
|
|
4863
4924
|
def rot_100(self, a, cc=1):
|
|
@@ -5396,6 +5457,26 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
5396
5457
|
"""
|
|
5397
5458
|
return 1/(np.sqrt(2*np.pi)*s)*np.exp(-np.square((x - m)/s)/2)
|
|
5398
5459
|
|
|
5460
|
+
def calc_TCH_pV(self, tth, U, V, W, X, Y):
|
|
5461
|
+
"""
|
|
5462
|
+
Thompson-Cox-Hastings pseudo-Voigt
|
|
5463
|
+
Gaussian FWHM: U*tan(theta)^2 + V*tan(theta) + W
|
|
5464
|
+
Lorentzian FWHM: X*tan(theta) + Y/cos(theta)
|
|
5465
|
+
return pseudo Voigt FWHM
|
|
5466
|
+
"""
|
|
5467
|
+
theta = tth*np.pi/360
|
|
5468
|
+
tt = np.tan(theta)
|
|
5469
|
+
ct = np.cos(theta)
|
|
5470
|
+
G = np.sqrt(U*tt**2 + V*tt + W)
|
|
5471
|
+
L = X*tt + Y/ct
|
|
5472
|
+
|
|
5473
|
+
H = (G**5 + 2.69269*G**4*L + 2.42843*G**3*L**2 \
|
|
5474
|
+
+ 4.47163*G**2*L**3 + 0.07842*G*L**4 + L**5)**(1/5)
|
|
5475
|
+
# notice that the eta is defined differently in the FullProf manual
|
|
5476
|
+
# such that eta = 1-eta_FullProf
|
|
5477
|
+
eta = 1-(1.36603*L/H - 0.47719*(L/H)**2 + 0.11116*(L/H)**3)
|
|
5478
|
+
return H, eta
|
|
5479
|
+
|
|
5399
5480
|
#############
|
|
5400
5481
|
# SETTINGS #
|
|
5401
5482
|
#############
|
|
@@ -6407,4 +6488,71 @@ class Ref(object):
|
|
|
6407
6488
|
Returns:
|
|
6408
6489
|
bool: True if all required attributes are present, False otherwise.
|
|
6409
6490
|
"""
|
|
6410
|
-
return np.all([self.has_cif, self.has_dsp, self.has_hkl])
|
|
6491
|
+
return np.all([self.has_cif, self.has_dsp, self.has_hkl])
|
|
6492
|
+
|
|
6493
|
+
class HoverableCurveItem(pg.PlotCurveItem):
|
|
6494
|
+
def __init__(self, parent=None, hoverable=True, *args, **kwargs):
|
|
6495
|
+
super().__init__(*args, **kwargs)
|
|
6496
|
+
self.parent = parent
|
|
6497
|
+
self.basePen = self.opts['pen']
|
|
6498
|
+
self.hoverable = hoverable
|
|
6499
|
+
self.setAcceptHoverEvents(True)
|
|
6500
|
+
|
|
6501
|
+
def setData(self, *args, **kargs):
|
|
6502
|
+
# added the pen re-assignment to the function.
|
|
6503
|
+
if 'pen' in kargs:
|
|
6504
|
+
self.basePen = kargs['pen']
|
|
6505
|
+
return super().setData(*args, **kargs)
|
|
6506
|
+
|
|
6507
|
+
def highlight(self, pos=None):
|
|
6508
|
+
self.parent.patches['ref_hl_curve'].setData(self.xData, self.yData)
|
|
6509
|
+
self.parent.patches['ref_hl_curve'].setVisible(True)
|
|
6510
|
+
self.parent.patches['ref_hl_label'].setText(str(self.name))
|
|
6511
|
+
self.parent.patches['ref_hl_label'].setVisible(True)
|
|
6512
|
+
if pos is None:
|
|
6513
|
+
self.parent.patches['ref_hl_label'].setPos(self.xData[0], self.yData[0])
|
|
6514
|
+
else:
|
|
6515
|
+
self.parent.patches['ref_hl_label'].setPos(pos)
|
|
6516
|
+
|
|
6517
|
+
if self.parent.pxrd_win is not None and self.parent.pxrd_win.isVisible():
|
|
6518
|
+
self.parent.win_pxrd_highlight(self.index)
|
|
6519
|
+
|
|
6520
|
+
def lowlight(self):
|
|
6521
|
+
self.setPen(self.basePen)
|
|
6522
|
+
self.parent.patches['ref_hl_label'].setVisible(False)
|
|
6523
|
+
self.parent.patches['ref_hl_curve'].setVisible(False)
|
|
6524
|
+
self.parent.win_pxrd_lowlight()
|
|
6525
|
+
|
|
6526
|
+
def hoverEvent(self, ev):
|
|
6527
|
+
if self.hoverable and not ev.isExit() and ev.buttons() == QtCore.Qt.MouseButton.LeftButton:
|
|
6528
|
+
if self.mouseShape().contains(ev.pos()):
|
|
6529
|
+
self.highlight(ev.pos())
|
|
6530
|
+
|
|
6531
|
+
def mouseClickEvent(self, ev):
|
|
6532
|
+
if ev.buttons() == QtCore.Qt.MouseButton.LeftButton:
|
|
6533
|
+
if self.mouseShape().contains(ev.pos()):
|
|
6534
|
+
self.highlight(ev.pos())
|
|
6535
|
+
else:
|
|
6536
|
+
self.lowlight()
|
|
6537
|
+
return super().mouseClickEvent(ev)
|
|
6538
|
+
|
|
6539
|
+
class ClickableScatterPlotItem(pg.ScatterPlotItem):
|
|
6540
|
+
"""
|
|
6541
|
+
Reimplementation of the ScatterPlotItem class with added click event handling.
|
|
6542
|
+
The original class is limited to left mouse button click events.
|
|
6543
|
+
"""
|
|
6544
|
+
def __init__(self, *args, **kwargs):
|
|
6545
|
+
super().__init__(*args, **kwargs)
|
|
6546
|
+
|
|
6547
|
+
def mouseClickEvent(self, ev):
|
|
6548
|
+
if not ev.button() == QtCore.Qt.MouseButton.NoButton:
|
|
6549
|
+
pts = self.pointsAt(ev.pos())
|
|
6550
|
+
if len(pts) > 0:
|
|
6551
|
+
self.ptsClicked = pts
|
|
6552
|
+
ev.accept()
|
|
6553
|
+
self.sigClicked.emit(self, self.ptsClicked, ev)
|
|
6554
|
+
else:
|
|
6555
|
+
#print "no spots"
|
|
6556
|
+
ev.ignore()
|
|
6557
|
+
else:
|
|
6558
|
+
ev.ignore()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: xrdPlanner
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: A tool to project X-ray diffraction cones on a detector screen at different geometries (tilt, rotation, offset) and X-ray energies
|
|
5
5
|
Author-email: Lennard Krause <lkrause@chem.au.dk>
|
|
6
6
|
Project-URL: Homepage, https://github.com/LennardKrause/xrdPlanner
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|