1
0
forked from IPKM/nmreval

changed FFHS integration; wrapping phase values; small stuff;

This commit is contained in:
dominik 2022-09-27 17:35:05 +02:00
parent 5120c9d57c
commit 89ce4bab9f
30 changed files with 423 additions and 321 deletions

View File

@ -8,7 +8,7 @@ from .signals import Signal
class FID(Signal):
"""
Extensions if :class:`Signal` for NMR timesignals
Extensions of :class:`Signal` for NMR timesignals
"""
def __init__(self, x, y, **kwargs):
super().__init__(x, y, **kwargs)

View File

@ -117,8 +117,6 @@ class Points:
Args:
value: array of the same length as full or masked y
Returns:
"""
value = np.asarray(value, dtype=self._y.dtype)
if value.shape == self._y.shape:
@ -169,8 +167,6 @@ class Points:
Args:
opts:
Returns:
"""
self.meta.update(opts)
@ -278,7 +274,7 @@ class Points:
avg_range: Tuple[int, int] = (0, 0), avg_mode: str = 'mean',
pts: Optional[list] = None) -> List[tuple]:
"""
Return (x, y) values at specific positions.
Return (x, y) values at specified positions.
Args:
idx (list, optional) : List of indexes to evaluate.

View File

@ -26,7 +26,8 @@ class FFHS(Distribution):
@staticmethod
def specdens(omega, tau0, *args):
def integrand(u, o, tau0):
return FFHS.distribution(u, tau0) * u / (1+o**2 * u**2)
return u**4 * tau0 / (81 + 9*u**2 - 2*u**4 + u**6) / (u**4 + (o*tau0)**2)
# return FFHS.distribution(u, tau0) * u / (1+o**2 * u**2)
ret_val = np.array([quad(integrand, 0, np.infty, args=(o, tau0), epsabs=1e-12, epsrel=1e-12)[0] for o in omega])

View File

@ -35,7 +35,7 @@ class LogGaussian(Distribution):
integration_ranges = [(omega_i, tau_j, sigma) for (omega_i, tau_j) in product(_t, _tau)]
with np.errstate(divide='ignore'):
res = np.array(pool.map(_integrate_process_3, integration_ranges))
res = np.array(pool.map(_integrate_process_time, integration_ranges))
ret_val = res.reshape((_t.shape[0], _tau.shape[0]))
return ret_val.squeeze()
@ -49,8 +49,8 @@ class LogGaussian(Distribution):
integration_ranges = [(omega_i, tau_j, sigma) for (omega_i, tau_j) in product(_omega, _tau)]
with np.errstate(divide='ignore'):
res_real = np.array(pool.map(_integrate_process_1, integration_ranges))
res_imag = np.array(pool.map(_integrate_process_2, integration_ranges))
res_real = np.array(pool.map(_integrate_process_imag, integration_ranges))
res_imag = np.array(pool.map(_integrate_process_real, integration_ranges))
ret_val = (res_real+1j*res_imag).reshape((_omega.shape[0], _tau.shape[0]))
return ret_val.squeeze()
@ -64,7 +64,7 @@ class LogGaussian(Distribution):
integration_ranges = [(omega_i, tau_j, sigma) for (omega_i, tau_j) in product(_omega, _tau)]
with np.errstate(divide='ignore'):
res = np.array(pool.map(_integrate_process_1, integration_ranges))
res = np.array(pool.map(_integrate_process_imag, integration_ranges))
ret_val = res.reshape((_omega.shape[0], _tau.shape[0]))
ret_val /= _omega[:, None]
@ -75,15 +75,15 @@ class LogGaussian(Distribution):
return args[0]*np.exp(args[1]**2 / 2)
def _integrate_process_1(args):
def _integrate_process_imag(args):
omega_i, tau_j, sigma = args
area, _ = quad(_integrand_freq_imag_high, 0, 50, args=(omega_i, tau_j, sigma))
area = quad(_integrand_freq_imag_high, 0, 50, args=(omega_i, tau_j, sigma))[0]
area += quad(_integrand_freq_imag_low, -50, 0, args=(omega_i, tau_j, sigma))[0]
return area
def _integrate_process_2(args):
def _integrate_process_real(args):
omega_i, tau_j, sigma = args
area = quad(_integrand_freq_real_high, 0, 50, args=(omega_i, tau_j, sigma))[0]
area += quad(_integrand_freq_real_low, -50, 0, args=(omega_i, tau_j, sigma))[0]
@ -91,7 +91,7 @@ def _integrate_process_2(args):
return area
def _integrate_process_3(args):
def _integrate_process_time(args):
omega_i, tau_j, sigma = args
return quad(_integrand_time, -50, 50, args=(omega_i, tau_j, sigma))[0]

View File

@ -26,7 +26,7 @@ def evaluate(sample, empty, reference, ref_points=Cyclohexane, show_cooling=Fals
if show_cooling:
fig, ax = plt.subplots()
print('\n')
for k, v in sample.heating.items():
for k, v in sample.cooling.items():
print('Plot run {} with cooling rate {} K/min'.format(k, v))
c = sample.flow_data(v, mode='c')
ax.plot(c[0], c[1], label=str(v)+' K/min')

View File

@ -2,9 +2,10 @@
# Form implementation generated from reading ui file 'resources/_ui/editsignalwidget.ui'
#
# Created by: PyQt5 UI code generator 5.12.3
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
@ -73,6 +74,7 @@ class Ui_Form(object):
self.ph1slider = QtWidgets.QDoubleSpinBox(self.groupBox_2)
self.ph1slider.setMinimum(-360.0)
self.ph1slider.setMaximum(360.0)
self.ph1slider.setWrapping(True)
self.ph1slider.setObjectName("ph1slider")
self.gridLayout_4.addWidget(self.ph1slider, 5, 1, 1, 1)
self.label_6 = QtWidgets.QLabel(self.groupBox_2)
@ -101,6 +103,7 @@ class Ui_Form(object):
self.ph0slider.setSizePolicy(sizePolicy)
self.ph0slider.setMinimum(-180.0)
self.ph0slider.setMaximum(180.0)
self.ph0slider.setWrapping(True)
self.ph0slider.setObjectName("ph0slider")
self.gridLayout_4.addWidget(self.ph0slider, 2, 1, 1, 1)
self.label_8 = QtWidgets.QLabel(self.groupBox_2)

View File

@ -2,9 +2,10 @@
# Form implementation generated from reading ui file 'resources/_ui/hdftree.ui'
#
# Created by: PyQt5 UI code generator 5.12.3
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
@ -14,25 +15,37 @@ class Ui_Hdf_Dialog(object):
def setupUi(self, Hdf_Dialog):
Hdf_Dialog.setObjectName("Hdf_Dialog")
Hdf_Dialog.resize(460, 772)
self.verticalLayout = QtWidgets.QVBoxLayout(Hdf_Dialog)
self.verticalLayout.setContentsMargins(4, 4, 4, 4)
self.verticalLayout.setSpacing(3)
self.verticalLayout_2 = QtWidgets.QVBoxLayout(Hdf_Dialog)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.label_3 = QtWidgets.QLabel(Hdf_Dialog)
self.label_3.setTextFormat(QtCore.Qt.RichText)
self.label_3.setObjectName("label_3")
self.verticalLayout_2.addWidget(self.label_3)
self.splitter = QtWidgets.QSplitter(Hdf_Dialog)
self.splitter.setOrientation(QtCore.Qt.Vertical)
self.splitter.setChildrenCollapsible(False)
self.splitter.setObjectName("splitter")
self.horizontalLayoutWidget = QtWidgets.QWidget(self.splitter)
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.horizontalLayoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setObjectName("verticalLayout")
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.verticalLayout.addLayout(self.verticalLayout_3)
self.widget = QtWidgets.QWidget(Hdf_Dialog)
self.widget = QtWidgets.QWidget(self.horizontalLayoutWidget)
self.widget.setObjectName("widget")
self.gridLayout = QtWidgets.QGridLayout(self.widget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setSpacing(2)
self.gridLayout.setObjectName("gridLayout")
self.comboBox_2 = QtWidgets.QComboBox(self.widget)
self.comboBox_2.setObjectName("comboBox_2")
self.gridLayout.addWidget(self.comboBox_2, 1, 1, 1, 1)
self.label = QtWidgets.QLabel(self.widget)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.comboBox_2 = QtWidgets.QComboBox(self.widget)
self.comboBox_2.setObjectName("comboBox_2")
self.gridLayout.addWidget(self.comboBox_2, 1, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(self.widget)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
@ -40,13 +53,18 @@ class Ui_Hdf_Dialog(object):
self.comboBox.setObjectName("comboBox")
self.gridLayout.addWidget(self.comboBox, 0, 1, 1, 1)
self.verticalLayout.addWidget(self.widget)
self.widget_2 = ExpandableWidget(Hdf_Dialog)
self.widget_2 = ExpandableWidget(self.splitter)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.widget_2.sizePolicy().hasHeightForWidth())
self.widget_2.setSizePolicy(sizePolicy)
self.widget_2.setObjectName("widget_2")
self.verticalLayout.addWidget(self.widget_2)
self.verticalLayout_2.addWidget(self.splitter)
self.buttonBox = QtWidgets.QDialogButtonBox(Hdf_Dialog)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.verticalLayout.addWidget(self.buttonBox)
self.verticalLayout_2.addWidget(self.buttonBox)
self.retranslateUi(Hdf_Dialog)
self.buttonBox.rejected.connect(Hdf_Dialog.close)
@ -56,6 +74,7 @@ class Ui_Hdf_Dialog(object):
def retranslateUi(self, Hdf_Dialog):
_translate = QtCore.QCoreApplication.translate
Hdf_Dialog.setWindowTitle(_translate("Hdf_Dialog", "View HDF file"))
self.label_3.setText(_translate("Hdf_Dialog", "<html><head/><body><p><span style=\" color:#000000;\">Colors: </span><span style=\" color:#1f77b4;\">Time signals and spectra</span><span style=\" color:#000000;\">, </span><span style=\" color:#ff7f0e;\">accumulations</span></p></body></html>"))
self.label.setText(_translate("Hdf_Dialog", "Label"))
self.label_2.setText(_translate("Hdf_Dialog", "Group"))
from ..lib.expandablewidget import ExpandableWidget

View File

@ -2,9 +2,10 @@
# Form implementation generated from reading ui file 'resources/_ui/phase_corr_dialog.ui'
#
# Created by: PyQt5 UI code generator 5.12.3
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
@ -46,6 +47,7 @@ class Ui_SignalEdit(object):
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.ph0slider.sizePolicy().hasHeightForWidth())
self.ph0slider.setSizePolicy(sizePolicy)
self.ph0slider.setWrapping(True)
self.ph0slider.setMinimum(-180.0)
self.ph0slider.setMaximum(180.0)
self.ph0slider.setObjectName("ph0slider")
@ -61,6 +63,7 @@ class Ui_SignalEdit(object):
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.ph1slider.sizePolicy().hasHeightForWidth())
self.ph1slider.setSizePolicy(sizePolicy)
self.ph1slider.setWrapping(True)
self.ph1slider.setMinimum(-360.0)
self.ph1slider.setMaximum(360.0)
self.ph1slider.setObjectName("ph1slider")

View File

@ -2,9 +2,10 @@
# Form implementation generated from reading ui file 'resources/_ui/valueeditor.ui'
#
# Created by: PyQt5 UI code generator 5.12.3
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
@ -47,30 +48,47 @@ class Ui_MaskDialog(object):
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.verticalLayout.addLayout(self.horizontalLayout)
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setContentsMargins(-1, 0, -1, -1)
self.gridLayout.setSpacing(3)
self.gridLayout.setObjectName("gridLayout")
self.line = QtWidgets.QFrame(MaskDialog)
self.line.setFrameShadow(QtWidgets.QFrame.Raised)
self.line.setLineWidth(3)
self.line.setFrameShape(QtWidgets.QFrame.HLine)
self.line.setObjectName("line")
self.verticalLayout.addWidget(self.line)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setContentsMargins(-1, 0, -1, -1)
self.horizontalLayout_2.setSpacing(3)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.add_button = QtWidgets.QPushButton(MaskDialog)
icon = QtGui.QIcon.fromTheme("list-add")
self.add_button.setIcon(icon)
self.add_button.setObjectName("add_button")
self.gridLayout.addWidget(self.add_button, 0, 0, 1, 2)
self.horizontalLayout_2.addWidget(self.add_button)
self.delete_button = QtWidgets.QPushButton(MaskDialog)
icon = QtGui.QIcon.fromTheme("list-remove")
self.delete_button.setIcon(icon)
self.delete_button.setObjectName("delete_button")
self.gridLayout.addWidget(self.delete_button, 0, 2, 1, 2)
self.horizontalLayout_2.addWidget(self.delete_button)
self.split_button = QtWidgets.QPushButton(MaskDialog)
self.split_button.setObjectName("split_button")
self.gridLayout.addWidget(self.split_button, 0, 4, 1, 2)
self.horizontalLayout_2.addWidget(self.split_button)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.line_2 = QtWidgets.QFrame(MaskDialog)
self.line_2.setLineWidth(3)
self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
self.line_2.setObjectName("line_2")
self.verticalLayout.addWidget(self.line_2)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setContentsMargins(-1, 0, -1, -1)
self.horizontalLayout_3.setSpacing(3)
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.mask_button = QtWidgets.QPushButton(MaskDialog)
self.mask_button.setObjectName("mask_button")
self.gridLayout.addWidget(self.mask_button, 1, 0, 1, 3)
self.horizontalLayout_3.addWidget(self.mask_button)
self.unmaskbutton = QtWidgets.QPushButton(MaskDialog)
self.unmaskbutton.setObjectName("unmaskbutton")
self.gridLayout.addWidget(self.unmaskbutton, 1, 3, 1, 3)
self.verticalLayout.addLayout(self.gridLayout)
self.horizontalLayout_3.addWidget(self.unmaskbutton)
self.verticalLayout.addLayout(self.horizontalLayout_3)
self.label.setBuddy(self.spinBox)
self.retranslateUi(MaskDialog)

View File

@ -7,7 +7,7 @@ from ...lib.colors import Tab10
from ..Qt import QtGui, QtCore, QtWidgets
from .._py.shift_scale_dialog import Ui_shift_dialog
from ..lib.pg_objects import PlotItem
from ..lib.utils import SciSpinBox
from ..lib.spinboxes import SciSpinBox
class QShift(QtWidgets.QDialog, Ui_shift_dialog):

View File

@ -1,8 +1,9 @@
import numpy as np
import pyqtgraph as pg
from pyqtgraph import mkPen
from numpy import inf, linspace
from numpy.fft import fft, fftfreq, fftshift
from ...lib.pg_objects import PlotItem, LogInfiniteLine
from ....lib.importer import find_models
from ....math import apodization as apodization
from ....utils.text import convert
@ -24,10 +25,19 @@ class QPreviewDialogs(QtWidgets.QDialog):
self.mode = ''
def setRange(self, xlim: list, ylim: list, logmode: list[bool]):
self.graphicsView.getPlotItem().setLogMode(x=logmode[0], y=logmode[1])
if logmode[0]:
xlim = [np.log10(x) for x in xlim]
if logmode[1]:
ylim = [np.log10(y) for y in ylim]
self.graphicsView.setRange(xRange=xlim, yRange=ylim, padding=0, disableAutoRange=True)
def add_data(self, x, y):
self.data.append((x, y))
real_plt = pg.PlotDataItem(x=x, y=y.real, pen=pg.mkColor('b'))
imag_plt = pg.PlotDataItem(x=x, y=y.imag, pen=pg.mkColor('r'))
real_plt = PlotItem(x=x, y=y.real, pen=mkPen('b'))
imag_plt = PlotItem(x=x, y=y.imag, pen=mkPen('r'))
self.graphs.append((real_plt, imag_plt))
self.graphicsView.addItem(real_plt)
self.graphicsView.addItem(imag_plt)
@ -70,7 +80,7 @@ class QPhasedialog(QPreviewDialogs, Ui_SignalEdit):
self.mode = 'ph'
self.pvt_line = pg.InfiniteLine(pos=0, movable=True)
self.pvt_line = LogInfiniteLine(pos=0, movable=True)
self.graphicsView.addItem(self.pvt_line)
self.pvt_line.sigPositionChanged.connect(self.move_line)
@ -109,7 +119,7 @@ class QApodDialog(QPreviewDialogs, Ui_ApodEdit):
self.apodcombobox.addItem(ap().name)
self.apodcombobox.blockSignals(False)
self.apod_graph = pg.PlotDataItem(x=[], y=[])
self.apod_graph = PlotItem(x=[], y=[])
self.graphicsView.addItem(self.apod_graph)
self.mode = 'ap'
@ -117,14 +127,14 @@ class QApodDialog(QPreviewDialogs, Ui_ApodEdit):
self.change_apodization(0)
def add_data(self, x, y):
real_plt = pg.PlotDataItem(x=x, y=y.real, pen=pg.mkPen('b'))
# imag_plt = pg.PlotDataItem(x=x, y=y.imag, pen=pg.mkPen('r'))
real_plt = PlotItem(x=x, y=y.real, pen=mkPen('b'))
# imag_plt = (x=x, y=y.imag, pen=pg.mkPen('r'))
self.graphicsView.addItem(real_plt)
# self.graphicsView.addItem(imag_plt)
y_fft = fftshift(fft(y))
x_fft = fftshift(fftfreq(len(x), d=x[1]-x[0]))
real_plt_fft = pg.PlotDataItem(x=x_fft, y=y_fft.real, pen=pg.mkPen('b'))
real_plt_fft = PlotItem(x=x_fft, y=y_fft.real, pen=mkPen('b'))
# imag_plt_fft = pg.PlotDataItem(x=x_fft, y=y_fft.imag, pen=pg.mkPen('b'))
self.graphicsView_2.addItem(real_plt_fft)
# self.graphicsView_2.addItem(imag_plt_fft)

View File

@ -61,10 +61,10 @@ class QHdfViewer(QtWidgets.QDialog, Ui_Hdf_Dialog):
label_item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsSelectable)
label_item.setCheckState(0, QtCore.Qt.Unchecked)
if child.type == 'signal':
label_item.setBackground(0, QtGui.QBrush(QtGui.QColor('cyan')))
label_item.setBackground(0, QtGui.QBrush(QtGui.QColor(31, 119, 180)))
label_item.setCheckState(1, QtCore.Qt.Unchecked)
elif child.type == 'points':
label_item.setBackground(0, QtGui.QBrush(QtGui.QColor('red')))
label_item.setBackground(0, QtGui.QBrush(QtGui.QColor(255, 127, 14)))
item.addChild(label_item)
self._populate_tree(child, label_item)

View File

@ -137,6 +137,7 @@ class Namespace:
class QNamespaceWidget(QtWidgets.QWidget, Ui_Form):
selected = QtCore.pyqtSignal(str)
sendKey = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent=parent)
@ -186,7 +187,9 @@ class QNamespaceWidget(QtWidgets.QWidget, Ui_Form):
value_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
key_item.setData(QtCore.Qt.UserRole, alias)
key_item.setData(QtCore.Qt.UserRole+1, entry)
value_item.setData(QtCore.Qt.UserRole, alias)
value_item.setData(QtCore.Qt.UserRole+1, entry)
row = self.namespace_table.rowCount()
self.namespace_table.setRowCount(row+1)
@ -209,3 +212,4 @@ class QNamespaceWidget(QtWidgets.QWidget, Ui_Form):
@QtCore.pyqtSlot(QtWidgets.QTableWidgetItem, name='on_namespace_table_itemDoubleClicked')
def item_selected(self, item: QtWidgets.QTableWidgetItem):
self.selected.emit(item.data(QtCore.Qt.UserRole))
self.sendKey.emit(item.data(QtCore.Qt.UserRole+1))

View File

@ -0,0 +1,45 @@
from math import inf
from ..Qt import QtWidgets, QtGui
class SciSpinBox(QtWidgets.QDoubleSpinBox):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.validator = QtGui.QDoubleValidator(self)
self.setMinimum(-inf)
self.setMaximum(inf)
self.setDecimals(1000)
self.precision = 0.001
self._prev_value = float(self.lineEdit().text())
def valueFromText(self, text: str) -> float:
try:
self._prev_value = float(self.cleanText())
except ValueError:
pass
return self._prev_value
def textFromValue(self, value: float) -> str:
if value == 0:
return '0'
else:
return f'{value:.3e}'
def stepBy(self, step: int):
self._prev_value = self.value()
new_value = self._prev_value
if new_value != 0.0:
new_value *= 10**(step/19.)
else:
new_value = 0.001
self.setValue(new_value)
self.lineEdit().setText(f'{new_value:.3e}')
def validate(self, text, pos):
return self.validator.validate(text, pos)

View File

@ -1,4 +1,3 @@
from math import inf
from contextlib import contextmanager
from numpy import linspace
from scipy.interpolate import interp1d
@ -17,48 +16,6 @@ def busy_cursor():
QtWidgets.QApplication.restoreOverrideCursor()
class SciSpinBox(QtWidgets.QDoubleSpinBox):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.validator = QtGui.QDoubleValidator(self)
self.setMinimum(-inf)
self.setMaximum(inf)
self.setDecimals(1000)
self.precision = 0.001
self._prev_value = float(self.lineEdit().text())
def valueFromText(self, text: str) -> float:
try:
self._prev_value = float(self.cleanText())
except ValueError:
pass
return self._prev_value
def textFromValue(self, value: float) -> str:
if value == 0:
return '0'
else:
return f'{value:.3e}'
def stepBy(self, step: int):
self._prev_value = self.value()
new_value = self._prev_value
if new_value != 0.0:
new_value *= 10**(step/19.)
else:
new_value = 0.001
self.setValue(new_value)
self.lineEdit().setText(f'{new_value:.3e}')
def validate(self, text, pos):
return self.validator.validate(text, pos)
class RdBuCMap:
# taken from Excel sheet from colorbrewer.org
_rdbu = [

View File

@ -714,6 +714,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
@QtCore.pyqtSlot(str)
def do_preview(self, mode):
if mode == 'ap':
dialog = QApodDialog(parent=self)
elif mode == 'ph':
@ -721,6 +722,8 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
else:
raise ValueError('Unknown preview mode %s' % str(mode))
dialog.setRange(*self.current_graph_widget.ranges, self.current_graph_widget.log)
for sid in self.current_graph_widget.active:
data_mode = self.management[sid].mode
tobeadded = False

View File

@ -51,6 +51,13 @@ class HdfNode:
self.children = OrderedDict()
self.children[key] = value
def __contains__(self, key):
if self.children is None:
return False
return key in self.children
def clear(self):
self.name = ''
self.type = 'group'
@ -386,3 +393,7 @@ class HdfReader(HdfNode):
pass
return value
def get_scripts(self) -> tuple[str, str]:
return unicode_(self.file['scripts/experiment_script'][()]), \
unicode_(self.file['scripts/result_script'][()])

View File

@ -296,8 +296,8 @@ def _kww_sin_single(w, tau, beta):
sign = np.sign(_w)
low_approx = _w < _kwwc_lim_low(beta)
high_approx = _w > _kwwc_lim_hig(beta)
low_approx = _w < _kwws_lim_low(beta)
high_approx = _w > _kwws_lim_hig(beta)
mid_integration = ~(low_approx | high_approx)
ret_val = np.zeros_like(_w, dtype=float)

View File

@ -20,7 +20,7 @@ and
\sum_{i=0}^{N-1} \frac{f(t_{i+i}) - f(t_i)}{f(t_{i+i}) - f(t_i)}{t_{i+1} - t_i}
\frac{\sin(\omega t_{i+1}) - \sin(\omega t_i)}{\omega^2}
More details can befound in [Blo]
More details can be found in [Blo]
[Blo] Blochowicz, Th.: Ph.D. Thesis, Universität Bayreuth (2003)
@ -30,7 +30,7 @@ More details can befound in [Blo]
def logft_cos(x, y, new_x=None):
n = x.size
if new_x is None:
new_x = 2 * np.pi * np.geomspace(1 / np.max(x), 1 / np.min(x), num=n)
new_x = 2*np.pi * np.geomspace(1/np.max(x), 1/np.min(x), num=n)
dydx = np.diff(y) / np.diff(x)
@ -54,7 +54,7 @@ def logft_cos(x, y, new_x=None):
def logft_sin(x, y, new_x=None):
n = x.size
if new_x is None:
new_x = 2 * np.pi * np.geomspace(1 / np.max(x), 1 / np.min(x), num=n)
new_x = 2*np.pi * np.geomspace(1/np.max(x), 1/np.min(x), num=n)
dydx = np.diff(y) / np.diff(x)
@ -79,9 +79,10 @@ def logft_sin(x, y, new_x=None):
def logft_cmplx(x, y, new_x=None, backward: bool = False):
n = x.size
if new_x is None:
new_x = 2 * np.pi * np.logspace(-np.log10(np.max(x)), -np.log10(np.min(x)), num=n)
new_x = 2 * np.pi * np.geomspace(1/np.max(x), 1/np.min(x), num=n)
dydx = np.diff(y) / np.diff(x)
sign = 2*backward - 1
if n < 5000:
wt = new_x[:, None] * x[None, :]

View File

@ -5,6 +5,9 @@ Fit functions (:mod:`nmreval.models`)
.. currentmodule:: nmreval.models
Basic functions
^^^^^^^^^^^^^^^
.. autosummary::
:toctree: generated
:nosignatures:
@ -20,6 +23,14 @@ Fit functions (:mod:`nmreval.models`)
Log
Sine
Correlation functions
^^^^^^^^^^^^^^^^^^^^^
.. autosummary::
:toctree: generated
Exponential
"""
from .basic import *

