1
0
forked from IPKM/nmreval

fixed problem with setting color from context menu

This commit is contained in:
Dominik Demuth 2023-05-18 18:51:02 +02:00
parent bc215ce32b
commit fcaf43b3eb
13 changed files with 167 additions and 40733 deletions

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'src/resources/_ui/basewindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
# Created by: PyQt5 UI code generator 5.15.9
#
# 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.
@ -64,6 +64,9 @@ class Ui_BaseWindow(object):
icon5 = QtGui.QIcon()
icon5.addPixmap(QtGui.QPixmap(":/eval_t1_dock"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.tabWidget.addTab(self.t1tauwidget, icon5, "")
self.drawingswidget = DrawingsWidget()
self.drawingswidget.setObjectName("drawingswidget")
self.tabWidget.addTab(self.drawingswidget, "")
self.integralwidget = IntegralWidget()
self.integralwidget.setObjectName("integralwidget")
self.tabWidget.addTab(self.integralwidget, "")
@ -72,7 +75,7 @@ class Ui_BaseWindow(object):
self.horizontalLayout.addWidget(self.splitter)
BaseWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(BaseWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1386, 22))
self.menubar.setGeometry(QtCore.QRect(0, 0, 1386, 20))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
@ -114,6 +117,8 @@ class Ui_BaseWindow(object):
self.menuStuff = QtWidgets.QMenu(self.menubar)
self.menuStuff.setTitle("")
self.menuStuff.setObjectName("menuStuff")
self.menuDSC = QtWidgets.QMenu(self.menubar)
self.menuDSC.setObjectName("menuDSC")
BaseWindow.setMenuBar(self.menubar)
self.toolBar = QtWidgets.QToolBar(BaseWindow)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
@ -353,6 +358,8 @@ class Ui_BaseWindow(object):
self.actionUpdate.setObjectName("actionUpdate")
self.actionMine = QtWidgets.QAction(BaseWindow)
self.actionMine.setObjectName("actionMine")
self.action_draw_object = QtWidgets.QAction(BaseWindow)
self.action_draw_object.setObjectName("action_draw_object")
self.actionBugs = QtWidgets.QAction(BaseWindow)
self.actionBugs.setObjectName("actionBugs")
self.actionShow_error_log = QtWidgets.QAction(BaseWindow)
@ -361,6 +368,8 @@ class Ui_BaseWindow(object):
self.actionCreate_starter.setObjectName("actionCreate_starter")
self.actionAbout = QtWidgets.QAction(BaseWindow)
self.actionAbout.setObjectName("actionAbout")
self.actionTNMH_model = QtWidgets.QAction(BaseWindow)
self.actionTNMH_model.setObjectName("actionTNMH_model")
self.menuSave.addAction(self.actionSave)
self.menuSave.addAction(self.actionExportGraphic)
self.menuSave.addAction(self.action_save_fit_parameter)
@ -441,6 +450,7 @@ class Ui_BaseWindow(object):
self.menuWindow.addSeparator()
self.menuWindow.addAction(self.actionRefresh)
self.menuWindow.addSeparator()
self.menuWindow.addAction(self.action_draw_object)
self.menuNMR.addAction(self.t1action)
self.menuNMR.addAction(self.actionCalculateT1)
self.menuNMR.addAction(self.action_coup_calc)
@ -456,6 +466,7 @@ class Ui_BaseWindow(object):
self.menuStuff.addAction(self.actionLife)
self.menuStuff.addAction(self.actionTetris)
self.menuStuff.addAction(self.actionMine)
self.menuDSC.addAction(self.actionTNMH_model)
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menuWindow.menuAction())
self.menubar.addAction(self.menuData.menuAction())
@ -464,6 +475,7 @@ class Ui_BaseWindow(object):
self.menubar.addAction(self.menuFit.menuAction())
self.menubar.addAction(self.menuNMR.menuAction())
self.menubar.addAction(self.menuBDS.menuAction())
self.menubar.addAction(self.menuDSC.menuAction())
self.menubar.addAction(self.menuOptions.menuAction())
self.menubar.addAction(self.menuHelp.menuAction())
self.menubar.addAction(self.menuStuff.menuAction())
@ -487,7 +499,7 @@ class Ui_BaseWindow(object):
self.retranslateUi(BaseWindow)
self.tabWidget.setCurrentIndex(0)
self.action_close.triggered.connect(BaseWindow.close)
self.action_close.triggered.connect(BaseWindow.close) # type: ignore
QtCore.QMetaObject.connectSlotsByName(BaseWindow)
def retranslateUi(self, BaseWindow):
@ -499,6 +511,7 @@ class Ui_BaseWindow(object):
self.tabWidget.setTabText(self.tabWidget.indexOf(self.editsignalwidget), _translate("BaseWindow", "Signals"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.ptsselectwidget), _translate("BaseWindow", "Pick points"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.t1tauwidget), _translate("BaseWindow", "SLR"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.drawingswidget), _translate("BaseWindow", "Drawings"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.integralwidget), _translate("BaseWindow", "Integrate"))
self.menuFile.setTitle(_translate("BaseWindow", "&File"))
self.menuSave.setTitle(_translate("BaseWindow", "&Save..."))
@ -515,6 +528,7 @@ class Ui_BaseWindow(object):
self.menuNMR.setTitle(_translate("BaseWindow", "NMR"))
self.menuBDS.setTitle(_translate("BaseWindow", "BDS"))
self.menuSpectrum.setTitle(_translate("BaseWindow", "Spectrum"))
self.menuDSC.setTitle(_translate("BaseWindow", "DSC"))
self.toolBar.setWindowTitle(_translate("BaseWindow", "Main"))
self.toolbar_edit.setWindowTitle(_translate("BaseWindow", "Math"))
self.toolBar_nmr.setWindowTitle(_translate("BaseWindow", "NMR"))
@ -567,6 +581,7 @@ class Ui_BaseWindow(object):
self.actionFit_parameter_saving.setText(_translate("BaseWindow", "Fit parameter saving..."))
self.actionShow_fit_parameter.setText(_translate("BaseWindow", "Parameter..."))
self.actionSkip_points.setText(_translate("BaseWindow", "Skip points..."))
self.actionGuide_lines.setText(_translate("BaseWindow", "Draw lines..."))
self.actionMaximize.setText(_translate("BaseWindow", "Maximize"))
self.actionTile.setText(_translate("BaseWindow", "Tile windows"))
self.actionTileVertical.setText(_translate("BaseWindow", "Tile windows vertically"))
@ -614,15 +629,18 @@ class Ui_BaseWindow(object):
self.actionTetris.setText(_translate("BaseWindow", "Not Tetris"))
self.actionUpdate.setText(_translate("BaseWindow", "Look for updates"))
self.actionMine.setText(_translate("BaseWindow", "Mine"))
self.action_draw_object.setText(_translate("BaseWindow", "Draw objects..."))
self.actionBugs.setText(_translate("BaseWindow", "Bugs! Problems! Wishes!"))
self.actionShow_error_log.setText(_translate("BaseWindow", "Show error log"))
self.actionCreate_starter.setText(_translate("BaseWindow", "Create starter.."))
self.actionAbout.setText(_translate("BaseWindow", "About..."))
self.actionTNMH_model.setText(_translate("BaseWindow", "TNMH model..."))
from ..data.datawidget.datawidget import DataWidget
from ..data.integral_widget import IntegralWidget
from ..data.point_select import PointSelectWidget
from ..data.signaledit.editsignalwidget import EditSignalWidget
from ..data.valueeditwidget import ValueEditWidget
from ..fit.fitwindow import QFitDialog
from ..graphs.drawings import DrawingsWidget
from ..lib.mdiarea import MdiAreaTile
from ..nmr.t1widget import QT1Widget

