forked from IPKM/nmreval
fixed problem with setting color from context menu
This commit is contained in:
parent
bc215ce32b
commit
fcaf43b3eb
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Form implementation generated from reading ui file 'src/resources/_ui/basewindow.ui'
|
# 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
|
# 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.
|
# 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 = QtGui.QIcon()
|
||||||
icon5.addPixmap(QtGui.QPixmap(":/eval_t1_dock"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon5.addPixmap(QtGui.QPixmap(":/eval_t1_dock"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
self.tabWidget.addTab(self.t1tauwidget, icon5, "")
|
self.tabWidget.addTab(self.t1tauwidget, icon5, "")
|
||||||
|
self.drawingswidget = DrawingsWidget()
|
||||||
|
self.drawingswidget.setObjectName("drawingswidget")
|
||||||
|
self.tabWidget.addTab(self.drawingswidget, "")
|
||||||
self.integralwidget = IntegralWidget()
|
self.integralwidget = IntegralWidget()
|
||||||
self.integralwidget.setObjectName("integralwidget")
|
self.integralwidget.setObjectName("integralwidget")
|
||||||
self.tabWidget.addTab(self.integralwidget, "")
|
self.tabWidget.addTab(self.integralwidget, "")
|
||||||
@ -72,7 +75,7 @@ class Ui_BaseWindow(object):
|
|||||||
self.horizontalLayout.addWidget(self.splitter)
|
self.horizontalLayout.addWidget(self.splitter)
|
||||||
BaseWindow.setCentralWidget(self.centralwidget)
|
BaseWindow.setCentralWidget(self.centralwidget)
|
||||||
self.menubar = QtWidgets.QMenuBar(BaseWindow)
|
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.menubar.setObjectName("menubar")
|
||||||
self.menuFile = QtWidgets.QMenu(self.menubar)
|
self.menuFile = QtWidgets.QMenu(self.menubar)
|
||||||
self.menuFile.setObjectName("menuFile")
|
self.menuFile.setObjectName("menuFile")
|
||||||
@ -114,6 +117,8 @@ class Ui_BaseWindow(object):
|
|||||||
self.menuStuff = QtWidgets.QMenu(self.menubar)
|
self.menuStuff = QtWidgets.QMenu(self.menubar)
|
||||||
self.menuStuff.setTitle("")
|
self.menuStuff.setTitle("")
|
||||||
self.menuStuff.setObjectName("menuStuff")
|
self.menuStuff.setObjectName("menuStuff")
|
||||||
|
self.menuDSC = QtWidgets.QMenu(self.menubar)
|
||||||
|
self.menuDSC.setObjectName("menuDSC")
|
||||||
BaseWindow.setMenuBar(self.menubar)
|
BaseWindow.setMenuBar(self.menubar)
|
||||||
self.toolBar = QtWidgets.QToolBar(BaseWindow)
|
self.toolBar = QtWidgets.QToolBar(BaseWindow)
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
||||||
@ -353,6 +358,8 @@ class Ui_BaseWindow(object):
|
|||||||
self.actionUpdate.setObjectName("actionUpdate")
|
self.actionUpdate.setObjectName("actionUpdate")
|
||||||
self.actionMine = QtWidgets.QAction(BaseWindow)
|
self.actionMine = QtWidgets.QAction(BaseWindow)
|
||||||
self.actionMine.setObjectName("actionMine")
|
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 = QtWidgets.QAction(BaseWindow)
|
||||||
self.actionBugs.setObjectName("actionBugs")
|
self.actionBugs.setObjectName("actionBugs")
|
||||||
self.actionShow_error_log = QtWidgets.QAction(BaseWindow)
|
self.actionShow_error_log = QtWidgets.QAction(BaseWindow)
|
||||||
@ -361,6 +368,8 @@ class Ui_BaseWindow(object):
|
|||||||
self.actionCreate_starter.setObjectName("actionCreate_starter")
|
self.actionCreate_starter.setObjectName("actionCreate_starter")
|
||||||
self.actionAbout = QtWidgets.QAction(BaseWindow)
|
self.actionAbout = QtWidgets.QAction(BaseWindow)
|
||||||
self.actionAbout.setObjectName("actionAbout")
|
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.actionSave)
|
||||||
self.menuSave.addAction(self.actionExportGraphic)
|
self.menuSave.addAction(self.actionExportGraphic)
|
||||||
self.menuSave.addAction(self.action_save_fit_parameter)
|
self.menuSave.addAction(self.action_save_fit_parameter)
|
||||||
@ -441,6 +450,7 @@ class Ui_BaseWindow(object):
|
|||||||
self.menuWindow.addSeparator()
|
self.menuWindow.addSeparator()
|
||||||
self.menuWindow.addAction(self.actionRefresh)
|
self.menuWindow.addAction(self.actionRefresh)
|
||||||
self.menuWindow.addSeparator()
|
self.menuWindow.addSeparator()
|
||||||
|
self.menuWindow.addAction(self.action_draw_object)
|
||||||
self.menuNMR.addAction(self.t1action)
|
self.menuNMR.addAction(self.t1action)
|
||||||
self.menuNMR.addAction(self.actionCalculateT1)
|
self.menuNMR.addAction(self.actionCalculateT1)
|
||||||
self.menuNMR.addAction(self.action_coup_calc)
|
self.menuNMR.addAction(self.action_coup_calc)
|
||||||
@ -456,6 +466,7 @@ class Ui_BaseWindow(object):
|
|||||||
self.menuStuff.addAction(self.actionLife)
|
self.menuStuff.addAction(self.actionLife)
|
||||||
self.menuStuff.addAction(self.actionTetris)
|
self.menuStuff.addAction(self.actionTetris)
|
||||||
self.menuStuff.addAction(self.actionMine)
|
self.menuStuff.addAction(self.actionMine)
|
||||||
|
self.menuDSC.addAction(self.actionTNMH_model)
|
||||||
self.menubar.addAction(self.menuFile.menuAction())
|
self.menubar.addAction(self.menuFile.menuAction())
|
||||||
self.menubar.addAction(self.menuWindow.menuAction())
|
self.menubar.addAction(self.menuWindow.menuAction())
|
||||||
self.menubar.addAction(self.menuData.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.menuFit.menuAction())
|
||||||
self.menubar.addAction(self.menuNMR.menuAction())
|
self.menubar.addAction(self.menuNMR.menuAction())
|
||||||
self.menubar.addAction(self.menuBDS.menuAction())
|
self.menubar.addAction(self.menuBDS.menuAction())
|
||||||
|
self.menubar.addAction(self.menuDSC.menuAction())
|
||||||
self.menubar.addAction(self.menuOptions.menuAction())
|
self.menubar.addAction(self.menuOptions.menuAction())
|
||||||
self.menubar.addAction(self.menuHelp.menuAction())
|
self.menubar.addAction(self.menuHelp.menuAction())
|
||||||
self.menubar.addAction(self.menuStuff.menuAction())
|
self.menubar.addAction(self.menuStuff.menuAction())
|
||||||
@ -487,7 +499,7 @@ class Ui_BaseWindow(object):
|
|||||||
|
|
||||||
self.retranslateUi(BaseWindow)
|
self.retranslateUi(BaseWindow)
|
||||||
self.tabWidget.setCurrentIndex(0)
|
self.tabWidget.setCurrentIndex(0)
|
||||||
self.action_close.triggered.connect(BaseWindow.close)
|
self.action_close.triggered.connect(BaseWindow.close) # type: ignore
|
||||||
QtCore.QMetaObject.connectSlotsByName(BaseWindow)
|
QtCore.QMetaObject.connectSlotsByName(BaseWindow)
|
||||||
|
|
||||||
def retranslateUi(self, 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.editsignalwidget), _translate("BaseWindow", "Signals"))
|
||||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.ptsselectwidget), _translate("BaseWindow", "Pick points"))
|
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.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.tabWidget.setTabText(self.tabWidget.indexOf(self.integralwidget), _translate("BaseWindow", "Integrate"))
|
||||||
self.menuFile.setTitle(_translate("BaseWindow", "&File"))
|
self.menuFile.setTitle(_translate("BaseWindow", "&File"))
|
||||||
self.menuSave.setTitle(_translate("BaseWindow", "&Save..."))
|
self.menuSave.setTitle(_translate("BaseWindow", "&Save..."))
|
||||||
@ -515,6 +528,7 @@ class Ui_BaseWindow(object):
|
|||||||
self.menuNMR.setTitle(_translate("BaseWindow", "NMR"))
|
self.menuNMR.setTitle(_translate("BaseWindow", "NMR"))
|
||||||
self.menuBDS.setTitle(_translate("BaseWindow", "BDS"))
|
self.menuBDS.setTitle(_translate("BaseWindow", "BDS"))
|
||||||
self.menuSpectrum.setTitle(_translate("BaseWindow", "Spectrum"))
|
self.menuSpectrum.setTitle(_translate("BaseWindow", "Spectrum"))
|
||||||
|
self.menuDSC.setTitle(_translate("BaseWindow", "DSC"))
|
||||||
self.toolBar.setWindowTitle(_translate("BaseWindow", "Main"))
|
self.toolBar.setWindowTitle(_translate("BaseWindow", "Main"))
|
||||||
self.toolbar_edit.setWindowTitle(_translate("BaseWindow", "Math"))
|
self.toolbar_edit.setWindowTitle(_translate("BaseWindow", "Math"))
|
||||||
self.toolBar_nmr.setWindowTitle(_translate("BaseWindow", "NMR"))
|
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.actionFit_parameter_saving.setText(_translate("BaseWindow", "Fit parameter saving..."))
|
||||||
self.actionShow_fit_parameter.setText(_translate("BaseWindow", "Parameter..."))
|
self.actionShow_fit_parameter.setText(_translate("BaseWindow", "Parameter..."))
|
||||||
self.actionSkip_points.setText(_translate("BaseWindow", "Skip points..."))
|
self.actionSkip_points.setText(_translate("BaseWindow", "Skip points..."))
|
||||||
|
self.actionGuide_lines.setText(_translate("BaseWindow", "Draw lines..."))
|
||||||
self.actionMaximize.setText(_translate("BaseWindow", "Maximize"))
|
self.actionMaximize.setText(_translate("BaseWindow", "Maximize"))
|
||||||
self.actionTile.setText(_translate("BaseWindow", "Tile windows"))
|
self.actionTile.setText(_translate("BaseWindow", "Tile windows"))
|
||||||
self.actionTileVertical.setText(_translate("BaseWindow", "Tile windows vertically"))
|
self.actionTileVertical.setText(_translate("BaseWindow", "Tile windows vertically"))
|
||||||
@ -614,15 +629,18 @@ class Ui_BaseWindow(object):
|
|||||||
self.actionTetris.setText(_translate("BaseWindow", "Not Tetris"))
|
self.actionTetris.setText(_translate("BaseWindow", "Not Tetris"))
|
||||||
self.actionUpdate.setText(_translate("BaseWindow", "Look for updates"))
|
self.actionUpdate.setText(_translate("BaseWindow", "Look for updates"))
|
||||||
self.actionMine.setText(_translate("BaseWindow", "Mine"))
|
self.actionMine.setText(_translate("BaseWindow", "Mine"))
|
||||||
|
self.action_draw_object.setText(_translate("BaseWindow", "Draw objects..."))
|
||||||
self.actionBugs.setText(_translate("BaseWindow", "Bugs! Problems! Wishes!"))
|
self.actionBugs.setText(_translate("BaseWindow", "Bugs! Problems! Wishes!"))
|
||||||
self.actionShow_error_log.setText(_translate("BaseWindow", "Show error log"))
|
self.actionShow_error_log.setText(_translate("BaseWindow", "Show error log"))
|
||||||
self.actionCreate_starter.setText(_translate("BaseWindow", "Create starter.."))
|
self.actionCreate_starter.setText(_translate("BaseWindow", "Create starter.."))
|
||||||
self.actionAbout.setText(_translate("BaseWindow", "About..."))
|
self.actionAbout.setText(_translate("BaseWindow", "About..."))
|
||||||
|
self.actionTNMH_model.setText(_translate("BaseWindow", "TNMH model..."))
|
||||||
from ..data.datawidget.datawidget import DataWidget
|
from ..data.datawidget.datawidget import DataWidget
|
||||||
from ..data.integral_widget import IntegralWidget
|
from ..data.integral_widget import IntegralWidget
|
||||||
from ..data.point_select import PointSelectWidget
|
from ..data.point_select import PointSelectWidget
|
||||||
from ..data.signaledit.editsignalwidget import EditSignalWidget
|
from ..data.signaledit.editsignalwidget import EditSignalWidget
|
||||||
from ..data.valueeditwidget import ValueEditWidget
|
from ..data.valueeditwidget import ValueEditWidget
|
||||||
from ..fit.fitwindow import QFitDialog
|
from ..fit.fitwindow import QFitDialog
|
||||||
|
from ..graphs.drawings import DrawingsWidget
|
||||||
from ..lib.mdiarea import MdiAreaTile
|
from ..lib.mdiarea import MdiAreaTile
|
||||||
from ..nmr.t1widget import QT1Widget
|
from ..nmr.t1widget import QT1Widget
|
||||||
|
@ -12,6 +12,7 @@ from ..lib import get_icon
|
|||||||
from .._py.fitfunctionwidget import Ui_Form
|
from .._py.fitfunctionwidget import Ui_Form
|
||||||
from ..Qt import QtWidgets, QtCore, QtGui
|
from ..Qt import QtWidgets, QtCore, QtGui
|
||||||
|
|
||||||
|
|
||||||
class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
|
class QFunctionWidget(QtWidgets.QWidget, Ui_Form):
|
||||||
func_cnt = count()
|
func_cnt = count()
|
||||||
func_colors = cycle(Tab10)
|
func_colors = cycle(Tab10)
|
||||||
|
@ -5,7 +5,7 @@ from pathlib import Path
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from pyqtgraph import PlotDataItem
|
from pyqtgraph import PlotDataItem
|
||||||
|
|
||||||
from nmreval.data.points import Points
|
from nmreval.data import DSC
|
||||||
from nmreval.io.dsc import Cyclohexane, DSCCalibrator, DSCSample
|
from nmreval.io.dsc import Cyclohexane, DSCCalibrator, DSCSample
|
||||||
|
|
||||||
from ..Qt import QtWidgets, QtCore
|
from ..Qt import QtWidgets, QtCore
|
||||||
@ -250,7 +250,7 @@ class QDSCReader(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
return
|
return
|
||||||
|
|
||||||
rate, mode = self.current_run
|
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:
|
if filesave:
|
||||||
new_val.savetxt(self.fname.with_name(f'{self.fname.stem} {rate}K-min {mode}.dat'.replace(' ', '_')))
|
new_val.savetxt(self.fname.with_name(f'{self.fname.stem} {rate}K-min {mode}.dat'.replace(' ', '_')))
|
||||||
|
@ -1078,3 +1078,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
|||||||
def show_version(self):
|
def show_version(self):
|
||||||
from nmreval.version import __version__
|
from nmreval.version import __version__
|
||||||
QtWidgets.QMessageBox.about(self, 'Version', f'Build date of AppImage: {__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')
|
||||||
|
@ -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 .points import Points
|
||||||
|
|
||||||
|
from ..dsc.tnmh_model import TNMH
|
||||||
|
|
||||||
|
|
||||||
class DSC(Points):
|
class DSC(Points):
|
||||||
def __init__(self, x, y, **kwargs):
|
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
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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))
|
|
||||||
|
|
||||||
|
|
46
src/nmreval/dsc/tnmh_model.py
Normal file
46
src/nmreval/dsc/tnmh_model.py
Normal 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)
|
@ -4,7 +4,7 @@ from collections import OrderedDict, namedtuple
|
|||||||
from scipy.special import psi
|
from scipy.special import psi
|
||||||
|
|
||||||
__all__ = ['NA', 'kb_joule', 'h_joule', 'hbar_joule',
|
__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']
|
'nuclei', 'gamma', 'gamma_full', 'energy_converter']
|
||||||
|
|
||||||
# Boltzmann constant in Joule, elementary charge and Avogadro constant are CODATA 2018 definitions
|
# Boltzmann constant in Joule, elementary charge and Avogadro constant are CODATA 2018 definitions
|
||||||
|
@ -136,7 +136,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1386</width>
|
<width>1386</width>
|
||||||
<height>22</height>
|
<height>20</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
@ -326,6 +326,12 @@
|
|||||||
<addaction name="actionTetris"/>
|
<addaction name="actionTetris"/>
|
||||||
<addaction name="actionMine"/>
|
<addaction name="actionMine"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuDSC">
|
||||||
|
<property name="title">
|
||||||
|
<string>DSC</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionTNMH_model"/>
|
||||||
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
<addaction name="menuWindow"/>
|
<addaction name="menuWindow"/>
|
||||||
<addaction name="menuData"/>
|
<addaction name="menuData"/>
|
||||||
@ -334,6 +340,7 @@
|
|||||||
<addaction name="menuFit"/>
|
<addaction name="menuFit"/>
|
||||||
<addaction name="menuNMR"/>
|
<addaction name="menuNMR"/>
|
||||||
<addaction name="menuBDS"/>
|
<addaction name="menuBDS"/>
|
||||||
|
<addaction name="menuDSC"/>
|
||||||
<addaction name="menuOptions"/>
|
<addaction name="menuOptions"/>
|
||||||
<addaction name="menuHelp"/>
|
<addaction name="menuHelp"/>
|
||||||
<addaction name="menuStuff"/>
|
<addaction name="menuStuff"/>
|
||||||
@ -1022,6 +1029,11 @@
|
|||||||
<string>About...</string>
|
<string>About...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionTNMH_model">
|
||||||
|
<property name="text">
|
||||||
|
<string>TNMH model...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
Loading…
Reference in New Issue
Block a user