View File

@ -88,7 +88,33 @@ class EpsInfty:
return ret_val
class CCwithHFW:
class _HNWithHF:
name = 'HN + HF wing'
type = 'Dielectric Spectroscopy'
equation = r'\Delta\epsilon HN(\omega, \tau, \alpha, \gamma) / CD(\omega, \tau_{c}, \alpha\gamma-\delta)'
params = [r'\Delta\epsilon', r'\tau', r'\alpha', r'\gamma', r'\tau_{c}', '\delta']
bounds = [(0, None), (0, None), (0, 1), (0, 1), (0, None), (0, 1)]
iscomplex = True
@staticmethod
def func(x, deps, tau, alpha, gamma, tauc, delta, complex_mode: int = 0):
w = 2 * np.pi * x
numerator = (1 + 1j*w*tauc) ** (gamma-delta)
denominator = (1 + (1j*w*tau)**alpha) ** gamma
epsilon = deps * np.conjugate(numerator / denominator)
if complex_mode == 0:
return epsilon
elif complex_mode == 1:
return epsilon.real
elif complex_mode == 2:
return epsilon.imag
else:
raise ValueError(f'{complex_mode!r} has not value 0, 1, or 2')
class CCWithHF:
name = 'CC + HF wing'
type = 'Dielectric Spectroscopy'
equation = r'\Delta\epsilon CC(\omega, \tau, \alpha) / CD(\omega, \tau_{c}, \beta-\delta)'
@ -98,23 +124,10 @@ class CCwithHFW:
@staticmethod
def func(x, deps, tau, alpha, tauc, delta, complex_mode: int = 0):
w = 2*np.pi*x
numerator = (1 + 1j*w*tauc)**(alpha-delta)
denominator = 1 + (1j*w*tau)**alpha
epsilon = deps * np.conjugate(numerator / denominator)
if complex_mode == 0:
return epsilon
elif complex_mode == 1:
return epsilon.real
elif complex_mode == 2:
return epsilon.imag
else:
raise ValueError(f'{complex_mode!r} has not value 0, 1, or 2')
return _HNWithHF.func(x, deps, tau, alpha, 1, tauc, delta, complex_mode=complex_mode)
class CDwithHFW:
class CDWithHF:
name = 'CD + HF wing'
type = 'Dielectric Spectroscopy'
equation = r'\Delta\epsilon CD(\omega, \tau, \gamma) / CD(\omega, \tau_{c}, \gamma-\delta)'
@ -124,20 +137,7 @@ class CDwithHFW:
@staticmethod
def func(x, deps, tau, gamma, tauc, delta, complex_mode: int = 0):
w = 2*np.pi*x
numerator = (1 + 1j*w*tauc)**(gamma-delta)
denominator = (1 + 1j*w*tau)**gamma
epsilon = deps * np.conjugate(numerator / denominator)
if complex_mode == 0:
return epsilon
elif complex_mode == 1:
return epsilon.real
elif complex_mode == 2:
return epsilon.imag
else:
raise ValueError(f'{complex_mode!r} has not value 0, 1, or 2')
return _HNWithHF.func(x, deps, tau, 1, gamma, tauc, delta, complex_mode=complex_mode)
class PowerLawBDS:
@ -232,3 +232,52 @@ class DerivativeColeDavidson:
denom = (1 + omtau**2)**((1+g)/2.)
return eps * np.pi * numer / denom / 2.
class _DerivativeHNWithHF:
name = 'Derivative (HN + HF wing)'
type = 'Dielectric Spectroscopy'
params = [r'\Delta\epsilon', r'\tau', r'\alpha', r'\gamma', r'\tau_{c}', r'\delta']
bounds = [(0, None), (0, None), (0, 1), (0, 1), (0, None), (0, 1)]
@staticmethod
def func(x, deps, tau, alpha, gamma, tauc, delta):
w = 2*np.pi*x
a_pi2 = alpha*np.pi/2
w_lamb = (w*tau)**alpha
w_mu = w*tauc
ag_d = alpha*gamma - delta
phi = np.sin(a_pi2) * w_lamb / (1+np.cos(a_pi2) * w_lamb)
chi = ag_d*np.arctan(w_mu) - gamma*np.arctan(phi)
m_squared = 1 + w_mu**2
l_squared = 1 + 2*np.cos(a_pi2)*w_lamb + w_lamb**2
term1 = (ag_d * w_mu**2 / m_squared - alpha*gamma * w_lamb * (w_lamb + np.cos(a_pi2)) / l_squared) * np.cos(chi)
term2 = (ag_d * w_mu / m_squared - alpha*gamma*np.sin(a_pi2) * w_lamb / l_squared) * np.sin(chi)
return deps * (term2 - term1) * m_squared**(ag_d/2) / l_squared**(gamma/2)
class DerivativeCCWithHF:
name = 'Derivative (CC + HF wing)'
type = 'Dielectric Spectroscopy'
params = [r'\Delta\epsilon', r'\tau', r'\alpha', r'\tau_{c}', r'\delta']
bounds = [(0, None), (0, None), (0, 1), (0, None), (0, 1)]
@staticmethod
def func(x, deps, tau, alpha, tauc, delta):
return _DerivativeHNWithHF.func(x, deps, tau, alpha, 1, tauc, delta)
class DerivativeCDWithHF:
name = 'Derivative (CD + HF wing)'
type = 'Dielectric Spectroscopy'
params = [r'\Delta\epsilon', r'\tau', r'\gamma', r'\tau_{c}', r'\delta']
bounds = [(0, None), (0, None), (0, 1), (0, None), (0, 1)]
@staticmethod
def func(x, deps, tau, gamma, tauc, delta):
return _DerivativeHNWithHF.func(x, deps, tau, 1, gamma, tauc, delta)