View File

@ -12,6 +12,7 @@ from ..lib import get_icon
from .._py.fitfunctionwidget import Ui_Form
from ..Qt import QtWidgets, QtCore, QtGui
class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
func_cnt = count()
func_colors = cycle(Tab10)

View File

@ -5,7 +5,7 @@ from pathlib import Path
import numpy as np
from pyqtgraph import PlotDataItem
from nmreval.data.points import Points
from nmreval.data import DSC
from nmreval.io.dsc import Cyclohexane, DSCCalibrator, DSCSample
from ..Qt import QtWidgets, QtCore
@ -250,7 +250,7 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
return
rate, mode = self.current_run
new_val = Points(sample_data[0], sample_data[1], value=rate, name=f'{self.fname.stem} {rate} ({mode})')
new_val = DSC(sample_data[0], sample_data[1], value=rate, name=f'{self.fname.stem} {rate} ({mode})')
if filesave:
new_val.savetxt(self.fname.with_name(f'{self.fname.stem} {rate}K-min {mode}.dat'.replace(' ', '_')))

View File

@ -1078,3 +1078,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
def show_version(self):
from nmreval.version import __version__
QtWidgets.QMessageBox.about(self, 'Version', f'Build date of AppImage: {__version__}')
@QtCore.pyqtSlot(name='on_actionTNMH_model_triggered')
def calculate_tnmh(self):
print('tnmh')

View File

@ -1,6 +1,84 @@
from __future__ import annotations
from typing import Optional
import numpy as np
from scipy.optimize import fsolve
try:
from scipy.integrate import cumulative_trapezoid
except ImportError:
from scipy.integrate import cumtrapz as cumulative_trapezoid
from scipy.stats import linregress
from .points import Points
from ..dsc.tnmh_model import TNMH
class DSC(Points):
def __init__(self, x, y, **kwargs):
super().__init__(x, y, **kwargs)
x, unique = np.unique(x, return_index=True)
super().__init__(x, y[unique], **kwargs)
self.meta['is_fictive'] = False
def get_fictive_cp(self, glass: tuple[float, float], liquid: tuple[float, float]) -> ('DSC', float):
min_glass, max_glass = min(glass), max(glass)
min_liquid, max_liquid = min(liquid), max(liquid)
region = self.copy()
region.cut(min_glass, max_liquid)
glass_regime = (min_glass < region.x) & (region.x < max_glass)
regress = linregress(region.x[glass_regime], region.y[glass_regime])
glass_extrapolation = regress.slope * region.x + regress.intercept
region.y -= glass_extrapolation
liquid_regime = (min_liquid < region.x) & (region.x < max_liquid)
regress2 = linregress(region.x[liquid_regime], region.y[liquid_regime])
real_area = cumulative_trapezoid(region.y, region.x, initial=0)
real_area -= real_area[-1]
t = regress2.intercept-regress.intercept
m = regress2.slope-regress.slope
c0 = 0.5*m*region.x.max()**2 + t*region.x.max()
def equiv(_x, _i):
return (0.5*m * _x**2 + t*_x - c0) - real_area[_i]
def equiv_prime(_x, _i):
return m * _x + t
fictive_temperature = np.array([fsolve(equiv, region.x[i], fprime=equiv_prime, args=(i,))[0] for i in range(len(region.x))])
t_g_fictive = fictive_temperature[:20].mean()
region.y = np.gradient(fictive_temperature, region.x)
return region, t_g_fictive
def calculate_tnmh(self, p0: list, glass: tuple[float, float], liquid: tuple[float, float],
tg: float = None, num_points: int = 200, return_fictive: bool = True) -> ('FitResult', Optional[float], Optional[DSC]):
dtf_dt, fictive_tg = self.get_fictive_cp(glass, liquid)
if tg is None:
tg = fictive_tg
temp_equidist = np.linspace(dtf_dt.x[0], dtf_dt.x[-1], num_points)
dtf_dt_equidist = np.interp(temp_equidist, dtf_dt.x, dtf_dt.y)
from ..fit.minimizer import FitRoutine
fitter = FitRoutine()
fitter.set_model(TNMH)
data = fitter.add_data(temp_equidist, dtf_dt_equidist)
data.set_parameter(p0 + [tg, self.value], var=[True]*4 + [False]*2, default_bounds=True)
res = fitter.run()[0]
if return_fictive:
return res, tg, dtf_dt
else:
return res

