diff --git a/src/gui_qt/_py/dscfile_dialog.py b/src/gui_qt/_py/dscfile_dialog.py
index 12cb6d5..3169e44 100644
--- a/src/gui_qt/_py/dscfile_dialog.py
+++ b/src/gui_qt/_py/dscfile_dialog.py
@@ -1,29 +1,113 @@
# -*- coding: utf-8 -*-
-# Form implementation generated from reading ui file 'resources/_ui/dscfile_dialog.ui'
+# Form implementation generated from reading ui file 'src/resources/_ui/dscfile_dialog.ui'
#
-# Created by: PyQt5 UI code generator 5.9.2
+# Created by: PyQt5 UI code generator 5.15.2
#
-# 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
+
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
- Dialog.resize(962, 662)
- self.gridLayout_2 = QtWidgets.QGridLayout(Dialog)
- self.gridLayout_2.setObjectName("gridLayout_2")
- self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
- self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
- self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Save)
- self.buttonBox.setObjectName("buttonBox")
- self.gridLayout_2.addWidget(self.buttonBox, 1, 1, 1, 1)
- self.gridLayout_4 = QtWidgets.QGridLayout()
- self.gridLayout_4.setContentsMargins(-1, 0, 0, -1)
- self.gridLayout_4.setSpacing(3)
- self.gridLayout_4.setObjectName("gridLayout_4")
- self.cp_checkBox = QtWidgets.QCheckBox(Dialog)
+ Dialog.resize(1341, 799)
+ self.verticalLayout_5 = QtWidgets.QVBoxLayout(Dialog)
+ self.verticalLayout_5.setObjectName("verticalLayout_5")
+ self.splitter = QtWidgets.QSplitter(Dialog)
+ self.splitter.setOrientation(QtCore.Qt.Horizontal)
+ self.splitter.setObjectName("splitter")
+ self.verticalLayoutWidget = QtWidgets.QWidget(self.splitter)
+ self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
+ self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
+ self.verticalLayout_4.setContentsMargins(6, 6, 6, 6)
+ self.verticalLayout_4.setObjectName("verticalLayout_4")
+ self.groupBox = QtWidgets.QGroupBox(self.verticalLayoutWidget)
+ self.groupBox.setFlat(False)
+ self.groupBox.setObjectName("groupBox")
+ self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox)
+ self.verticalLayout.setContentsMargins(6, 6, 6, 6)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.step_listWidget = QtWidgets.QListWidget(self.groupBox)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.step_listWidget.sizePolicy().hasHeightForWidth())
+ self.step_listWidget.setSizePolicy(sizePolicy)
+ self.step_listWidget.setMinimumSize(QtCore.QSize(0, 0))
+ self.step_listWidget.setObjectName("step_listWidget")
+ self.verticalLayout.addWidget(self.step_listWidget)
+ self.verticalLayout_4.addWidget(self.groupBox)
+ self.groupBox_2 = QtWidgets.QGroupBox(self.verticalLayoutWidget)
+ self.groupBox_2.setObjectName("groupBox_2")
+ self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox_2)
+ self.verticalLayout_2.setContentsMargins(6, 6, 6, 6)
+ self.verticalLayout_2.setObjectName("verticalLayout_2")
+ self.groupBox_4 = QtWidgets.QGroupBox(self.groupBox_2)
+ self.groupBox_4.setObjectName("groupBox_4")
+ self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.groupBox_4)
+ self.verticalLayout_6.setContentsMargins(6, 6, 6, 6)
+ self.verticalLayout_6.setObjectName("verticalLayout_6")
+ self.empty_label = QtWidgets.QLabel(self.groupBox_4)
+ self.empty_label.setObjectName("empty_label")
+ self.verticalLayout_6.addWidget(self.empty_label)
+ self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
+ self.horizontalLayout_2.setSpacing(3)
+ self.horizontalLayout_2.setObjectName("horizontalLayout_2")
+ self.loadempty_button = QtWidgets.QPushButton(self.groupBox_4)
+ self.loadempty_button.setObjectName("loadempty_button")
+ self.horizontalLayout_2.addWidget(self.loadempty_button)
+ self.delempty_button = QtWidgets.QPushButton(self.groupBox_4)
+ self.delempty_button.setObjectName("delempty_button")
+ self.horizontalLayout_2.addWidget(self.delempty_button)
+ self.verticalLayout_6.addLayout(self.horizontalLayout_2)
+ self.verticalLayout_2.addWidget(self.groupBox_4)
+ self.groupBox_5 = QtWidgets.QGroupBox(self.groupBox_2)
+ self.groupBox_5.setObjectName("groupBox_5")
+ self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.groupBox_5)
+ self.verticalLayout_7.setContentsMargins(6, 6, 6, 6)
+ self.verticalLayout_7.setSpacing(3)
+ self.verticalLayout_7.setObjectName("verticalLayout_7")
+ self.none_radioButton = QtWidgets.QRadioButton(self.groupBox_5)
+ self.none_radioButton.setObjectName("none_radioButton")
+ self.buttonGroup = QtWidgets.QButtonGroup(Dialog)
+ self.buttonGroup.setObjectName("buttonGroup")
+ self.buttonGroup.addButton(self.none_radioButton)
+ self.verticalLayout_7.addWidget(self.none_radioButton)
+ self.isotherm_radioButton = QtWidgets.QRadioButton(self.groupBox_5)
+ self.isotherm_radioButton.setChecked(True)
+ self.isotherm_radioButton.setObjectName("isotherm_radioButton")
+ self.buttonGroup.addButton(self.isotherm_radioButton)
+ self.verticalLayout_7.addWidget(self.isotherm_radioButton)
+ self.slope_radioButton = QtWidgets.QRadioButton(self.groupBox_5)
+ self.slope_radioButton.setObjectName("slope_radioButton")
+ self.buttonGroup.addButton(self.slope_radioButton)
+ self.verticalLayout_7.addWidget(self.slope_radioButton)
+ self.widget = QtWidgets.QWidget(self.groupBox_5)
+ self.widget.setMinimumSize(QtCore.QSize(0, 33))
+ self.widget.setObjectName("widget")
+ self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget)
+ self.horizontalLayout_3.setContentsMargins(3, 3, 3, 3)
+ self.horizontalLayout_3.setObjectName("horizontalLayout_3")
+ self.limit1_lineedit = QtWidgets.QLineEdit(self.widget)
+ self.limit1_lineedit.setObjectName("limit1_lineedit")
+ self.horizontalLayout_3.addWidget(self.limit1_lineedit)
+ self.limit2_lineedit = QtWidgets.QLineEdit(self.widget)
+ self.limit2_lineedit.setText("")
+ self.limit2_lineedit.setObjectName("limit2_lineedit")
+ self.horizontalLayout_3.addWidget(self.limit2_lineedit)
+ self.verticalLayout_7.addWidget(self.widget)
+ self.verticalLayout_2.addWidget(self.groupBox_5)
+ self.verticalLayout_4.addWidget(self.groupBox_2)
+ self.groupBox_3 = QtWidgets.QGroupBox(self.verticalLayoutWidget)
+ self.groupBox_3.setObjectName("groupBox_3")
+ self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox_3)
+ self.verticalLayout_3.setContentsMargins(6, 6, 6, 6)
+ self.verticalLayout_3.setObjectName("verticalLayout_3")
+ self.cp_checkBox = QtWidgets.QCheckBox(self.groupBox_3)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -31,36 +115,8 @@ class Ui_Dialog(object):
self.cp_checkBox.setSizePolicy(sizePolicy)
self.cp_checkBox.setChecked(True)
self.cp_checkBox.setObjectName("cp_checkBox")
- self.gridLayout_4.addWidget(self.cp_checkBox, 11, 0, 1, 4)
- self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_2.setSpacing(3)
- self.horizontalLayout_2.setObjectName("horizontalLayout_2")
- self.loadempty_button = QtWidgets.QPushButton(Dialog)
- self.loadempty_button.setObjectName("loadempty_button")
- self.horizontalLayout_2.addWidget(self.loadempty_button)
- self.delempty_button = QtWidgets.QPushButton(Dialog)
- self.delempty_button.setObjectName("delempty_button")
- self.horizontalLayout_2.addWidget(self.delempty_button)
- self.gridLayout_4.addLayout(self.horizontalLayout_2, 5, 0, 1, 4)
- spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.gridLayout_4.addItem(spacerItem, 12, 0, 1, 1)
- self.isotherm_radioButton = QtWidgets.QRadioButton(Dialog)
- self.isotherm_radioButton.setChecked(True)
- self.isotherm_radioButton.setObjectName("isotherm_radioButton")
- self.buttonGroup = QtWidgets.QButtonGroup(Dialog)
- self.buttonGroup.setObjectName("buttonGroup")
- self.buttonGroup.addButton(self.isotherm_radioButton)
- self.gridLayout_4.addWidget(self.isotherm_radioButton, 6, 1, 1, 1)
- self.label_4 = QtWidgets.QLabel(Dialog)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth())
- self.label_4.setSizePolicy(sizePolicy)
- self.label_4.setStyleSheet("font-weight: bold")
- self.label_4.setObjectName("label_4")
- self.gridLayout_4.addWidget(self.label_4, 0, 0, 1, 4)
- self.reference_tableWidget = QtWidgets.QTableWidget(Dialog)
+ self.verticalLayout_3.addWidget(self.cp_checkBox)
+ self.reference_tableWidget = QtWidgets.QTableWidget(self.groupBox_3)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -75,57 +131,11 @@ class Ui_Dialog(object):
self.reference_tableWidget.horizontalHeader().setVisible(False)
self.reference_tableWidget.horizontalHeader().setStretchLastSection(True)
self.reference_tableWidget.verticalHeader().setVisible(False)
- self.gridLayout_4.addWidget(self.reference_tableWidget, 9, 0, 1, 4)
- self.step_listWidget = QtWidgets.QListWidget(Dialog)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.step_listWidget.sizePolicy().hasHeightForWidth())
- self.step_listWidget.setSizePolicy(sizePolicy)
- self.step_listWidget.setMinimumSize(QtCore.QSize(0, 0))
- self.step_listWidget.setObjectName("step_listWidget")
- self.gridLayout_4.addWidget(self.step_listWidget, 1, 0, 1, 4)
- self.label = QtWidgets.QLabel(Dialog)
- self.label.setObjectName("label")
- self.gridLayout_4.addWidget(self.label, 6, 0, 1, 1)
- self.slope_radioButton = QtWidgets.QRadioButton(Dialog)
- self.slope_radioButton.setObjectName("slope_radioButton")
- self.buttonGroup.addButton(self.slope_radioButton)
- self.gridLayout_4.addWidget(self.slope_radioButton, 6, 2, 1, 1)
- self.empty_label = QtWidgets.QLabel(Dialog)
- self.empty_label.setObjectName("empty_label")
- self.gridLayout_4.addWidget(self.empty_label, 4, 0, 1, 4)
- self.label_3 = QtWidgets.QLabel(Dialog)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth())
- self.label_3.setSizePolicy(sizePolicy)
- self.label_3.setStyleSheet("font-weight: bold")
- self.label_3.setObjectName("label_3")
- self.gridLayout_4.addWidget(self.label_3, 8, 0, 1, 4)
- self.label_2 = QtWidgets.QLabel(Dialog)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth())
- self.label_2.setSizePolicy(sizePolicy)
- self.label_2.setStyleSheet("font-weight: bold")
- self.label_2.setObjectName("label_2")
- self.gridLayout_4.addWidget(self.label_2, 3, 0, 1, 4)
- self.line = QtWidgets.QFrame(Dialog)
- self.line.setFrameShape(QtWidgets.QFrame.HLine)
- self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.line.setObjectName("line")
- self.gridLayout_4.addWidget(self.line, 7, 0, 1, 4)
- self.none_radioButton = QtWidgets.QRadioButton(Dialog)
- self.none_radioButton.setObjectName("none_radioButton")
- self.buttonGroup.addButton(self.none_radioButton)
- self.gridLayout_4.addWidget(self.none_radioButton, 6, 3, 1, 1)
+ self.verticalLayout_3.addWidget(self.reference_tableWidget)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setSpacing(3)
self.horizontalLayout.setObjectName("horizontalLayout")
- self.ref_add_pushButton = QtWidgets.QPushButton(Dialog)
+ self.ref_add_pushButton = QtWidgets.QPushButton(self.groupBox_3)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -133,7 +143,7 @@ class Ui_Dialog(object):
self.ref_add_pushButton.setSizePolicy(sizePolicy)
self.ref_add_pushButton.setObjectName("ref_add_pushButton")
self.horizontalLayout.addWidget(self.ref_add_pushButton)
- self.ref_remove_pushButton = QtWidgets.QPushButton(Dialog)
+ self.ref_remove_pushButton = QtWidgets.QPushButton(self.groupBox_3)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -141,16 +151,22 @@ class Ui_Dialog(object):
self.ref_remove_pushButton.setSizePolicy(sizePolicy)
self.ref_remove_pushButton.setObjectName("ref_remove_pushButton")
self.horizontalLayout.addWidget(self.ref_remove_pushButton)
- self.gridLayout_4.addLayout(self.horizontalLayout, 10, 0, 1, 4)
- self.line_2 = QtWidgets.QFrame(Dialog)
- self.line_2.setFrameShape(QtWidgets.QFrame.HLine)
- self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
- self.line_2.setObjectName("line_2")
- self.gridLayout_4.addWidget(self.line_2, 2, 0, 1, 4)
- self.gridLayout_2.addLayout(self.gridLayout_4, 0, 0, 1, 1)
- self.gridLayout = QtWidgets.QGridLayout()
+ self.verticalLayout_3.addLayout(self.horizontalLayout)
+ self.verticalLayout_4.addWidget(self.groupBox_3)
+ spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.verticalLayout_4.addItem(spacerItem)
+ self.buttonBox = QtWidgets.QDialogButtonBox(self.verticalLayoutWidget)
+ self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
+ self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Save)
+ self.buttonBox.setCenterButtons(True)
+ self.buttonBox.setObjectName("buttonBox")
+ self.verticalLayout_4.addWidget(self.buttonBox)
+ self.widget1 = QtWidgets.QWidget(self.splitter)
+ self.widget1.setObjectName("widget1")
+ self.gridLayout = QtWidgets.QGridLayout(self.widget1)
+ self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
- self.raw_graph = PlotWidget(Dialog)
+ self.raw_graph = PlotWidget(self.widget1)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -159,7 +175,7 @@ class Ui_Dialog(object):
self.raw_graph.setMinimumSize(QtCore.QSize(300, 200))
self.raw_graph.setObjectName("raw_graph")
self.gridLayout.addWidget(self.raw_graph, 0, 0, 1, 1)
- self.calib_graph = PlotWidget(Dialog)
+ self.calib_graph = PlotWidget(self.widget1)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -168,7 +184,7 @@ class Ui_Dialog(object):
self.calib_graph.setMinimumSize(QtCore.QSize(300, 200))
self.calib_graph.setObjectName("calib_graph")
self.gridLayout.addWidget(self.calib_graph, 1, 0, 1, 1)
- self.baseline_graph = PlotWidget(Dialog)
+ self.baseline_graph = PlotWidget(self.widget1)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -177,7 +193,7 @@ class Ui_Dialog(object):
self.baseline_graph.setMinimumSize(QtCore.QSize(300, 200))
self.baseline_graph.setObjectName("baseline_graph")
self.gridLayout.addWidget(self.baseline_graph, 0, 1, 1, 1)
- self.end_graph = PlotWidget(Dialog)
+ self.end_graph = PlotWidget(self.widget1)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -186,7 +202,7 @@ class Ui_Dialog(object):
self.end_graph.setMinimumSize(QtCore.QSize(0, 0))
self.end_graph.setObjectName("end_graph")
self.gridLayout.addWidget(self.end_graph, 1, 1, 1, 1)
- self.gridLayout_2.addLayout(self.gridLayout, 0, 1, 1, 1)
+ self.verticalLayout_5.addWidget(self.splitter)
self.retranslateUi(Dialog)
self.buttonBox.accepted.connect(Dialog.accept)
@@ -196,18 +212,20 @@ class Ui_Dialog(object):
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Read DSC file"))
- self.cp_checkBox.setText(_translate("Dialog", "Convert to heat capacity"))
+ self.groupBox.setTitle(_translate("Dialog", "Detected steps"))
+ self.groupBox_2.setTitle(_translate("Dialog", "Baseline corrections"))
+ self.groupBox_4.setTitle(_translate("Dialog", "Empty measurement"))
+ self.empty_label.setText(_translate("Dialog", "No emtpy measurement"))
self.loadempty_button.setText(_translate("Dialog", "Load empty"))
self.delempty_button.setText(_translate("Dialog", "Remove empty"))
- self.isotherm_radioButton.setText(_translate("Dialog", "Isotherms"))
- self.label_4.setText(_translate("Dialog", "Detected steps"))
- self.label.setText(_translate("Dialog", "Slope"))
- self.slope_radioButton.setText(_translate("Dialog", "Initial slope"))
- self.empty_label.setText(_translate("Dialog", "Empty measurement"))
- self.label_3.setText(_translate("Dialog", "Calibration"))
- self.label_2.setText(_translate("Dialog", "Baseline"))
+ self.groupBox_5.setTitle(_translate("Dialog", "Slope correction"))
self.none_radioButton.setText(_translate("Dialog", "None"))
+ self.isotherm_radioButton.setText(_translate("Dialog", "Isotherms"))
+ self.slope_radioButton.setText(_translate("Dialog", "Initial slope"))
+ self.limit1_lineedit.setPlaceholderText(_translate("Dialog", "start (in min)"))
+ self.limit2_lineedit.setPlaceholderText(_translate("Dialog", "stop (in min)"))
+ self.groupBox_3.setTitle(_translate("Dialog", "References"))
+ self.cp_checkBox.setText(_translate("Dialog", "Use reference to convert to heat capacity"))
self.ref_add_pushButton.setText(_translate("Dialog", "Add reference"))
self.ref_remove_pushButton.setText(_translate("Dialog", "Remove reference"))
-
from pyqtgraph import PlotWidget
diff --git a/src/gui_qt/_py/eval_expr_dialog.py b/src/gui_qt/_py/eval_expr_dialog.py
index 5bda16f..844b343 100644
--- a/src/gui_qt/_py/eval_expr_dialog.py
+++ b/src/gui_qt/_py/eval_expr_dialog.py
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'src/resources/_ui/eval_expr_dialog.ui'
#
-# Created by: PyQt5 UI code generator 5.15.9
+# Created by: PyQt5 UI code generator 5.15.2
#
# 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.
diff --git a/src/gui_qt/_py/fitdialog.py b/src/gui_qt/_py/fitdialog.py
index 8ed9207..cf7d7f6 100644
--- a/src/gui_qt/_py/fitdialog.py
+++ b/src/gui_qt/_py/fitdialog.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
-# Form implementation generated from reading ui file 'resources/_ui/fitdialog.ui'
+# Form implementation generated from reading ui file 'src/resources/_ui/fitdialog.ui'
#
-# Created by: PyQt5 UI code generator 5.12.3
+# Created by: PyQt5 UI code generator 5.15.2
#
-# 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
diff --git a/src/gui_qt/_py/fitresult.py b/src/gui_qt/_py/fitresult.py
index 987e4c6..ae2d077 100644
--- a/src/gui_qt/_py/fitresult.py
+++ b/src/gui_qt/_py/fitresult.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
-# Form implementation generated from reading ui file '/autohome/dominik/nmreval-gitea/src/resources/_ui/fitresult.ui'
+# Form implementation generated from reading ui file 'src/resources/_ui/fitresult.ui'
#
-# Created by: PyQt5 UI code generator 5.15.7
+# Created by: PyQt5 UI code generator 5.15.2
#
# 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.
diff --git a/src/gui_qt/io/dscreader.py b/src/gui_qt/io/dscreader.py
index c9fb6a3..8091e29 100644
--- a/src/gui_qt/io/dscreader.py
+++ b/src/gui_qt/io/dscreader.py
@@ -97,7 +97,7 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
if empty:
self.empty = self.calibrator.set_measurement(empty, mode='empty')
- self.empty_label.setText(str(self.empty.fname.name))
+ self.empty_label.setText('~/' + str(self.empty.fname.relative_to(Path.home())))
self.update_plots()
@@ -158,20 +158,28 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
self.sample_idx = None
self.clear_plots()
- def get_data(self, ):
+ def get_data(self):
if self.sample_idx is None:
return
rate = self.current_run[0]
- slope_type = {self.none_radioButton: None,
- self.isotherm_radioButton: 'iso',
- self.slope_radioButton: 'curve'}[self.buttonGroup.checkedButton()]
+ slope_type = {
+ self.none_radioButton: None,
+ self.isotherm_radioButton: 'iso',
+ self.slope_radioButton: 'curve',
+ }[self.buttonGroup.checkedButton()]
+
+ limit = None
+ if slope_type == 'curve':
+ try:
+ limit = float(self.limit1_lineedit.text())*60, float(self.limit2_lineedit.text())*60
+ except ValueError:
+ limit = None
try:
- raw_sample, drift_value, sample_data, empty_data, slope = self.calibrator.get_data(self.sample_idx,
- slope=slope_type)
+ raw_sample, drift_value, sample_data, empty_data, slope = self.calibrator.get_data(self.sample_idx, slope=slope_type, limits=limit)
except ValueError as e:
- _msg = QtWidgets.QMessageBox.warning(self, 'No rate found', e.args[0])
+ _msg = QtWidgets.QMessageBox.warning(self, f'Data collection with error', e.args[0])
return
self.calibrator.ref_list = []
@@ -194,6 +202,8 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
@QtCore.pyqtSlot(QtWidgets.QAbstractButton, name='on_buttonGroup_buttonClicked')
@QtCore.pyqtSlot(int, name='on_cp_checkBox_stateChanged')
+ @QtCore.pyqtSlot(str, name='on_limit1_lineedit_textChanged')
+ @QtCore.pyqtSlot(str, name='on_limit2_lineedit_textChanged')
def update_plots(self, _=None):
res = self.get_data()
if res is None:
@@ -254,7 +264,7 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
def button_clicked(self, bttn: QtWidgets.QAbstractButton):
bttn_value = self.buttonBox.standardButton(bttn)
if bttn_value in (self.buttonBox.Ok, self.buttonBox.Apply, self.buttonBox.Save):
- self.export_data(filesave=bttn_value==self.buttonBox.Save, close_after=bttn_value==self.buttonBox.Ok)
+ self.export_data(filesave=bttn_value == self.buttonBox.Save, close_after=bttn_value == self.buttonBox.Ok)
else:
super().close()
diff --git a/src/gui_qt/main/management.py b/src/gui_qt/main/management.py
index 1e118d2..aa2449f 100644
--- a/src/gui_qt/main/management.py
+++ b/src/gui_qt/main/management.py
@@ -911,7 +911,7 @@ class UpperManagement(QtCore.QObject):
self.data[new_id[0]].data = new_data
except Exception as e:
failures.append((data_i, e))
- print(str(data_i) + ' failed with Exception: ' + ''.join(e.args))
+ logger.warning(str(data_i) + ' failed with Exception: ' + ''.join(e.args))
continue
if overwrite:
@@ -946,9 +946,9 @@ class UpperManagement(QtCore.QObject):
self.newData.emit([s_id], graph)
except Exception as err:
- print('Creation failed with error: ' + ', '.join(err.args))
+ logger.exception('Creation failed with error: ' + ', '.join(err.args))
err_msg = QtWidgets.QMessageBox(parent=self.sender())
- err_msg.setText('One or more errors occured during evaluation.')
+ err_msg.setText('One or more errors occurred during evaluation.')
err_msg.setDetailedText('Creation failed with error: ' + ', '.join(err.args))
err_msg.exec()
diff --git a/src/nmreval/dsc/calibration.py b/src/nmreval/dsc/calibration.py
deleted file mode 100644
index bfae765..0000000
--- a/src/nmreval/dsc/calibration.py
+++ /dev/null
@@ -1,289 +0,0 @@
-import os
-import argparse
-import sys
-
-import numpy as np
-import matplotlib.pyplot as plt
-import scipy.interpolate
-from scipy.integrate import simps
-
-from ..io.dsc import DSCSample, Cyclohexane
-
-
-parser = argparse.ArgumentParser(description='Calibrate DSC data')
-parser.add_argument('sample', type=str, help='filename of DSC sample')
-parser.add_argument('empty', type=str, help='filename of empty pan')
-parser.add_argument('reference', help='filename of reference', type=str)
-parser.add_argument('--cooling', help='Show figure of found cooling rates', action='store_true')
-
-
-def evaluate(sample, empty, reference, ref_points=Cyclohexane, show_cooling=False):
- sample = DSCSample(sample)
- empty = DSCSample(empty)
- reference = DSCSample(reference)
-
- if show_cooling:
- fig, ax = plt.subplots()
- print('\n')
- 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')
- ax.set_xlabel('T / K')
- plt.legend()
- plt.show()
-
- return
-
- run_list = []
- if len(sample.heating) > 1:
- run = None
- print('\nMultiple heat rates found:')
- for k, v in sample.heating.items():
- print(' run {}: {} K/min'.format(k, v))
- while run not in sample.heating:
- # choose your own adventure!!!
- value = input('\nPlease select a run (press Enter for all heat rates): ')
- if value == '':
- run_list = list(sample.heating.keys())
- break
- else:
- run = int(value)
- run_list = [run]
- else:
- run_list = list(sample.heating.keys())
-
- for run in run_list:
- rate = sample.heating[run]
-
- print('\nProcessing heat rate {} K/min'.format(rate))
-
- print('Load data of heating data')
- len_sample = sample.length(run)
-
- # sanity checks
- try:
- reference_data = reference.flow_data(rate)
- except IndexError:
- print('ERROR: Reference measurement has no heat rate {} K/min'.format(rate))
- print('Stop evaluation')
- sys.exit()
-
- try:
- run_baseline = empty.get_run(rate)
- except ValueError:
- print('ERROR: Empty measurement has no heat rate {} K/min'.format(rate))
- print('Stop evaluation')
- sys.exit()
-
- len_baseline = empty.length(run_baseline)
- if len_baseline != len_sample:
- print('WARNING: measurements differ by {} points'.format(abs(len_baseline - len_sample)))
- # max_length = min(len_baseline, len_sample)
-
- sample_data = sample.flow_data(rate, length=None)
- empty_data = empty.flow_data(rate, length=None)
-
- # plot input data
- fig1, ax1 = plt.subplots(2, 3, **{'figsize': (10, 6)})
- ax1[0, 0].set_title('raw data')
- ax1[0, 0].set_xlabel('T / K')
-
- ax1[0, 0].plot(sample_data[0], sample_data[1], 'k-', label='Sample')
- ax1[0, 0].plot(empty_data[0], empty_data[1], 'b-', label='Empty')
- ax1[0, 0].plot(reference_data[0], reference_data[1], 'r-', label='Reference')
- ax1[0, 0].legend()
-
- print('Substract empty data\n')
- sample_baseline = sample_data.copy()
- empty_y = empty_data[1]
- if len_sample != len_baseline:
- with np.errstate(all='ignore'):
- empty_y = scipy.interpolate.interp1d(empty_data[0], empty_data[1],
- fill_value='extrapolate')(sample_data[0])
- sample_baseline[1] = sample_data[1] - empty_y
-
- # plot baseline correction
- ax1[0, 1].set_title('baseline correction')
- ax1[0, 1].set_xlabel('T / K')
-
- ax1[0, 1].plot(sample_data[0], sample_data[1], 'k--', label='Raw')
- ax1[0, 1].plot(sample_baseline[0], sample_baseline[1], 'k-', label='Baseline corrected')
- ax1[0, 1].plot(empty_data[0], empty_data[1], 'b-', label='Empty')
- ax1[0, 1].legend()
-
- print('Load isothermal data around heat rate')
- mean_isotherms = []
- for offset, where, ls in [(-1, 'low', '-'), (1, 'high', '--')]:
- # read isotherms and baseline correct
- len_baseline = empty.length(run_baseline+offset)
- len_sample = sample.length(run+offset)
- if len_baseline != len_sample:
- print('WARNING: {} T isotherms differ by {} points'.format(where, abs(len_baseline-len_sample)))
-
- max_length = min(len_baseline, len_sample)
- isotherm_sample = sample.isotherm_data(run_baseline+offset, length=max_length)
- isotherm_empty = empty.isotherm_data(run+offset, length=max_length)
-
- isotherm_sample[1] -= isotherm_empty[1]
-
- # get mean isotherm value
- m = np.polyfit(isotherm_sample[0, 200:-200], isotherm_sample[1, 200:-200], 0)[0]
- mean_isotherms.append(m)
- print('Calculated {} heat flow: {:.4} mW'.format(where, m))
-
- ax1[0, 2].plot(isotherm_sample[0], isotherm_sample[1], 'k--')
-
- # calculate slope from difference between isotherms
- slope = (mean_isotherms[1]-mean_isotherms[0]) / (sample_data[2, -1] - empty_data[2, 0])
- print('Heat flow slope from isotherms: {:.4} per minute'.format(slope*60))
-
- # calculate mean slope of heat flow at points in the beginning
- slope_baseline = np.gradient(sample_baseline[1, int(4000/rate):int(9000/rate)],
- sample_baseline[2, 300]-sample_baseline[2, 299]).mean()
- print('Heat flow slope from initial heating: {:.4f} per minute\n'.format(slope_baseline*60))
-
- drift_corrected = sample_baseline[1] - mean_isotherms[0] - (sample_baseline[2]-empty_data[2, 0])*slope
- drift_from_slope = sample_baseline[1] - mean_isotherms[0] - (sample_baseline[2]-empty_data[2, 0])*slope_baseline
-
- # plot
- ax1[0, 2].axhline(mean_isotherms[0], linestyle=':')
- ax1[0, 2].axhline(mean_isotherms[1], linestyle=':')
-
- ax1[0, 2].plot(sample_baseline[2], sample_baseline[1], 'k-', label='Baseline corrected')
- ax1[0, 2].plot(sample_baseline[2], drift_corrected, 'g-', label='Corrected (isotherm)')
- ax1[0, 2].plot(sample_baseline[2], drift_from_slope, 'b-', label='Corrected (heating)')
-
- ax1[0, 2].plot(sample_baseline[2], mean_isotherms[0] + (sample_baseline[2]-empty_data[2, 0])*slope, 'g--')
- ax1[0, 2].plot(sample_baseline[2], mean_isotherms[0] + slope_baseline*(sample_baseline[2]-empty_data[2, 0]),
- 'b--')
-
- ax1[0, 2].plot(sample_baseline[2, int(4000/rate):int(9000/rate)],
- sample_baseline[1, int(4000/rate):int(9000/rate)], 'r--')
-
- ax1[0, 2].set_title('time dependence')
- ax1[0, 2].set_xlabel('t / s')
- ax1[0, 2].legend()
-
- melts = []
- for i, (ref_temp, enthalpy) in enumerate(ref_points.transitions):
- # region around reference peaks
- t_low_lim = ref_temp - 15
- t_high_lim = ref_temp + 15
- low_border = np.argmin(np.abs(reference_data[0]-t_low_lim))
- high_border = np.argmin(np.abs(reference_data[0]-t_high_lim))
- ref_zoom = reference_data[:, low_border:high_border]
- x_val = np.array([[ref_zoom[0, 0], 1],
- [ref_zoom[0, -1], 1]])
- y_val = np.array([ref_zoom[1, 0],
- ref_zoom[1, -1]])
- print('Baseline correct reference of %.2f transition' % ref_temp)
- sol = np.linalg.solve(x_val, y_val)
- ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1])
- peak_max = ref_zoom[:, np.argmax(ref_zoom[1])]
- integration_limit = np.argmin(abs(ref_zoom[0]-peak_max[0]+3)), np.argmin(abs(ref_zoom[0]-peak_max[0]-3))
-
- # substract baseline around reference peaks
- x_val = np.array([[ref_zoom[0, integration_limit[0]], 1],
- [ref_zoom[0, integration_limit[1]], 1]])
- y_val = np.array([ref_zoom[1, integration_limit[0]],
- ref_zoom[1, integration_limit[1]]])
-
- print('Baseline correct reference of %.2f transition' % ref_temp)
- sol = np.linalg.solve(x_val, y_val)
- ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1])
-
- # calculate onset slope (use points at position of maximum gradient +/- 100/rate)
- ref_grad = np.gradient(ref_zoom[1])
- max_grad = np.argmax(ref_grad)
-
- x_val = np.array([[ref_zoom[0, max_grad-int(100/rate)], 1],
- [ref_zoom[0, max_grad+int(100/rate)+1], 1]])
- y_val = np.array([ref_zoom[1, max_grad-int(100/rate)],
- ref_zoom[1, max_grad+int(100/rate)+1]])
- sol = np.linalg.solve(x_val, y_val)
- onset = sol[0]*ref_zoom[0] + sol[1]
-
- melts.append(-sol[1]/sol[0])
-
- # plot
- ax1[1, i].set_title(f'reference: {ref_temp:.2f}')
- ax1[1, i].set_xlabel('T / K')
-
- ax1[1, i].plot(reference_data[0], reference_data[1], 'r-')
- ax1[1, i].plot(ref_zoom[0, max_grad], ref_zoom[0, max_grad], 'kx')
- ax1[1, i].plot(ref_zoom[0], onset, 'k--')
- ax1[1, i].axhline(0, color='k', linestyle='--')
-
- ax1[1, i].set_xlim(ref_zoom[0, integration_limit[0]], ref_zoom[0, integration_limit[1]])
- ax1[1, i].set_ylim(-max(ref_zoom[1])/10, max(ref_zoom[1])*1.1)
-
- print('Onset of transition: %.2f K found at %.2f' % (ref_temp, melts[-1]))
- if enthalpy is not None:
- # integrate over low temperature peak to calibrate y axis
- # delta H in J/g: Integrate Peak over time and divide by weight
- area = 1e-3 * simps(ref_zoom[1, integration_limit[0]:integration_limit[1]],
- ref_zoom[2, integration_limit[0]:integration_limit[1]],
- even='avg')
- calib_y_axis = enthalpy / (area / reference.weight)
- print("Calibration factor of peak: %f\n" % calib_y_axis)
-
- sample_baseline[1] *= calib_y_axis
-
- fig1.delaxes(ax1[1, 2])
- fig1.tight_layout()
-
- plt.show()
-
- # give a choice how to compensate for long-time drift
- mode = None
- while mode not in ['i', 'h']:
- mode = input('\nUse [i]sotherms or initial [h]eating for long-time correction? (Default: i) ')
- if mode == '':
- mode = 'i'
-
- if mode == 'h':
- print('\nCorrect slope from initial heating')
- sample_baseline[1] = drift_from_slope
- else:
- print('\nCorrect slope from isotherm')
- sample_baseline[1] = drift_corrected
-
- # calibrate T axis
- print('\nCalibrate temperature')
- real_trans = np.array([temp for (temp, _) in ref_points.transitions])
- t_vals = np.array([[melts[0], 1],
- [melts[1], 1]])
- calibration_temp = np.linalg.solve(t_vals, real_trans)
- print('T_real = {:.4f} * T_meas {:+.4f}'.format(*calibration_temp))
-
- sample_baseline[0] = calibration_temp[0] * sample_baseline[0] + calibration_temp[1]
-
- print('Convert to capacity')
- cp = sample_baseline[1] * 60. / rate / sample.weight / 1000.
- if sample.weight is None:
- raise ValueError('No sample weight given')
-
- # plot final results in separate figure
- fig2, ax2 = plt.subplots()
- ax2.set_title('{} K/min: Heat flow vs. heat capacity (close to cont.)'.format(rate))
- ax2.set_xlabel('Temperature / K')
-
- ax2.plot(sample_baseline[0], sample_baseline[1], label='heat flow')
- ax2.plot(sample_baseline[0], cp, label='heat capacity')
-
- plt.legend()
- plt.show()
-
- outname = os.path.splitext(sample.name)[0] + '_' + str(rate) + 'K-min.dat'
- header = 'Made with version: {}\n'.format(__version__)
- header += 'T/K\tCp/J/(gK)\theat flow/mW'
-
- print()
- print('Save to', outname)
- np.savetxt(outname, np.c_[sample_baseline[0], cp, sample_baseline[1]], header=header)
-
-
-if __name__ == '__main__':
- args = parser.parse_args()
- evaluate(args.sample, args.empty, args.reference, show_cooling=args.cooling)
diff --git a/src/nmreval/dsc/dsc_calibration_fast_neu.py b/src/nmreval/dsc/dsc_calibration_fast_neu.py
deleted file mode 100644
index 0575213..0000000
--- a/src/nmreval/dsc/dsc_calibration_fast_neu.py
+++ /dev/null
@@ -1,292 +0,0 @@
-from __future__ import annotations
-
-__version__ = '0.1.2'
-
-import os
-from argparse import ArgumentParser
-from pathlib import Path
-import sys
-import numpy as np
-import matplotlib.pyplot as plt
-from scipy.integrate import simps
-
-from nmreval.io.dsc import DSCReader, Cyclohexane, ReferenceValue
-
-parser = ArgumentParser(description='Calibrate DSC data')
-parser.add_argument('sample', type=str, help='filename of DSC sample')
-parser.add_argument('empty', type=str, help='filename of empty pan')
-parser.add_argument('reference', help='filename of reference', type=str)
-parser.add_argument('--cooling', help='Plot found cooling rates', action='store_true')
-
-
-def evaluate(sample: str|Path, empty: str|Path, reference: str|Path,
- ref_points: ReferenceValue = Cyclohexane, show_cooling: bool = False):
-
- sample = DSCReader(sample)
- empty = DSCReader(empty)
- reference = DSCReader(reference)
- print(sample)
-
- if show_cooling:
- fig, ax = plt.subplots()
- print('\n')
- 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')
- ax.set_xlabel('T / K')
- plt.legend()
- plt.show()
-
- return
-
- run_list = []
- if len(sample.heating) > 1:
- run = None
- print('\nMultiple heat rates found:')
- for k, v in sample.heating.items():
- print(' run {}: {} K/min'.format(k, v))
- while run not in sample.heating:
- # choose your own adventure!!!
- value = input('\nPlease select a run (press Enter for all heat rates): ')
- if value == '':
- run_list = list(sample.heating.keys())
- break
- else:
- run = int(value)
- run_list = [run]
- else:
- run_list = list(sample.heating.keys())
-
- for run in run_list:
- rate = sample.heating[run]
-
- print('\nProcessing heat rate {} K/min'.format(rate))
-
- print('Load data of heating data')
- len_sample = sample.length(run)
-
- # sanity checks
- try:
- reference_data = reference.flow_data(rate)
- except IndexError:
- print('ERROR: Reference measurement has no heat rate {} K/min'.format(rate))
- print('Stop evaluation')
- sys.exit()
-
- try:
- run_baseline = empty.get_run(rate)
- except ValueError:
- print('ERROR: Empty measurement has no heat rate {} K/min'.format(rate))
- print('Stop evaluation')
- sys.exit()
-
- len_baseline = empty.length(run_baseline)
- max_length = None
- if len_baseline != len_sample:
- print('WARNING: measurements differ by {} points'.format(abs(len_baseline - len_sample)))
- max_length = min(len_baseline, len_sample)
-
- sample_data = sample.flow_data(rate, length=max_length)
- empty_data = empty.flow_data(rate, length=max_length)
-
- # plot input data
- fig1, ax1 = plt.subplots(2, 3, **{'figsize': (10, 6)})
- ax1[0, 0].set_title('raw data')
- ax1[0, 0].set_xlabel('T / K')
-
- ax1[0, 0].plot(sample_data[0], sample_data[1], 'k-', label='Sample')
- ax1[0, 0].plot(empty_data[0], empty_data[1], 'b-', label='Empty')
- ax1[0, 0].plot(reference_data[0], reference_data[1], 'r-', label='Reference')
- ax1[0, 0].legend()
-
- print('Substract empty data')
- sample_baseline = sample_data.copy()
- sample_baseline[1] = sample_data[1] - empty_data[1]
-
- # plot baseline correction
- ax1[0, 1].set_title('baseline correction')
- ax1[0, 1].set_xlabel('T / K')
-
- ax1[0, 1].plot(sample_data[0], sample_data[1], 'k--', label='Raw')
- ax1[0, 1].plot(sample_baseline[0], sample_baseline[1], 'k-', label='Baseline corrected')
- ax1[0, 1].plot(empty_data[0], empty_data[1], 'b-', label='Empty')
- ax1[0, 1].legend()
-
- print('Load isothermal data around heat rate')
- mean_isotherms = []
- for offset, where, ls in [(-1, 'low', '-'), (1, 'high', '--')]:
- # read isotherms and baseline correct
- len_baseline = empty.length(run_baseline+offset)
- len_sample = sample.length(run+offset)
- if len_baseline != len_sample:
- print('WARNING: {} T isotherms differ by {} points'.format(where, abs(len_baseline-len_sample)))
-
- max_length = min(len_baseline, len_sample)
- isotherm_sample = sample.isotherm_data(run_baseline+offset, length=max_length)
- isotherm_empty = empty.isotherm_data(run+offset, length=max_length)
-
- isotherm_sample[1] -= isotherm_empty[1]
-
- # get mean isotherm value
- m = np.polyfit(isotherm_sample[0, 200:-200], isotherm_sample[1, 200:-200], 0)[0]
- mean_isotherms.append(m)
- print('Calculated {} heat flow: {} mW'.format(where, m))
-
- ax1[0, 2].plot(isotherm_sample[0], isotherm_sample[1], 'k--')
-
- # calculate slope from difference between isotherms
- slope = (mean_isotherms[1]-mean_isotherms[0]) / (sample_data[2, -1] - empty_data[2, 0])
- print('Heat flow slope from isotherms: {} per minute'.format(slope*60))
-
- # calculate mean slope of heat flow at points in the beginning
- slope_baseline = np.gradient(sample_baseline[1, int(4000/rate):int(9000/rate)],
- sample_baseline[2, 300]-sample_baseline[2, 299]).mean()
- print('Heat flow slope from initial heating: {} per minute'.format(slope_baseline*60))
-
- drift_corrected = sample_baseline[1] - mean_isotherms[0] - (sample_baseline[2]-empty_data[2, 0])*slope
- drift_from_slope = sample_baseline[1] - mean_isotherms[0] - (sample_baseline[2]-empty_data[2, 0])*slope_baseline
-
- # plot
- ax1[0, 2].axhline(mean_isotherms[0], linestyle=':')
- ax1[0, 2].axhline(mean_isotherms[1], linestyle=':')
-
- ax1[0, 2].plot(sample_baseline[2], sample_baseline[1], 'k-', label='Baseline corrected')
- ax1[0, 2].plot(sample_baseline[2], drift_corrected, 'g-', label='Corrected (isotherm)')
- ax1[0, 2].plot(sample_baseline[2], drift_from_slope, 'b-', label='Corrected (heating)')
-
- ax1[0, 2].plot(sample_baseline[2], mean_isotherms[0] + (sample_baseline[2]-empty_data[2, 0])*slope, 'g--')
- ax1[0, 2].plot(sample_baseline[2], mean_isotherms[0] + slope_baseline*(sample_baseline[2]-empty_data[2, 0]),
- 'b--')
-
- ax1[0, 2].plot(sample_baseline[2, int(4000/rate):int(9000/rate)],
- sample_baseline[1, int(4000/rate):int(9000/rate)], 'r--')
-
- ax1[0, 2].set_title('time dependence')
- ax1[0, 2].set_xlabel('t / s')
- ax1[0, 2].legend()
-
- melts = []
- for i, (trans_temp, enthalpy) in enumerate(ref_points.transitions):
- print(trans_temp, enthalpy)
-
- # region around reference peaks
- # NOTE: limits are hard coded for cyclohexane, other references need other limits
- low_border = np.argmin(abs(reference_data[0]-(trans_temp-15)))
- high_border = np.argmin(abs(reference_data[0]-(trans_temp+15)))
- ref_zoom = reference_data[:, low_border:high_border]
- x_val = np.array([[ref_zoom[0, 0], 1],
- [ref_zoom[0, -1], 1]])
- y_val = np.array([ref_zoom[1, 0],
- ref_zoom[1, -1]])
- print('Baseline correct reference of {} transition'.format(trans_temp))
- sol = np.linalg.solve(x_val, y_val)
- ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1])
- peak_max = ref_zoom[:, np.argmax(ref_zoom[1])]
- integration_limit = np.argmin(abs(ref_zoom[0]-peak_max[0]+3)), np.argmin(abs(ref_zoom[0]-peak_max[0]-3))
-
- # substract baseline around reference peaks
- x_val = np.array([[ref_zoom[0, integration_limit[0]], 1],
- [ref_zoom[0, integration_limit[1]], 1]])
- y_val = np.array([ref_zoom[1, integration_limit[0]],
- ref_zoom[1, integration_limit[1]]])
-
- print('Baseline correct reference of {} transition'.format(trans_temp))
- sol = np.linalg.solve(x_val, y_val)
- ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1])
-
- # calculate onset slope (use points at position of maximum gradient +/- 100/rate)
- ref_grad = np.gradient(ref_zoom[1])
- max_grad = np.argmax(ref_grad)
-
- x_val = np.array([[ref_zoom[0, max_grad-int(100/rate)], 1],
- [ref_zoom[0, max_grad+int(100/rate)+1], 1]])
- y_val = np.array([ref_zoom[1, max_grad-int(100/rate)],
- ref_zoom[1, max_grad+int(100/rate)+1]])
- sol = np.linalg.solve(x_val, y_val)
- onset = sol[0]*ref_zoom[0] + sol[1]
-
- melts.append(-sol[1]/sol[0])
-
- # plot
- ax1[1, i].set_title('reference: {:.2f} K'.format(trans_temp))
- ax1[1, i].set_xlabel('T / K')
-
- ax1[1, i].plot(reference_data[0], reference_data[1], 'r-')
- ax1[1, i].plot(ref_zoom[0, max_grad], ref_zoom[0, max_grad], 'kx')
- ax1[1, i].plot(ref_zoom[0], onset, 'k--')
- ax1[1, i].axhline(0, color='k', linestyle='--')
-
- ax1[1, i].set_xlim(ref_zoom[0, integration_limit[0]], ref_zoom[0, integration_limit[1]])
- ax1[1, i].set_ylim(-max(ref_zoom[1])/10, max(ref_zoom[1])*1.1)
-
- print('Onset of transition: {:.2f} K, should be at {:.2f}'.format(melts[-1], trans_temp))
- if enthalpy is not None:
- # integrate over low temperature peak to calibrate y axis
- # NOTE: again, this is only valid for cyclohexane
- # delta H in J/g: Integrate Peak over time and divide by weight
- area = 1e-3 * simps(ref_zoom[1, integration_limit[0]:integration_limit[1]],
- ref_zoom[2, integration_limit[0]:integration_limit[1]],
- even='avg')
- calib_y_axis = enthalpy / (area / reference.weight)
- print("Calibration factor of peak: {}".format(calib_y_axis))
-
- sample_baseline[1] *= calib_y_axis
-
- fig1.delaxes(ax1[1, 2])
- fig1.tight_layout()
-
- plt.show()
-
- # give a choice how to compensate for long-time drift
- mode = None
- while mode not in ['i', 'h']:
- mode = input('\nUse [i]sotherms or initial [h]eating for long-time correction? (Default: i) ')
- if mode == '':
- mode = 'i'
-
- if mode == 'h':
- print('\nCorrect slope from initial heating')
- sample_baseline[1] = drift_from_slope
- else:
- print('\nCorrect slope from isotherm')
- sample_baseline[1] = drift_corrected
-
- # calibrate T axis
- print('\nCalibrate temperature')
- real_trans = np.array([ref_points.transition1, ref_points.transition2])
- t_vals = np.array([[melts[0], 1],
- [melts[1], 1]])
- calibration_temp = np.linalg.solve(t_vals, real_trans)
- print('T_real = {:.4f} * T_meas {:+.4f}'.format(*calibration_temp))
-
- sample_baseline[0] = calibration_temp[0] * sample_baseline[0] + calibration_temp[1]
-
- print('Convert to capacity')
- cp = sample_baseline[1] * 60. / rate / sample.weight / 1000.
- if sample.weight is None:
- raise ValueError('No sample weight given')
-
- # plot final results in separate figure
- fig2, ax2 = plt.subplots()
- ax2.set_title('{} K/min: Heat flow vs. heat capacity (close to cont.)'.format(rate))
- ax2.set_xlabel('Temperature / K')
-
- ax2.plot(sample_baseline[0], sample_baseline[1], label='heat flow')
- ax2.plot(sample_baseline[0], cp, label='heat capacity')
-
- plt.legend()
- plt.show()
-
- outname = os.path.splitext(sample.name)[0] + '_' + str(rate) + 'K-min.dat'
- header = 'Made with version: {}\n'.format(__version__)
- header += 'T/K\tCp/J/(gK)\theat flow/mW'
-
- print()
- print('Save to', outname)
- np.savetxt(outname, np.c_[sample_baseline[0], cp, sample_baseline[1]], header=header)
-
-
-if __name__ == '__main__':
- args = parser.parse_args()
- evaluate(args.sample, args.empty, args.reference, show_cooling=args.cooling)
diff --git a/src/nmreval/io/dsc.py b/src/nmreval/io/dsc.py
index 84c024f..be6cff4 100644
--- a/src/nmreval/io/dsc.py
+++ b/src/nmreval/io/dsc.py
@@ -33,7 +33,7 @@ class DSCSample:
self.read_file(fname)
- def read_file(self, fname: str | Path):
+ def read_file(self, fname: str | Path) -> None:
fname = Path(fname)
# file contains weird deg C character in stupiod ISO encoding
@@ -141,7 +141,7 @@ class DSCCalibrator:
def __init__(self):
self.sample = None
self.empty = None
- self.reference =[]
+ self.reference = []
self.ref_list = []
def set_measurement(self,
@@ -207,11 +207,8 @@ class DSCCalibrator:
integ_limit = (np.argmin(np.abs(ref_zoom[0] - peak_max[0] + 3)),
np.argmin(np.abs(ref_zoom[0] - peak_max[0] - 3)))
- # substract baseline around reference peaks
- x_val = np.array([[ref_zoom[0, integ_limit[0]], 1], [ref_zoom[0, integ_limit[1]], 1]])
- y_val = np.array([ref_zoom[1, integ_limit[0]], ref_zoom[1, integ_limit[1]]])
-
- sol = np.linalg.solve(x_val, y_val)
+ # subtract baseline around reference peak
+ sol = self.solve_linear_eq(integ_limit, ref_zoom)
ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1])
# calculate onset slope (use points at position of maximum gradient - 100/rate (+50/rate))
@@ -220,11 +217,7 @@ class DSCCalibrator:
grad_pos = max_grad-int(50 / rate), max_grad
- x_val = np.array([[ref_zoom[0, grad_pos[0]], 1],
- [ref_zoom[0, grad_pos[1]], 1]])
- y_val = np.array([ref_zoom[1, grad_pos[0]],
- ref_zoom[1,grad_pos[1]]])
- sol = np.linalg.solve(x_val, y_val)
+ sol = self.solve_linear_eq(grad_pos, ref_zoom)
onset = sol[0] * ref_zoom[0] + sol[1]
melts.append(-sol[1] / sol[0])
@@ -254,7 +247,15 @@ class DSCCalibrator:
return calib_x, calib_y, results
- def get_data(self, idx, slope='iso'):
+ @staticmethod
+ def solve_linear_eq(limits: tuple, ref_zoom: np.ndarray) -> np.ndarray:
+ x_val = np.array([[ref_zoom[0, limits[0]], 1], [ref_zoom[0, limits[1]], 1]])
+ y_val = np.array([ref_zoom[1, limits[0]], ref_zoom[1, limits[1]]])
+ sol = np.linalg.solve(x_val, y_val)
+
+ return sol
+
+ def get_data(self, idx: int, slope: str = 'iso', limits: tuple[float, float] = None):
if self.sample.steps[idx][0] == 'i':
raise ValueError('baseline correction is not implemented for isotherms')
@@ -304,21 +305,36 @@ class DSCCalibrator:
drift_value = np.c_[drift_value, isotherm_sample]
if slope is not None:
+ offset = sample_data[1, 200]
if slope == 'iso':
# calculate slope from difference between isotherms
m = (mean_isotherms[1] - mean_isotherms[0]) / (sample_data[2, -1] - sample_data[2, 0])
- offset = sample_data[1, 200]
+
else:
# calculate mean slope of heat flow from points in the beginning
- offset = sample_data[1, 200]
- grad = np.gradient(sample_data[1, :], sample_data[2, :])
+ region = None
+ if limits is not None:
+ if len(limits) != 2:
+ raise ValueError(f'limits must be tuple of len 2, not {limits!r}')
+ min_lim, max_lim = min(limits), max(limits)
+ window = (sample_data[2, :] >= min_lim) * (sample_data[2, :] <= max_lim)
+ region = sample_data[1:, window]
+ if region.shape[1] <= 2:
+ # raise ValueError(f'No data inside selected time window {min_lim/60} min and {max_lim/60} min')
+ region = None
+
+ if region is None:
+ # if no limits, use all
+ region = sample_data[1:, :]
+
+ grad = np.gradient(region[0, :], region[1, :])
grad = grad[~np.isnan(grad)]
m = grad[(grad < grad.mean()+grad.std()/5)*(grad > grad.mean()-grad.std()/5)].mean()
sample_data[1] -= m * (sample_data[2] - sample_data[2, 200]) + offset
line = np.array([[sample_data[2, 0], sample_data[2, -1]],
- [m * (sample_data[2, 200] - sample_data[2, 200]) + offset,
+ [m * (sample_data[2, 0] - sample_data[2, 200]) + offset,
m * (sample_data[2, -1] - sample_data[2, 200]) + offset]])
else:
diff --git a/src/resources/_ui/dscfile_dialog.ui b/src/resources/_ui/dscfile_dialog.ui
index 6b7143e..2276ceb 100644
--- a/src/resources/_ui/dscfile_dialog.ui
+++ b/src/resources/_ui/dscfile_dialog.ui
@@ -6,349 +6,445 @@
0
0
- 962
- 662
+ 1341
+ 799
Read DSC file
-
- -
-
+
+
-
+
Qt::Horizontal
-
- QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Save
-
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ Detected steps
+
+
+ false
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+ -
+
+
+ Baseline corrections
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ Empty measurement
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ No emtpy measurement
+
+
+
+ -
+
+
+ 3
+
+
-
+
+
+ Load empty
+
+
+
+ -
+
+
+ Remove empty
+
+
+
+
+
+
+
+
+ -
+
+
+ Slope correction
+
+
+
+ 3
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+ None
+
+
+ buttonGroup
+
+
+
+ -
+
+
+ Isotherms
+
+
+ true
+
+
+ buttonGroup
+
+
+
+ -
+
+
+ Initial slope
+
+
+ buttonGroup
+
+
+
+ -
+
+
+
+ 0
+ 33
+
+
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
+ 3
+
+
-
+
+
+ start (in min)
+
+
+
+ -
+
+
+
+
+
+ stop (in min)
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ References
+
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Use reference to convert to heat capacity
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ QAbstractItemView::SingleSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+ 2
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+
+
+ -
+
+
+ 3
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Add reference
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Remove reference
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Save
+
+
+ true
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 300
+ 200
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 300
+ 200
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 300
+ 200
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
- -
-
-
- 0
-
-
- 0
-
-
- 3
-
-
-
-
-
-
- 0
- 0
-
-
-
- Convert to heat capacity
-
-
- true
-
-
-
- -
-
-
- 3
-
-
-
-
-
- Load empty
-
-
-
- -
-
-
- Remove empty
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- Isotherms
-
-
- true
-
-
- buttonGroup
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- font-weight: bold
-
-
- Detected steps
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
- QAbstractItemView::SingleSelection
-
-
- QAbstractItemView::SelectRows
-
-
- 2
-
-
- false
-
-
- true
-
-
- false
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
- Slope
-
-
-
- -
-
-
- Initial slope
-
-
- buttonGroup
-
-
-
- -
-
-
- Empty measurement
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- font-weight: bold
-
-
- Calibration
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- font-weight: bold
-
-
- Baseline
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- None
-
-
- buttonGroup
-
-
-
- -
-
-
- 3
-
-
-
-
-
-
- 0
- 0
-
-
-
- Add reference
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Remove reference
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 300
- 200
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 300
- 200
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 300
- 200
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
-
-
-