View File

@ -1,3 +1,11 @@
"""
*********************
Correlation functions
*********************
Decay functions (KWW, ML,...)
"""
import numpy as np
from scipy.special import gammaincc
@ -5,6 +13,9 @@ from ..math.mittagleffler import mlf
class Exponential:
"""
Stretched exponential function
"""
type = 'Correlation function'
name = 'Stretched Exponential'
equation = r'C*exp(-(x/\tau)^{\beta})'
@ -12,6 +23,18 @@ class Exponential:
@staticmethod
def func(x, c, x0, beta):
r"""
Stretched exponential function
.. math::
x = c\exp(-x/x_0)
Args:
x (array-like): Input values
c (float): Amplitude
x0 (float):
beta (float): Stretching parameter
"""
return c*np.exp(-(x/x0)**beta)

View File

@ -49,7 +49,7 @@ class ColeColeFC(_AbstractFC):
relax = Relaxation(distribution=ColeCole)
class ColeDavidsionFC(_AbstractFC):
class ColeDavidsonFC(_AbstractFC):
name = 'Cole-Davidson'
params = _AbstractFC.params + [r'\gamma']
bounds = _AbstractFC.bounds + [(0, 1)]

View File

@ -4,5 +4,5 @@ scipy
pyqtgraph
bsddb3
h5py
PyQt5
pyqt