File diff suppressed because it is too large Load Diff

View File

@ -1,202 +0,0 @@
# tau_TNMH=77.93669386254352 beta=0.6334823578561849 x=0.4107577725462226 deltaE=205554.80338165778
# Temp dTfdT_data dTfdT_fit
1.50007e+02 -1.54659e-03 5.04753e-03
1.50258e+02 -1.35164e-03 -5.81695e-03
1.50509e+02 -1.15321e-03 -5.24594e-03
1.50760e+02 1.33378e-03 -5.19023e-03
1.51011e+02 -4.19078e-03 -5.23034e-03
1.51262e+02 -3.69741e-03 -5.32106e-03
1.51514e+02 -1.17892e-03 -5.44569e-03
1.51765e+02 -4.26847e-04 -5.59617e-03
1.52016e+02 1.34823e-03 -5.76806e-03
1.52267e+02 -8.53837e-04 -5.95864e-03
1.52518e+02 -3.32957e-03 -6.16618e-03
1.52769e+02 -3.18265e-03 -6.38951e-03
1.53021e+02 -9.27941e-04 -6.62778e-03
1.53272e+02 2.81209e-03 -6.88034e-03
1.53523e+02 2.53703e-03 -7.14668e-03
1.53774e+02 2.79565e-03 -7.42632e-03
1.54025e+02 3.73709e-03 -7.71879e-03
1.54277e+02 -4.74193e-04 -8.02362e-03
1.54528e+02 5.53513e-03 -8.34027e-03
1.54779e+02 5.40911e-03 -8.66813e-03
1.55030e+02 4.61145e-03 -9.00648e-03
1.55281e+02 3.12182e-03 -9.35449e-03
1.55532e+02 6.75992e-03 -9.71118e-03
1.55784e+02 3.14577e-03 -1.00754e-02
1.56035e+02 2.59412e-03 -1.04458e-02
1.56286e+02 -1.54718e-03 -1.08208e-02
1.56537e+02 1.17037e-04 -1.11987e-02
1.56788e+02 -2.03614e-03 -1.15774e-02
1.57039e+02 1.33113e-03 -1.19545e-02
1.57291e+02 -5.96949e-03 -1.23274e-02
1.57542e+02 -6.48426e-03 -1.26931e-02
1.57793e+02 -1.59997e-03 -1.30481e-02
1.58044e+02 -3.72898e-04 -1.33886e-02
1.58295e+02 1.30990e-03 -1.37104e-02
1.58547e+02 4.08780e-03 -1.40088e-02
1.58798e+02 -7.05642e-03 -1.42784e-02
1.59049e+02 -2.00584e-03 -1.45134e-02
1.59300e+02 -1.92937e-03 -1.47073e-02
1.59551e+02 -6.58517e-04 -1.48531e-02
1.59802e+02 7.32033e-04 -1.49429e-02
1.60054e+02 2.36722e-03 -1.49682e-02
1.60305e+02 -1.17443e-03 -1.49196e-02
1.60556e+02 4.59116e-04 -1.47868e-02
1.60807e+02 8.17255e-03 -1.45588e-02
1.61058e+02 8.48647e-03 -1.42234e-02
1.61310e+02 7.96560e-03 -1.37674e-02
1.61561e+02 1.29202e-02 -1.31766e-02
1.61812e+02 4.84645e-03 -1.24355e-02
1.62063e+02 1.24679e-02 -1.15274e-02
1.62314e+02 1.08789e-02 -1.04342e-02
1.62565e+02 9.31453e-03 -9.13630e-03
1.62817e+02 1.10428e-02 -7.61265e-03
1.63068e+02 1.81300e-02 -5.84047e-03
1.63319e+02 9.70774e-03 -3.79521e-03
1.63570e+02 1.20566e-02 -1.45035e-03
1.63821e+02 1.49584e-02 1.22268e-03
1.64072e+02 1.72350e-02 4.25478e-03
1.64324e+02 2.03471e-02 7.67928e-03
1.64575e+02 3.74633e-02 1.15322e-02
1.64826e+02 2.20722e-02 1.58527e-02
1.65077e+02 2.90447e-02 2.06828e-02
1.65328e+02 3.56891e-02 2.60686e-02
1.65580e+02 4.02175e-02 3.20598e-02
1.65831e+02 4.99873e-02 3.87108e-02
1.66082e+02 6.52373e-02 4.60809e-02
1.66333e+02 5.16469e-02 5.42346e-02
1.66584e+02 6.50874e-02 6.32432e-02
1.66835e+02 7.59582e-02 7.31846e-02
1.67087e+02 8.82617e-02 8.41446e-02
1.67338e+02 9.75569e-02 9.62183e-02
1.67589e+02 1.08193e-01 1.09511e-01
1.67840e+02 1.09727e-01 1.24138e-01
1.68091e+02 1.30829e-01 1.40230e-01
1.68342e+02 1.55907e-01 1.57932e-01
1.68594e+02 1.71526e-01 1.77404e-01
1.68845e+02 1.87568e-01 1.98829e-01
1.69096e+02 2.05094e-01 2.22407e-01
1.69347e+02 2.27806e-01 2.48367e-01
1.69598e+02 2.58337e-01 2.76962e-01
1.69850e+02 2.88510e-01 3.08478e-01
1.70101e+02 3.20528e-01 3.43232e-01
1.70352e+02 3.57173e-01 3.81577e-01
1.70603e+02 4.02201e-01 4.23903e-01
1.70854e+02 4.47497e-01 4.70630e-01
1.71105e+02 5.06370e-01 5.22210e-01
1.71357e+02 5.66666e-01 5.79104e-01
1.71608e+02 6.33707e-01 6.41763e-01
1.71859e+02 7.08395e-01 7.10580e-01
1.72110e+02 7.86941e-01 7.85817e-01
1.72361e+02 8.80202e-01 8.67486e-01
1.72612e+02 9.72949e-01 9.55178e-01
1.72864e+02 1.07283e+00 1.04780e+00
1.73115e+02 1.17098e+00 1.14323e+00
1.73366e+02 1.26581e+00 1.23794e+00
1.73617e+02 1.36284e+00 1.32657e+00
1.73868e+02 1.40164e+00 1.40186e+00
1.74120e+02 1.45067e+00 1.45520e+00
1.74371e+02 1.46476e+00 1.47830e+00
1.74622e+02 1.44706e+00 1.46612e+00
1.74873e+02 1.40520e+00 1.42006e+00
1.75124e+02 1.35811e+00 1.34934e+00
1.75375e+02 1.26322e+00 1.26857e+00
1.75627e+02 1.20703e+00 1.19227e+00
1.75878e+02 1.15871e+00 1.12985e+00
1.76129e+02 1.12062e+00 1.08413e+00
1.76380e+02 1.09118e+00 1.05315e+00
1.76631e+02 1.07111e+00 1.03314e+00
1.76882e+02 1.05191e+00 1.02044e+00
1.77134e+02 1.04878e+00 1.01241e+00
1.77385e+02 1.04027e+00 1.00731e+00
1.77636e+02 1.03275e+00 1.00413e+00
1.77887e+02 1.02782e+00 1.00219e+00
1.78138e+02 1.02566e+00 1.00108e+00
1.78390e+02 1.02147e+00 1.00049e+00
1.78641e+02 1.01938e+00 1.00020e+00
1.78892e+02 1.02000e+00 1.00007e+00
1.79143e+02 1.01835e+00 1.00002e+00
1.79394e+02 1.01657e+00 1.00001e+00
1.79645e+02 1.01941e+00 1.00000e+00
1.79897e+02 1.00523e+00 1.00000e+00
1.80148e+02 1.00689e+00 1.00000e+00
1.80399e+02 1.00730e+00 1.00000e+00
1.80650e+02 1.00768e+00 1.00000e+00
1.80901e+02 1.00746e+00 1.00000e+00
1.81152e+02 1.00606e+00 1.00000e+00
1.81404e+02 1.00202e+00 1.00000e+00
1.81655e+02 9.93205e-01 1.00000e+00
1.81906e+02 9.98851e-01 1.00000e+00
1.82157e+02 1.00478e+00 1.00000e+00
1.82408e+02 1.00147e+00 1.00000e+00
1.82660e+02 1.00747e+00 1.00000e+00
1.82911e+02 9.83522e-01 1.00000e+00
1.83162e+02 9.90690e-01 1.00000e+00
1.83413e+02 9.94175e-01 1.00000e+00
1.83664e+02 9.95883e-01 1.00000e+00
1.83915e+02 9.92199e-01 1.00000e+00
1.84167e+02 9.90755e-01 1.00000e+00
1.84418e+02 9.86480e-01 1.00000e+00
1.84669e+02 9.93964e-01 1.00000e+00
1.84920e+02 9.94745e-01 1.00000e+00
1.85171e+02 9.95895e-01 1.00000e+00
1.85422e+02 9.97575e-01 1.00000e+00
1.85674e+02 9.99326e-01 1.00000e+00
1.85925e+02 9.97579e-01 1.00000e+00
1.86176e+02 1.00187e+00 1.00000e+00
1.86427e+02 9.99647e-01 1.00000e+00
1.86678e+02 1.00026e+00 1.00000e+00
1.86930e+02 1.00307e+00 1.00000e+00
1.87181e+02 1.01192e+00 1.00000e+00
1.87432e+02 9.96247e-01 1.00000e+00
1.87683e+02 9.98530e-01 1.00000e+00
1.87934e+02 1.00165e+00 1.00000e+00
1.88185e+02 1.00562e+00 1.00000e+00
1.88437e+02 1.01337e+00 1.00000e+00
1.88688e+02 1.01309e+00 1.00000e+00
1.88939e+02 9.95564e-01 1.00000e+00
1.89190e+02 1.00160e+00 1.00000e+00
1.89441e+02 1.00596e+00 1.00000e+00
1.89692e+02 1.01222e+00 1.00000e+00
1.89944e+02 1.00825e+00 1.00000e+00
1.90195e+02 1.00603e+00 1.00000e+00
1.90446e+02 1.00770e+00 1.00000e+00
1.90697e+02 9.89746e-01 1.00000e+00
1.90948e+02 1.00511e+00 1.00000e+00
1.91200e+02 1.00621e+00 1.00000e+00
1.91451e+02 1.00143e+00 1.00000e+00
1.91702e+02 1.00224e+00 1.00000e+00
1.91953e+02 1.03274e+00 1.00000e+00
1.92204e+02 9.87474e-01 1.00000e+00
1.92455e+02 9.93631e-01 1.00000e+00
1.92707e+02 9.96782e-01 1.00000e+00
1.92958e+02 9.99014e-01 1.00000e+00
1.93209e+02 1.00251e+00 1.00000e+00
1.93460e+02 1.01135e+00 1.00000e+00
1.93711e+02 9.92486e-01 1.00000e+00
1.93962e+02 9.94748e-01 1.00000e+00
1.94214e+02 9.96729e-01 1.00000e+00
1.94465e+02 9.99500e-01 1.00000e+00
1.94716e+02 1.00314e+00 1.00000e+00
1.94967e+02 1.00767e+00 1.00000e+00
1.95218e+02 9.92280e-01 1.00000e+00
1.95470e+02 9.93172e-01 1.00000e+00
1.95721e+02 9.99065e-01 1.00000e+00
1.95972e+02 1.00089e+00 1.00000e+00
1.96223e+02 1.00147e+00 1.00000e+00
1.96474e+02 1.00277e+00 1.00000e+00
1.96725e+02 9.93517e-01 1.00000e+00
1.96977e+02 9.89833e-01 1.00000e+00
1.97228e+02 1.00075e+00 1.00000e+00
1.97479e+02 1.00224e+00 1.00000e+00
1.97730e+02 9.97354e-01 1.00000e+00
1.97981e+02 9.96498e-01 1.00000e+00
1.98232e+02 1.01632e+00 1.00000e+00
1.98484e+02 9.86819e-01 1.00000e+00
1.98735e+02 1.00374e+00 1.00000e+00
1.98986e+02 1.00217e+00 1.00000e+00
1.99237e+02 1.00089e+00 1.00000e+00
1.99488e+02 1.00215e+00 1.00000e+00
1.99740e+02 1.01197e+00 1.00000e+00
1.99991e+02 9.92503e-01 1.00000e+00

View File

@ -1,7 +0,0 @@
#Heating Rate tau_TNMH beta x deltaE Tg fictive
1.0000e+01 9.0613e+01 6.2053e-01 3.9548e-01 2.0820e+05 1.6911e+02
#Heating Rate tau_TNMH beta x deltaE Tg fictive
1.0000e+01 3.5330e+01 6.7660e-01 5.2984e-01 1.7362e+05 1.6934e+02
#Heating Rate tau_TNMH beta x deltaE Tg fictive
1.0000e+01 7.7937e+01 6.3348e-01 4.1076e-01 2.0555e+05 1.6925e+02

View File

@ -1,132 +0,0 @@
import sys
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import cumulative_trapezoid
from scipy.optimize import curve_fit, fsolve
from scipy.stats import linregress
from nmreval.data import Points
# Read data
dataName = sys.argv[1]
try:
data = np.loadtxt(dataName, skiprows=0).T
temp = data[0]
heat_capacity = data[1]
except IndexError:
exit()
print(np.round(temp, decimals=3)[:30])
def get_fictive_temperature(pts: Points, glass: tuple[float, float], liquid: tuple[float, float]):
min_glass, max_glass = min(glass), max(glass)
min_liquid, max_liquid = min(liquid), max(liquid)
region = pts.copy()
region.cut(min_glass, max_liquid)
glass_regime = (min_glass < region.x) & (region.x < max_glass)
regress = linregress(region.x[glass_regime], region.y[glass_regime])
glass_extrapolation = regress.slope * region.x + regress.intercept
region.y -= glass_extrapolation
liquid_regime = (min_liquid < region.x) & (region.x < max_liquid)
regress2 = linregress(region.x[liquid_regime], region.y[liquid_regime])
liquid_extrapolation = regress2.slope * region.x + regress2.intercept
real_area = -cumulative_trapezoid(region.y, region.x, initial=0)
real_area -= real_area[-1]
equivalent_area = cumulative_trapezoid(liquid_extrapolation, region.x, initial=0)
equivalent_area -= equivalent_area[-1]
equivalent_area *= -1
return region.x, np.round(region.x[np.argmin(np.abs(real_area[:, None] - equivalent_area[None, :]), axis=1)], decimals=4)
curve = Points(x=temp, y=heat_capacity, name=dataName)
# plt.plot(curve.x, curve.y)
# plt.show()
# First step: Calculate fictive Temperature T_f(T) from Cp data, then dT_f/dT
temperatures, fictiveTemp = get_fictive_temperature(curve, glass=(150, 160), liquid=(190, 200))
# Determine limiting T_f, i.e. T_f at lowest temperature
initial_Tf = np.mean(fictiveTemp[:20])
rate = curve.value
# Calculate dTf/dT
# with np.errstate(all='ignore'):
# dTfdT = np.diff(fictiveTemp)/np.diff(temperatures) # np.gradient(fictiveTemp, temperatures)
# nan_filter = ~np.isnan(dTfdT)
# temperatures = 0.5 * (temperatures[:-1] + temperatures[1:])[nan_filter]
# # fictiveTemp = fictiveTemp[nan_filter]
# dTfdT = dTfdT[nan_filter]
print(fictiveTemp[:30])
R = 8.314
def tnm_function(temperature, tau_g, x, beta, energy, tg):
step = len(temperature)
Tf = np.empty(step)
Tf[0] = temperature[0]
delT = np.diff(temperature)
delt = np.abs(delT) * 60 / rate
tau = np.empty(step)
dttau = np.zeros(step)
temp_0 = temperature[0]
for i in range(0, step-1):
tau[i] = relax(temperature[i+1], Tf[i], tau_g, tg, energy, x)
dttau[:i] += delt[i] / tau[i]
Tf[i+1] = np.sum(delT[:i] * (1-np.exp(-dttau[:i]**beta))) + temp_0
return Tf
def relax(t, tf, tau_g, t_glass, ea, x):
h = ea/R
return tau_g * np.exp((x*h / t) + ((1 - x) * h / tf) - h / t_glass)
# Use T_g = T_fictive for tau determination
T_g = initial_Tf
# Start values
p0 = [10, 0.5, 0.4, 225085]
def tnmh_fit(tg):
def wrap(x, tau_0, xx, beta, energy):
modelTemp = np.r_[x[::-1], x[1:]]
TNMH = tnm_function(modelTemp, tau_0, xx, beta, energy, tg)
res = np.gradient(TNMH, modelTemp)
return res[len(x)-1:]
return wrap
# Use only every 20th data point to reduce fitting time
temperaturesInterpol = np.linspace(temperatures[0], temperatures[-1], 200)
dTfdTInterpol = np.interp(temperaturesInterpol, temperatures, dTfdT)
res = curve_fit(tnmh_fit(T_g), temperaturesInterpol, dTfdTInterpol, p0)
plt.plot(temperatures, dTfdT, label='dTf/dT')
plt.plot(temperaturesInterpol, tnmh_fit(T_g)(temperaturesInterpol, *res[0]), label='fit')
plt.legend()
plt.show()