View File

@ -176,6 +176,9 @@
</property>
<item row="5" column="1">
<widget class="QDoubleSpinBox" name="ph1slider">
<property name="wrapping">
<bool>true</bool>
</property>
<property name="minimum">
<double>-360.000000000000000</double>
</property>
@ -229,6 +232,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="wrapping">
<bool>true</bool>
</property>
<property name="minimum">
<double>-180.000000000000000</double>
</property>

View File

@ -13,68 +13,88 @@
<property name="windowTitle">
<string>View HDF file</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3"/>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>2</number>
</property>
<item row="1" column="1">
<widget class="QComboBox" name="comboBox_2"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Label</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Group</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBox"/>
</item>
</layout>
<widget class="QLabel" name="label_3">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#000000;&quot;&gt;Colors: &lt;/span&gt;&lt;span style=&quot; color:#1f77b4;&quot;&gt;Time signals and spectra&lt;/span&gt;&lt;span style=&quot; color:#000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot; color:#ff7f0e;&quot;&gt;accumulations&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
<item>
<widget class="ExpandableWidget" name="widget_2" native="true"/>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="childrenCollapsible">
<bool>false</bool>
</property>
<widget class="QWidget" name="horizontalLayoutWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3"/>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>2</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Label</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBox_2"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Group</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBox"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="ExpandableWidget" name="widget_2" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">