View File

@ -1,317 +0,0 @@
# Tool-Naranayaswami-Moynihan-Hodge model
# by Florian Pabst 2020
import time
import re
import os
import sys
import numpy as np
import matplotlib.pyplot as plt
import scipy.odr as odr
from scipy.integrate import quad
from scipy.optimize import curve_fit, fsolve
# Read data
dataName = sys.argv[1]
try:
data = np.loadtxt(dataName,skiprows=0)
print("Loading")
dataTemp = data[:, 0]
dataCp = data[:, 1]
except IndexError:
print("File not found")
exit()
dataOutName = os.path.splitext(str(dataName))[0] + "_Tfict+TNMH.dat"
# First step: Calculate fictive Temperature T_f(T) from Cp data, then dT_f/dT
# Find start and end point for glass Cp linear fit
coordsGl = [(150, -0.126), (160, -0.09)]
"""
print("Please click on the left limit for glass Cp linear fit")
fig, (ax1) = P.subplots(1)
ax1.set_xlabel('Temperature / K')
ax1.set_xlim(left=140)
ax1.set_xlim(right=200)
ax1.plot(dataTemp,dataCp, 'ro')
#ax1.legend()
def onclick(event):
ix = event.xdata
iy = event.ydata
print(ix)
global coordsGl
coordsGl.append((ix, iy))
if len(coordsGl) == 1:
print('right limit')
if len(coordsGl) == 2:
fig.canvas.mpl_disconnect(cid)
return coordsGl
cid = fig.canvas.mpl_connect('button_press_event', onclick)
P.show()
"""
print(coordsGl)
for i in range(0,len(dataTemp)):
if dataTemp[i] < coordsGl[0][0]:
fitLimitLeft_Gl = i
if dataTemp[i] < coordsGl[1][0]:
fitLimitRight_Gl = i
# Find start and end point for liquid Cp linear fit
coordsLq = [(190, 2.07), (200, 1.773)]
"""
print("Please click on the left limit for liquid Cp linear fit")
fig, (ax1) = P.subplots(1)
ax1.set_xlabel('Temperature / K')
ax1.set_xlim(left=180)
ax1.set_xlim(right=250)
ax1.plot(dataTemp,dataCp, 'ro')
#ax1.legend()
def onclick(event):
ix = event.xdata
iy = event.ydata
print(ix)
global coordsLq
coordsLq.append((ix, iy))
if len(coordsLq) == 1:
print('right limit')
if len(coordsLq) == 2:
fig.canvas.mpl_disconnect(cid)
return coordsLq
cid = fig.canvas.mpl_connect('button_press_event', onclick)
P.show()
#print(coordsLq)
"""
for i in range(0, len(dataTemp)):
if dataTemp[i] < coordsLq[0][0]:
fitLimitLeft_Lq = i
if dataTemp[i] < coordsLq[1][0]:
fitLimitRight_Lq = i
def slope(x, t, m):
return t+x*m
# Determine glass Cp slope
res = curve_fit(slope, dataTemp[fitLimitLeft_Gl:fitLimitRight_Gl], dataCp[fitLimitLeft_Gl:fitLimitRight_Gl])
glassCpParam = res[0]
# Determine liquid Cp slope
res = curve_fit(slope, dataTemp[fitLimitLeft_Lq:fitLimitRight_Lq], dataCp[fitLimitLeft_Lq:fitLimitRight_Lq])
liquidCpParam = res[0]
xLin = np.linspace(coordsGl[0][0], coordsLq[1][0], len(dataTemp))
CpInterpol = np.interp(xLin, dataTemp, dataCp)
"""
fig, (ax1) = P.subplots(1)
ax1.set_xlabel('Temperature / K')
ax1.set_xlim(left=coordsGl[0][0])
ax1.set_xlim(right=coordsLq[1][0])
ax1.set_ylim(bottom=coordsGl[0][1]-0.1)
ax1.set_ylim(top=coordsLq[1][1]+0.1)
ax1.plot(dataTemp,dataCp, 'ro')
ax1.plot(dataTemp,slope(dataTemp,glassCpParam[0],glassCpParam[1]), 'b-')
ax1.plot(dataTemp,slope(dataTemp,liquidCpParam[0],liquidCpParam[1]), 'b-')
ax1.plot(xLin,CpInterpol, 'g-')
P.show()
"""
# Calculate Fictive Temperature for all temperatures in range
intStart = fitLimitLeft_Gl
intStop = fitLimitRight_Lq
fictiveTemp = []
temperatures = []
for i, tempStart in enumerate(dataTemp):
if fitLimitLeft_Gl < i < fitLimitRight_Lq:
intStart = i
integration2 = np.trapz((dataCp[intStart:intStop]-slope(dataTemp[intStart:intStop], glassCpParam[0], glassCpParam[1])), dataTemp[intStart:intStop])
def integrand1(temp):
return slope(temp, liquidCpParam[0], liquidCpParam[1])-slope(temp, glassCpParam[0], glassCpParam[1])
def fictiveTempEq(x):
return quad(integrand1, x, coordsLq[1][0])[0] - integration2
ficTemp = fsolve(fictiveTempEq, np.array([160]))
fictiveTemp.append(ficTemp[0])
temperatures.append(tempStart)
# Determine limiting T_f, i.e. T_f at lowest temperatures
def constant(x, t):
return t
res = curve_fit(constant, temperatures[0:20], fictiveTemp[0:20])
T_f_0 = res[0]
print(T_f_0[0])
# Calculate dTf/dT
dTfdT = []
temperaturesCut = []
for i in range(len(temperatures)-1):
if (temperatures[i+1]-temperatures[i]) != 0:
dTfdT.append((fictiveTemp[i+1]-fictiveTemp[i]) / (temperatures[i+1]-temperatures[i]))
temperaturesCut.append(temperatures[i+1])
print(fictiveTemp[:30])
fig, ax1 = plt.subplots(1)
ax1.set_xlabel('Temperature / K')
ax1.set_ylabel('Fictive Temperature / K')
# ax1.plot(temperatures, fictiveTemp, 'ro')
ax1.plot(temperaturesCut, dTfdT)
# ax1.axhline(y=T_f_0[0], color='b', linestyle='-')
plt.show()
# Second step: Calcualte and Fit TNMH-model
try:
rate = float(str((re.findall(r'\d+\.\d+K', dataName))[0])[:-1])
print("\tRate: %fK-min" % rate)
except IndexError:
rate = int(input("\tPlease enter the heating rate: "))
print("\tRate: %fK-min" %rate)
def tau_k(tau_0, deltaE, T_k, xx, T_f_km1):
return tau_0 * np.exp(xx*deltaE/(R*T_k) + (1-xx)*deltaE/(R*T_f_km1))
exponents = []
taus = []
temps = [0]
T_f_ns = []
markovs = [coordsLq[1][0]]
R = 8.31
# TNMH Code (adapted from Badrinarayanan's PhD Thesis):
def tnmfunc2(xdata, tau_0, xx, beta, deltaE):
delhR = deltaE/8.314
T = []
Tf = []
t = []
delt = []
tau = []
dttau = []
delT = []
step = len(xdata)
for k in range(0, step):
dttau.append(0)
T.append(240)
Tf.append(240)
t.append(0)
delt.append(0)
tau.append(0)
dttau.append(0)
delT.append(0)
T[1] = xdata[1]
Tf[1] = T[1]
t[1] = 0
delt[1] = 0
tau[1] = tau_0 * np.exp((xx*delhR / T[1]) + ((1 - xx)*delhR / Tf[1])-delhR/T_g)
dttau[1] = delt[1] / tau[1]
delT[1] = 0
Tfinit = T[1]
T_f_ns = [coordsLq[1][0]]
for i in range(1, step):
T[i] = xdata[i]
delT[i] = xdata[i] - xdata[i-1]
delt[i] = abs(delT[i]) / (rate/60)
t[i] = t[i-1] + delt[i]
tau[i] = tau_0 * np.exp((delhR*xx / T[i]) + ((1 - xx)*delhR / Tf[i-1])-delhR/T_g)
for j in np.arange(2, i).reshape(-1):
dttau[j] = dttau[j] + (delt[i] / tau[i])
Tfinit = Tfinit + (delT[j] * (1 - np.exp(- (dttau[j] ** beta))))
Tf[i] = Tfinit
T_f_ns.append(Tfinit)
Tfinit = Tf[1]
return T_f_ns
####################################################
# Use T_g = T_fictive for tau determination
T_g = T_f_0[0]
# or plug in T_half, T_onset, ... from separate evaluation
# Start values
p0 = [10, 0.5, 0.4, 225085]
def fitTNMH(p, x):
dTNMHdT = []
modelTemp = np.append(x[::-1], x[1:])
tau_0, xx, beta, deltaE = p
TNMH = tnmfunc2(modelTemp, tau_0, xx, beta, deltaE)
for i in range(len(modelTemp)-1):
dTNMHdT.append((TNMH[i+1]-TNMH[i]) / (modelTemp[i+1]-modelTemp[i]))
res = dTNMHdT[len(modelTemp)//2-1:]
return np.array(res)
# Use only every 20th data point to reduce fitting time
temperaturesInterpol = np.linspace(temperaturesCut[0], temperaturesCut[len(temperaturesCut)-1], 200)
dTfdTInterpol = np.interp(temperaturesInterpol, temperaturesCut, dTfdT)
ts = time.time()
model = odr.Model(fitTNMH)
whichFit = [1, 1, 1, 1]
odrdata = odr.Data(temperaturesInterpol, dTfdTInterpol)
myodr = odr.ODR(odrdata, model, beta0=p0, ifixb=whichFit, maxit=3000)
result = (myodr.run())
print(result.stopreason)
p0 = result.beta
print('TNMH heating Fit:')
print(p0)
# print('errors:')
# print(result.sd_beta)
ts = time.time()-ts
print('Time for fit:')
print(ts)
tau_0, xx, beta, deltaE = p0
fitResult = fitTNMH(p0, temperaturesInterpol)
fig, ax1 = plt.subplots()
ax1.set_xlabel('Temperature / K')
ax1.set_ylabel('Fictive Temperature / K')
ax1.plot(temperaturesCut, dTfdT, 'bo')
ax1.plot(temperaturesInterpol, dTfdTInterpol, 'yo')
ax1.plot(temperaturesInterpol, fitResult, 'r-')
plt.show()
dataOutName = os.path.splitext(str(dataName))[0] + "_dTfdT_tau.fit"
dataOut = np.column_stack((temperaturesInterpol, dTfdTInterpol, fitResult))
save = 0 # input("Save parameter to file? (yes = 1, no = 0): ")
if save == '1':
np.savetxt(dataOutName, dataOut, fmt='%1.5e', header="tau_TNMH="+str(tau_0) + "\tbeta="+str(beta) + "\tx="+str(xx) + "\tdeltaE="+str(deltaE) + "\nTemp\t\tdTfdT_data\t\tdTfdT_fit")
# Try to determine the heating rate from the data file name (Searching for digits followed by ".")
paramName = ((str(dataName)).split("_"))[0] + "_DSC_tau.param"
print(paramName)
with open(paramName, 'a') as f:
f.write('\n#Heating Rate \t tau_TNMH \t beta \t\t\t x \t deltaE \t Tg fictive')
f.write('\n')
f.write('%1.4e \t %1.4e \t %1.4e \t %1.4e \t %1.4e \t %1.4e' % (rate, tau_0, beta, xx, deltaE, T_g))

View File

@ -0,0 +1,46 @@
import numpy as np
from nmreval.utils.constants import R_joule as R
class TNMH:
type = 'DSC'
name = 'TNMH model'
equation = r''
params = [r'\tau_{g}', 'x', r'\beta', r'\Delta H', 'T_{g}', 'rate']
bounds = [(0, None), (0, 1), (0, 1), (0, None), (0, None), (0, None)]
@staticmethod
def func(x: np.ndarray, tau_g: float, xx: float, beta: float, energy: float, tg: float, rate: float) -> np.ndarray:
model_temp = np.r_[x[::-1], x[1:]]
curve = TNMH.tnm_function(model_temp, tau_g, xx, beta, energy, tg, rate)[x.size - 1:]
res = np.gradient(curve, x)
return res
@staticmethod
def tnm_function(x: np.ndarray, tau_g: float, xx: float, beta: float, energy: float, tg: float, rate: float) -> np.ndarray:
step = x.size
Tf = np.empty(step)
Tf[0] = x[0]
delta_temp = np.diff(x)
delta_time = np.abs(delta_temp) * 60 / rate
tau = np.empty(step)
dt_by_tau = np.zeros(step)
temp_0 = x[0]
for i in range(0, step - 1):
tau[i] = TNMH.relax(x[i+1], Tf[i], tau_g, tg, energy, xx)
dt_by_tau[:i] += delta_time[i] / tau[i]
Tf[i + 1] = np.sum(delta_temp[:i] * (1 - np.exp(-dt_by_tau[:i] ** beta))) + temp_0
return Tf
@staticmethod
def relax(t, tf, tau_g, t_glass, ea, x):
h = ea/R
return tau_g * np.exp((x*h / t) + ((1 - x) * h / tf) - h / t_glass)

View File

@ -4,7 +4,7 @@ from collections import OrderedDict, namedtuple
from scipy.special import psi
__all__ = ['NA', 'kb_joule', 'h_joule', 'hbar_joule',
'e', 'h', 'mu0', 'epsilon0', 'kB', 'R', 'hbar', 'pi', 'Eu',
'e', 'h', 'mu0', 'epsilon0', 'kB', 'R', 'R_joule', 'hbar', 'pi', 'Eu',
'nuclei', 'gamma', 'gamma_full', 'energy_converter']
# Boltzmann constant in Joule, elementary charge and Avogadro constant are CODATA 2018 definitions

View File

@ -136,7 +136,7 @@
<x>0</x>
<y>0</y>
<width>1386</width>
<height>22</height>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -326,6 +326,12 @@
<addaction name="actionTetris"/>
<addaction name="actionMine"/>
</widget>
<widget class="QMenu" name="menuDSC">
<property name="title">
<string>DSC</string>
</property>
<addaction name="actionTNMH_model"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuWindow"/>
<addaction name="menuData"/>
@ -334,6 +340,7 @@
<addaction name="menuFit"/>
<addaction name="menuNMR"/>
<addaction name="menuBDS"/>
<addaction name="menuDSC"/>
<addaction name="menuOptions"/>
<addaction name="menuHelp"/>
<addaction name="menuStuff"/>
@ -1022,6 +1029,11 @@
<string>About...</string>
</property>
</action>
<action name="actionTNMH_model">
<property name="text">
<string>TNMH model...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>