View File

@ -69,6 +69,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="wrapping">
<bool>true</bool>
</property>
<property name="minimum">
<double>-180.000000000000000</double>
</property>
@ -95,6 +98,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="wrapping">
<bool>true</bool>
</property>
<property name="minimum">
<double>-360.000000000000000</double>
</property>

View File

@ -96,14 +96,27 @@
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="topMargin">
<number>0</number>
<widget class="Line" name="line">
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="lineWidth">
<number>3</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>3</number>
</property>
<item row="0" column="0" colspan="2">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="add_button">
<property name="text">
<string>Add row</string>
@ -114,7 +127,7 @@
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<item>
<widget class="QPushButton" name="delete_button">
<property name="text">
<string>Delete rows</string>
@ -125,14 +138,34 @@
</property>
</widget>
</item>
<item row="0" column="4" colspan="2">
<item>
<widget class="QPushButton" name="split_button">
<property name="text">
<string>Split after selection</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
</layout>
</item>
<item>
<widget class="Line" name="line_2">
<property name="lineWidth">
<number>3</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>3</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="mask_button">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Masked rows are shown in green&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -142,7 +175,7 @@
</property>
</widget>
</item>
<item row="1" column="3" colspan="3">
<item>
<widget class="QPushButton" name="unmaskbutton">
<property name="text">
<string>Show all</string>

View File

@ -1,47 +0,0 @@
[metadata]
name = nmreval
version = 0.1
description = Evaluation of data
long_description = file: README.md
author = Dominik Demuth
author_email = dominik.demuth@physik.tu-darmstadt.de
install_requires =
numpy
scipy
matplotlib
bsddb3
pyqtgraph
pyqt
h5py
keywords = nmr, physics, science
classifiers =
Development Status :: 3 - Alpha
Intended Audience :: End Users/Desktop
Intended Audience :: Science/Research
Topic :: Scientific/Engineering :: Physics
Topic :: Scientific/Engineering :: Visualization
Programming Language :: Python :: 3
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3 :: Only
license = BSD 3-Clause License
[options]
include_package_data = True
packages = find:
scripts = bin/evaluate.py
[options.packages.find]
include =
nmreval*
resources*
[options.package_data]
* = *.txt, *.npz, *.png, *.json

View File

@ -1,74 +1,4 @@
"""A setuptools based setup module.
See:
https://packaging.python.org/guides/distributing-packages-using-setuptools/
https://github.com/pypa/sampleproject
"""
# Always prefer setuptools over distutils
from setuptools import setup, find_packages
import pathlib
from setuptools import setup
here = pathlib.Path(__file__).parent.resolve()
# Get the long description from the README file
long_description = (here / 'README.md').read_text(encoding='utf-8')
# Arguments marked as "Required" below must be included for upload to PyPI.
# Fields marked as "Optional" may be commented out.
setup(
# name='nmreval', # Required
# version='0.1', # Required
# description='A sample Python project', # Optional
# long_description=long_description, # Optional
# long_description_content_type='text/markdown', # Optional (see note above)
# url='https://chaos3.fkp.physik.tu-darmstadt.de/source/nmreval/', # Optional
# author='Dominik Demuth', # Optional
# author_email='dominik.demuth@physik.tu-darmstadt.de', # Optional
# classifiers=[ # Optional
# 'Development Status :: 3 - Alpha',
# 'Intended Audience :: End Users/Desktop',
# 'Intended Audience :: Science/Research',
# 'Topic :: Scientific/Engineering :: Physics',
# 'Topic :: Scientific/Engineering :: Visualization',
# 'License :: OSI Approved :: BSD 3-Clause License',
# 'Programming Language :: Python :: 3',
# 'Programming Language :: Python :: 3.7',
# 'Programming Language :: Python :: 3.8',
# 'Programming Language :: Python :: 3.9',
# "Programming Language :: Python :: 3.10",
# 'Programming Language :: Python :: 3 :: Only',
# ],
#
# keywords='nmr, physics, science', # Optional
# package_dir={'': '.'}, # Optional
# packages=find_packages(where='.'), # Required
# include_package_data=True,
# python_requires='>=3.7',
# install_requires=[
# 'numpy',
# 'scipy',
# 'matplotlib',
# 'bsddb3',
# 'pyqtgraph',
# 'pyqt',
# 'h5py'
# ], # Optional
# # extras_require={ # Optional
# # 'dev': ['check-manifest'],
# # 'test': ['coverage'],
# # },
# package_data={ # Optional
# 'sample': ['package_data.dat'],
# },
# data_files=[('my_data', ['data/data_file'])], # Optional
# entry_points={ # Optional
# 'console_scripts': [
# 'evaluate=bin:evaluate',
# ],
# },
# project_urls={ # Optional
# 'Source': 'https://chaos3.fkp.physik.tu-darmstadt.de/source/nmreval/',
# },
)
setup()